diff --git a/.gitignore b/.gitignore index a4712bc..fe3b0fc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ release/ __pycache__/ */__pycache__/ # 忽略测试文件 -test.py +test*.py diff --git a/README.md b/README.md index 07eadc6..79d8a7a 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,10 @@ * 支持自定义游戏速度倍率 * 保存在游戏存档文件中,可以通过修改`game rate`值更改速度倍率 * 游戏完成成就显示 - * 冒险模式全部完成显示银向日葵奖杯 + * 任意一游戏模式全部完成显示银向日葵奖杯 * 所有模式全部完成显示金向日葵奖杯 * 光标移动到向日葵奖杯上是显示当前各个模式通关次数 +* 含有游戏帮助界面 QwQ ## 环境要求 @@ -312,6 +313,8 @@ pyinstaller -F pypvz.py ` ![截屏19](/demo/demo19.webp) ![截屏20](/demo/demo20.webp) ![截屏21](/demo/demo21.webp) +![截屏22](/demo/demo22.webp) +![截屏23](/demo/demo23.webp) ## 关于日志与反馈 diff --git a/demo/demo22.webp b/demo/demo22.webp new file mode 100644 index 0000000..04f94e3 Binary files /dev/null and b/demo/demo22.webp differ diff --git a/demo/demo23.webp b/demo/demo23.webp new file mode 100644 index 0000000..1a2f45d Binary files /dev/null and b/demo/demo23.webp differ diff --git a/pypvz.py b/pypvz.py index 2d75121..89e0b5a 100755 --- a/pypvz.py +++ b/pypvz.py @@ -32,6 +32,7 @@ if __name__=="__main__": c.GAME_LOSE: screen.GameLoseScreen(), c.LEVEL: level.Level(), c.AWARD_SCREEN: screen.AwardScreen(), + c.HELP_SCREEN: screen.HelpScreen(), } game.setup_states(state_dict, c.MAIN_MENU) game.run() diff --git a/resources/graphics/Screen/HelpScreen.png b/resources/graphics/Screen/HelpScreen.png new file mode 100644 index 0000000..05a8180 Binary files /dev/null and b/resources/graphics/Screen/HelpScreen.png differ diff --git a/source/component/map.py b/source/component/map.py index 19dfc40..cfcdc88 100755 --- a/source/component/map.py +++ b/source/component/map.py @@ -9,27 +9,27 @@ class Map(): if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: self.width = c.GRID_POOL_X_LEN self.height = c.GRID_POOL_Y_LEN - self.gridHeightSize = c.GRID_POOL_Y_SIZE + self.grid_height_size = c.GRID_POOL_Y_SIZE self.map = [[(self.initMapGrid(c.MAP_GRASS), self.initMapGrid(c.MAP_WATER))[y in {2, 3}] for x in range(self.width)] for y in range(self.height)] elif self.background_type in c.ON_ROOF_BACKGROUNDS: self.width = c.GRID_ROOF_X_LEN self.height = c.GRID_ROOF_Y_LEN - self.gridHeightSize = c.GRID_ROOF_Y_SIZE + self.grid_height_size = c.GRID_ROOF_Y_SIZE self.map = [[self.initMapGrid(c.MAP_TILE) for x in range(self.width)] for y in range(self.height)] elif self.background_type == c.BACKGROUND_SINGLE: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN - self.gridHeightSize = c.GRID_Y_SIZE + self.grid_height_size = c.GRID_Y_SIZE self.map = [[(self.initMapGrid(c.MAP_UNAVAILABLE), self.initMapGrid(c.MAP_GRASS))[y == 2] for x in range(self.width)] for y in range(self.height)] elif self.background_type == c.BACKGROUND_TRIPLE: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN - self.gridHeightSize = c.GRID_Y_SIZE + self.grid_height_size = c.GRID_Y_SIZE self.map = [[(self.initMapGrid(c.MAP_UNAVAILABLE), self.initMapGrid(c.MAP_GRASS))[y in {1, 2, 3}] for x in range(self.width)] for y in range(self.height)] else: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN - self.gridHeightSize = c.GRID_Y_SIZE + self.grid_height_size = c.GRID_Y_SIZE self.map = [[self.initMapGrid(c.MAP_GRASS) for x in range(self.width)] for y in range(self.height)] def isValid(self, map_x, map_y): @@ -47,14 +47,14 @@ class Map(): # 判断位置是否可用 # 暂时没有写紫卡植物的判断方法 # 由于紫卡植物需要移除以前的植物,所以可用另外定义一个函数 - def isAvailable(self, map_x, map_y, plantName): + def isAvailable(self, map_x, map_y, plant_name): # 咖啡豆和墓碑吞噬者的判别最为特殊 - if plantName == c.COFFEEBEAN: - if self.map[map_y][map_x][c.MAP_SLEEP] and (plantName not in self.map[map_y][map_x][c.MAP_PLANT]): + if plant_name == c.COFFEEBEAN: + if self.map[map_y][map_x][c.MAP_SLEEP] and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT]): return True else: return False - if plantName == c.GRAVEBUSTER: + if plant_name == c.GRAVEBUSTER: if (c.GRAVE in self.map[map_y][map_x][c.MAP_PLANT]): return True else: @@ -64,13 +64,13 @@ class Map(): return False if self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_GRASS: # 草地 # 首先需要判断植物是否是水生植物,水生植物不能种植在陆地上 - if plantName not in c.WATER_PLANTS: + if plant_name not in c.WATER_PLANTS: if not self.map[map_y][map_x][c.MAP_PLANT]: # 没有植物肯定可以种植 return True elif (all((i in {"花盆(未实现)", c.PUMPKINHEAD}) for i in self.map[map_y][map_x][c.MAP_PLANT]) - and (plantName not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 + and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 return True - elif (plantName == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 没有南瓜头就能种南瓜头 + elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 没有南瓜头就能种南瓜头 return True else: return False @@ -78,26 +78,26 @@ class Map(): return False elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_TILE: # 屋顶 # 首先需要判断植物是否是水生植物,水生植物不能种植在陆地上 - if plantName not in c.WATER_PLANTS: + if plant_name not in c.WATER_PLANTS: if "花盆(未实现)" in self.map[map_y][map_x][c.MAP_PLANT]: if (all((i in {"花盆(未实现)", c.PUMPKINHEAD}) for i in self.map[map_y][map_x][c.MAP_PLANT]) - and (plantName not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 - if plantName in {c.SPIKEWEED}: # 不能在花盆上种植的植物 + and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 + if plant_name in {c.SPIKEWEED}: # 不能在花盆上种植的植物 return False else: return True - elif (plantName == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 有花盆且没有南瓜头就能种南瓜头 + elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 有花盆且没有南瓜头就能种南瓜头 return True else: return False - elif plantName == "花盆(未实现)": # 这一格本来没有花盆而且新来的植物是花盆,可以种 + elif plant_name == "花盆(未实现)": # 这一格本来没有花盆而且新来的植物是花盆,可以种 return True else: return False else: return False elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_WATER: # 水里 - if plantName in c.WATER_PLANTS: # 是水生植物 + if plant_name in c.WATER_PLANTS: # 是水生植物 if not self.map[map_y][map_x][c.MAP_PLANT]: # 只有无植物时才能在水里种植水生植物 return True else: @@ -105,12 +105,12 @@ class Map(): else: # 非水生植物,依赖睡莲 if c.LILYPAD in self.map[map_y][map_x][c.MAP_PLANT]: if (all((i in {c.LILYPAD, c.PUMPKINHEAD}) for i in self.map[map_y][map_x][c.MAP_PLANT]) - and (plantName not in self.map[map_y][map_x][c.MAP_PLANT])): - if plantName in {c.SPIKEWEED, c.POTATOMINE, "花盆(未实现)"}: # 不能在睡莲上种植的植物 + and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): + if plant_name in {c.SPIKEWEED, c.POTATOMINE, "花盆(未实现)"}: # 不能在睡莲上种植的植物 return False else: return True - elif (plantName == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 在睡莲上且没有南瓜头就能种南瓜头 + elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 在睡莲上且没有南瓜头就能种南瓜头 return True else: return False @@ -152,22 +152,22 @@ class Map(): def setMapGridType(self, map_x, map_y, plot_type): self.map[map_y][map_x][c.MAP_PLOT_TYPE] = plot_type - def addMapPlant(self, map_x, map_y, plantName, sleep=False): - self.map[map_y][map_x][c.MAP_PLANT].add(plantName) + def addMapPlant(self, map_x, map_y, plant_name, sleep=False): + self.map[map_y][map_x][c.MAP_PLANT].add(plant_name) self.map[map_y][map_x][c.MAP_SLEEP] = sleep - def removeMapPlant(self, map_x, map_y, plantName): - self.map[map_y][map_x][c.MAP_PLANT].discard(plantName) + def removeMapPlant(self, map_x, map_y, plant_name): + self.map[map_y][map_x][c.MAP_PLANT].discard(plant_name) def getRandomMapIndex(self): map_x = random.randint(0, self.width-1) map_y = random.randint(0, self.height-1) return (map_x, map_y) - def checkPlantToSeed(self, x, y, plantName): + def checkPlantToSeed(self, x, y, plant_name): pos = None map_x, map_y = self.getMapIndex(x, y) - if self.isValid(map_x, map_y) and self.isAvailable(map_x, map_y, plantName): + if self.isValid(map_x, map_y) and self.isAvailable(map_x, map_y, plant_name): pos = self.getMapGridPos(map_x, map_y) return pos @@ -212,7 +212,7 @@ LEVEL_MAP_DATA = ( # 第2关:三行草皮 { c.BACKGROUND_TYPE: 8, - c.INIT_SUN_NAME: 150, + c.INIT_SUN_NAME: 50, c.SHOVEL: 1, c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO, c.INCLUDED_ZOMBIES:(c.NORMAL_ZOMBIE,), @@ -412,7 +412,7 @@ LITTLE_GAME_MAP_DATA = ( c.SPIKEWEED: 100, c.SQUASH: 100, c.JALAPENO: 50, - c.THREEPEASHOOTER: 400,} + c.THREEPEASHOOTER: 300,} }, ) diff --git a/source/component/plant.py b/source/component/plant.py index 7275331..9481718 100755 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -37,7 +37,9 @@ class Car(pg.sprite.Sprite): # 豌豆及孢子类普通子弹 class Bullet(pg.sprite.Sprite): - def __init__(self, x, start_y, dest_y, name, damage, effect=None, passedTorchWood=None, damageType=c.ZOMBIE_DEAFULT_DAMAGE): + def __init__( self, x, start_y, dest_y, name, damage, + effect=None, passed_torchwood_x=None, + damageType=c.ZOMBIE_DEAFULT_DAMAGE): pg.sprite.Sprite.__init__(self) self.name = name @@ -60,7 +62,7 @@ class Bullet(pg.sprite.Sprite): self.current_time = 0 self.animate_timer = 0 self.animate_interval = 70 - self.passedTorchWood = passedTorchWood # 记录最近通过的火炬树横坐标,如果没有缺省为None + self.passed_torchwood_x = passed_torchwood_x # 记录最近通过的火炬树横坐标,如果没有缺省为None def loadFrames(self, frames, name): frame_list = tool.GFX[name] @@ -104,7 +106,7 @@ class Bullet(pg.sprite.Sprite): if self.y_vel * (self.dest_y - self.rect.y) < 0: self.rect.y = self.dest_y self.rect.x += self.x_vel - if self.rect.x >= c.SCREEN_WIDTH + 60: + if self.rect.x >= c.SCREEN_WIDTH + 20: self.kill() elif self.state == c.EXPLODE: if (self.current_time - self.explode_timer) > 250: @@ -206,7 +208,7 @@ class StarBullet(Bullet): else: self.rect.x -= 10 self.handleMapYPosition() - if ((self.rect.x > c.SCREEN_WIDTH + 60) or (self.rect.x < -60) + if ((self.rect.x > c.SCREEN_WIDTH + 20) or (self.rect.right < -20) or (self.rect.y > c.SCREEN_HEIGHT) or (self.rect.y < 0)): self.kill() elif self.state == c.EXPLODE: @@ -248,7 +250,7 @@ class Plant(pg.sprite.Sprite): self.animate_interval = 70 # 帧播放间隔 self.hit_timer = 0 # 被铲子指向时间 - self.highlightTime = 0 + self.highlight_time = 0 def loadFrames(self, frames, name, scale=1, color=c.BLACK): frame_list = tool.GFX[name] @@ -267,7 +269,7 @@ class Plant(pg.sprite.Sprite): self.loadFrames(self.frames, name, scale) def changeFrames(self, frames): - """change image frames and modify rect position""" + # change image frames and modify rect position self.frames = frames self.frame_num = len(self.frames) self.frame_index = 0 @@ -311,7 +313,7 @@ class Plant(pg.sprite.Sprite): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -322,7 +324,7 @@ class Plant(pg.sprite.Sprite): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames): return False if (self.state != c.SLEEP and zombie.state != c.DIE and - self.rect.x <= zombie.rect.right and zombie.rect.left <= c.SCREEN_WIDTH): + self.rect.x <= zombie.rect.right and zombie.rect.x <= c.SCREEN_WIDTH - 24): return True return False @@ -338,7 +340,7 @@ class Plant(pg.sprite.Sprite): self.changeFrames(self.sleep_frames) def setDamage(self, damage, zombie): - if not zombie.lostHead: + if not zombie.losthead: self.health -= damage self.hit_timer = self.current_time if ((self.name == c.HYPNOSHROOM) and @@ -429,20 +431,20 @@ class RepeaterPea(Plant): self.shoot_timer = 0 # 是否发射第一颗 - self.firstShot = False + self.first_shot = False def attacking(self): if self.shoot_timer == 0: self.shoot_timer = self.current_time - 700 elif (self.current_time - self.shoot_timer >= 1400): - self.firstShot = True + self.first_shot = True self.bullet_group.add(Bullet(self.rect.right - 15, self.rect.y, self.rect.y, c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None)) self.shoot_timer = self.current_time # 播放发射音效 c.SOUND_SHOOT.play() - elif self.firstShot and (self.current_time - self.shoot_timer) > 100: - self.firstShot = False + elif self.first_shot and (self.current_time - self.shoot_timer) > 100: + self.first_shot = False self.bullet_group.add(Bullet(self.rect.right - 15, self.rect.y, self.rect.y, c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None)) # 播放发射音效 @@ -580,7 +582,7 @@ class CherryBomb(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -596,7 +598,7 @@ class Chomper(Plant): self.digest_interval = 15000 self.attack_zombie = None self.zombie_group = None - self.shouldDiggest = False + self.should_diggest = False def loadImages(self, name, scale): self.idle_frames = [] @@ -624,7 +626,7 @@ class Chomper(Plant): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames): return False elif (self.state == c.IDLE and zombie.state != c.DIGEST and - self.rect.x <= zombie.rect.centerx and (not zombie.lostHead) and + self.rect.x <= zombie.rect.centerx and (not zombie.losthead) and (self.rect.x + c.GRID_X_SIZE*2.7 >= zombie.rect.centerx)): return True return False @@ -648,12 +650,12 @@ class Chomper(Plant): # 播放吞的音效 c.SOUND_BIGCHOMP.play() if self.attack_zombie.alive(): - self.shouldDiggest = True + self.should_diggest = True self.attack_zombie.kill() if (self.frame_index + 1) == self.frame_num: - if self.shouldDiggest: + if self.should_diggest: self.setDigest() - self.shouldDiggest = False + self.should_diggest = False else: self.setIdle() @@ -751,7 +753,7 @@ class PotatoMine(Plant): return False # 这里碰撞应当比碰撞一般更容易,就设置成圆形或矩形模式,不宜采用mask elif (pg.sprite.collide_circle_ratio(0.7)(zombie, self) and - (not self.is_init) and (not zombie.lostHead)): + (not self.is_init) and (not zombie.losthead)): return True return False @@ -767,12 +769,12 @@ class PotatoMine(Plant): class Squash(Plant): - def __init__(self, x, y, mapPlantsSet): + def __init__(self, x, y, map_plant_set): Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None) self.orig_pos = (x, y) self.aim_timer = 0 self.start_boom = False # 和灰烬等植物统一变量名,在这里表示倭瓜是否跳起 - self.mapPlantsSet = mapPlantsSet + self.map_plant_set = map_plant_set def loadImages(self, name, scale): self.idle_frames = [] @@ -816,7 +818,7 @@ class Squash(Plant): if self.canAttack(zombie): zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE) self.health = 0 # 避免僵尸在原位啃食 - self.mapPlantsSet.remove(c.SQUASH) + self.map_plant_set.remove(c.SQUASH) self.kill() # 播放碾压音效 c.SOUND_SQUASHING.play() @@ -870,7 +872,7 @@ class Spikeweed(Plant): if self.canAttack(zombie): # 有车的僵尸 if zombie.name in {c.ZOMBONI}: - zombie.health = zombie.lostHeadHealth + zombie.health = zombie.losthead_health killSelf = True else: zombie.setDamage(20, damageType=c.ZOMBIE_COMMON_DAMAGE) @@ -924,7 +926,7 @@ class Jalapeno(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -1091,7 +1093,7 @@ class IceShroom(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -1288,16 +1290,16 @@ class TorchWood(Plant): def idling(self): for i in self.bullet_group: if i.name == c.BULLET_PEA: - if i.passedTorchWood != self.rect.centerx: + if i.passed_torchwood_x != self.rect.centerx: if abs(i.rect.centerx - self.rect.centerx) <= 20: self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, - c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, effect=c.BULLET_EFFECT_UNICE, passedTorchWood=self.rect.centerx)) + c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, effect=c.BULLET_EFFECT_UNICE, passed_torchwood_x=self.rect.centerx)) i.kill() elif i.name == c.BULLET_PEA_ICE: - if i.passedTorchWood != self.rect.centerx: + if i.passed_torchwood_x != self.rect.centerx: if abs(i.rect.centerx - self.rect.centerx) <= 20: self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None, passedTorchWood=self.rect.centerx)) + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None, passed_torchwood_x=self.rect.centerx)) i.kill() class StarFruit(Plant): @@ -1311,8 +1313,8 @@ class StarFruit(Plant): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames): return False if zombie.state != c.DIE: - zombieMapY = self.level.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom)[1] - if (self.rect.x >= zombie.rect.x) and (self.map_y == zombieMapY): # 对于同行且在杨桃后的僵尸 + zombie_map_y = self.level.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom)[1] + if (self.rect.x >= zombie.rect.x) and (self.map_y == zombie_map_y): # 对于同行且在杨桃后的僵尸 return True # 斜向上,理想直线方程为:f(zombie.rect.x) = -0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10 # 注意实际上为射线 @@ -1348,10 +1350,10 @@ class StarFruit(Plant): class CoffeeBean(Plant): - def __init__(self, x, y, plant_group, mapContent, map, map_x): + def __init__(self, x, y, plant_group, map_content, map, map_x): Plant.__init__(self, x, y, c.COFFEEBEAN, c.PLANT_HEALTH, None) self.plant_group = plant_group - self.mapContent = mapContent + self.map_content = map_content self.map = map self.map_x = map_x @@ -1360,7 +1362,7 @@ class CoffeeBean(Plant): self.frame_index += 1 if self.frame_index >= self.frame_num: - self.mapContent[c.MAP_SLEEP] = False + self.map_content[c.MAP_SLEEP] = False for plant in self.plant_group: if plant.can_sleep: if plant.state == c.SLEEP: @@ -1371,7 +1373,7 @@ class CoffeeBean(Plant): plant.changeFrames(plant.idle_frames) # 播放唤醒音效 c.SOUND_MUSHROOM_WAKEUP.play() - self.mapContent[c.MAP_PLANT].remove(self.name) + self.map_content[c.MAP_PLANT].remove(self.name) self.kill() self.frame_index = self.frame_num - 1 @@ -1379,7 +1381,7 @@ class CoffeeBean(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -1480,7 +1482,7 @@ class TangleKlep(Plant): self.frames = self.idle_frames def canAttack(self, zombie): - if zombie.state != c.DIE and (not zombie.lostHead): + if zombie.state != c.DIE and (not zombie.losthead): # 这里碰撞应当比碰撞一般更容易,就设置成圆形或矩形模式,不宜采用mask if pg.sprite.collide_circle_ratio(0.7)(zombie, self): return True @@ -1510,17 +1512,17 @@ class TangleKlep(Plant): # 坑形态的毁灭菇同地刺一样不可以被啃食 # 爆炸时杀死同一格的所有植物 class DoomShroom(Plant): - def __init__(self, x, y, mapPlantsSet, explode_y_range): + def __init__(self, x, y, map_plant_set, explode_y_range): Plant.__init__(self, x, y, c.DOOMSHROOM, c.PLANT_HEALTH, None) self.can_sleep = True - self.mapPlantSet = mapPlantsSet + self.map_plant_set = map_plant_set self.bomb_timer = 0 self.explode_y_range = explode_y_range self.explode_x_range = 250 self.start_boom = False self.boomed = False - self.originalX = x - self.originalY = y + self.original_x = x + self.original_y = y def loadImages(self, name, scale): self.idle_frames = [] @@ -1556,7 +1558,7 @@ class DoomShroom(Plant): if self.frame_index >= self.frame_num: self.health = 0 self.frame_index = self.frame_num - 1 - self.mapPlantSet.add(c.HOLE) + self.map_plant_set.add(c.HOLE) # 睡觉状态 elif self.state == c.SLEEP: if (self.current_time - self.animate_timer) > self.animate_interval: @@ -1576,7 +1578,7 @@ class DoomShroom(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -1668,8 +1670,8 @@ class GraveBuster(Plant): self.frame_index = self.frame_num - 1 for item in self.plant_group: if item.name == c.GRAVE: - itemMapX, _ = self.map.getMapIndex(item.rect.centerx, item.rect.bottom) - if itemMapX == self.map_x: + item_map_x, _ = self.map.getMapIndex(item.rect.centerx, item.rect.bottom) + if item_map_x == self.map_x: item.health = 0 self.health = 0 self.animate_timer = self.current_time @@ -1677,7 +1679,7 @@ class GraveBuster(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) @@ -1689,7 +1691,7 @@ class FumeShroom(Plant): Plant.__init__(self, x, y, c.FUMESHROOM, c.PLANT_HEALTH, bullet_group) self.can_sleep = True self.shoot_timer = 0 - self.showAttackFrames = True + self.show_attack_frames = True self.zombie_group = zombie_group def loadImages(self, name, scale): @@ -1726,18 +1728,18 @@ class FumeShroom(Plant): if self.shoot_timer == 0: self.shoot_timer = self.current_time - 700 elif self.current_time - self.shoot_timer >= 1100: - if self.showAttackFrames: - self.showAttackFrames = False + if self.show_attack_frames: + self.show_attack_frames = False self.changeFrames(self.attack_frames) if self.current_time - self.shoot_timer >= 1400: self.bullet_group.add(Fume(self.rect.right - 35, self.rect.y)) # 烟雾只是个动画,实际伤害由本身完成 - for targetZombie in self.zombie_group: - if self.canAttack(targetZombie): - targetZombie.setDamage(c.BULLET_DAMAGE_NORMAL, damageType=c.ZOMBIE_RANGE_DAMAGE) + for target_zombie in self.zombie_group: + if self.canAttack(target_zombie): + target_zombie.setDamage(c.BULLET_DAMAGE_NORMAL, damageType=c.ZOMBIE_RANGE_DAMAGE) self.shoot_timer = self.current_time - self.showAttackFrames = True + self.show_attack_frames = True # 播放发射音效 c.SOUND_FUME.play() @@ -1754,7 +1756,7 @@ class FumeShroom(Plant): self.image = self.frames[self.frame_index] self.mask = pg.mask.from_surface(self.image) - if (self.current_time - self.highlightTime < 100): + if (self.current_time - self.highlight_time < 100): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): self.image.set_alpha(192) diff --git a/source/component/zombie.py b/source/component/zombie.py index fc0ecaa..07c816e 100755 --- a/source/component/zombie.py +++ b/source/component/zombie.py @@ -5,7 +5,10 @@ from .. import constants as c class Zombie(pg.sprite.Sprite): - def __init__(self, x, y, name, head_group=None, helmetHealth=0, helmetType2Health=0, bodyHealth=c.NORMAL_HEALTH, lostHeadHealth=c.LOSTHEAD_HEALTH, damage=c.ZOMBIE_ATTACK_DAMAGE, canSwim=False): + def __init__( self, x, y, name, head_group=None, + helmet_health=0, helmet_type2_health=0, + body_health=c.NORMAL_HEALTH, losthead_health=c.LOSTHEAD_HEALTH, + damage=c.ZOMBIE_ATTACK_DAMAGE, can_swim=False): pg.sprite.Sprite.__init__(self) self.name = name @@ -15,26 +18,26 @@ class Zombie(pg.sprite.Sprite): self.frame_num = len(self.frames) self.image = self.frames[self.frame_index] - self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() + self.mask = pg.mask.from_surface(self.image) self.rect.x = x self.rect.bottom = y # 大蒜换行移动像素值,< 0时向上,= 0时不变,> 0时向上 - self.targetYChange = 0 - self.originalY = y - self.toChangeGroup = False + self.target_y_change = 0 + self.original_y = y + self.to_change_group = False - self.helmetHealth = helmetHealth - self.helmetType2Health = helmetType2Health - self.health = bodyHealth + lostHeadHealth - self.lostHeadHealth = lostHeadHealth + self.helmet_health = helmet_health + self.helmet_type2_health = helmet_type2_health + self.health = body_health + losthead_health + self.losthead_health = losthead_health self.damage = damage self.dead = False - self.lostHead = False - self.canSwim = canSwim + self.losthead = False + self.can_swim = can_swim self.swimming = False - self.helmet = (self.helmetHealth > 0) - self.helmetType2 = (self.helmetType2Health > 0) + self.helmet = (self.helmet_health > 0) + self.helmet_type2 = (self.helmet_type2_health > 0) self.head_group = head_group self.walk_timer = 0 @@ -44,7 +47,7 @@ class Zombie(pg.sprite.Sprite): self.animate_interval = 150 self.walk_animate_interval = 180 self.attack_animate_interval = 100 - self.lostHead_animate_interval = 180 + self.losthead_animate_interval = 180 self.die_animate_interval = 50 self.boomDie_animate_interval = 100 self.ice_slow_ratio = 1 @@ -88,8 +91,8 @@ class Zombie(pg.sprite.Sprite): if self.health <= 0: self.setDie() return True - elif self.health <= self.lostHeadHealth: - if not self.lostHead: + elif self.health <= self.losthead_health: + if not self.losthead: self.changeFrames(framesKind) self.setLostHead() return True @@ -105,7 +108,7 @@ class Zombie(pg.sprite.Sprite): return # 能游泳的僵尸 - if self.canSwim: + if self.can_swim: # 在水池范围内 # 在右侧岸左 if self.rect.right <= c.MAP_POOL_FRONT_X: @@ -119,25 +122,25 @@ class Zombie(pg.sprite.Sprite): c.SOUND_ZOMBIE_ENTERING_WATER.play() # 同样没有兼容双防具 if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.helmet = False else: self.changeFrames(self.helmet_swim_frames) - if self.helmetType2: - if self.helmetType2Health <= 0: - self.helmetType2 = False + if self.helmet_type2: + if self.helmet_type2_health <= 0: + self.helmet_type2 = False else: self.changeFrames(self.helmet_swim_frames) # 已经进入游泳状态 else: if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.changeFrames(self.swim_frames) self.helmet = False - if self.helmetType2: - if self.helmetType2Health <= 0: + if self.helmet_type2: + if self.helmet_type2_health <= 0: self.changeFrames(self.swim_frames) - self.helmetType2 = False + self.helmet_type2 = False # 水生僵尸已经接近家门口并且上岸 else: if self.swimming: @@ -145,55 +148,55 @@ class Zombie(pg.sprite.Sprite): self.swimming = False # 同样没有兼容双防具 if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.helmet = False else: self.changeFrames(self.helmet_walk_frames) - if self.helmetType2: - if self.helmetType2Health <= 0: - self.helmetType2 = False + if self.helmet_type2: + if self.helmet_type2_health <= 0: + self.helmet_type2 = False else: self.changeFrames(self.helmet_walk_frames) if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.helmet = False self.changeFrames(self.walk_frames) - if self.helmetType2: - if self.helmetType2Health <= 0: - self.helmetType2 = False + if self.helmet_type2: + if self.helmet_type2_health <= 0: + self.helmet_type2 = False self.changeFrames(self.walk_frames) elif self.is_hypno and self.rect.right > c.MAP_POOL_FRONT_X + 55: # 常数拟合暂时缺乏检验 if self.swimming: self.changeFrames(self.walk_frames) if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.changeFrames(self.walk_frames) self.helmet = False elif self.swimming: # 游泳状态需要改为步行 self.changeFrames(self.helmet_walk_frames) - if self.helmetType2: - if self.helmetType2Health <= 0: + if self.helmet_type2: + if self.helmet_type2_health <= 0: self.changeFrames(self.walk_frames) - self.helmetType2 = False + self.helmet_type2 = False elif self.swimming: # 游泳状态需要改为步行 self.changeFrames(self.helmet_walk_frames) self.swimming = False # 尚未进入水池 else: - if self.helmetHealth <= 0 and self.helmet: + if self.helmet_health <= 0 and self.helmet: self.changeFrames(self.walk_frames) self.helmet = False - if self.helmetType2Health <= 0 and self.helmetType2: + if self.helmet_type2_health <= 0 and self.helmet_type2: self.changeFrames(self.walk_frames) - self.helmetType2 = False + self.helmet_type2 = False # 不能游泳的一般僵尸 else: - if self.helmetHealth <= 0 and self.helmet: + if self.helmet_health <= 0 and self.helmet: self.changeFrames(self.walk_frames) self.helmet = False - if self.helmetType2Health <= 0 and self.helmetType2: + if self.helmet_type2_health <= 0 and self.helmet_type2: self.changeFrames(self.walk_frames) - self.helmetType2 = False + self.helmet_type2 = False if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()): self.handleGarlicYChange() @@ -204,48 +207,48 @@ class Zombie(pg.sprite.Sprite): self.rect.x -= 1 def handleGarlicYChange(self): - if self.targetYChange < 0: - if self.rect.bottom > self.originalY + self.targetYChange: # 注意这里加的是负数 + if self.target_y_change < 0: + if self.rect.bottom > self.original_y + self.target_y_change: # 注意这里加的是负数 self.rect.bottom -= 3 # 过半时换行 - if ((self.toChangeGroup) and - (self.rect.bottom >= self.originalY + 0.5*self.targetYChange)): - self.level.zombie_groups[self.mapY].remove(self) - self.level.zombie_groups[self.targetMapY].add(self) - self.toChangeGroup = False + if ((self.to_change_group) and + (self.rect.bottom >= self.original_y + 0.5*self.target_y_change)): + self.level.zombie_groups[self.map_y].remove(self) + self.level.zombie_groups[self.target_map_y].add(self) + self.to_change_group = False else: - self.rect.bottom = self.originalY + self.targetYChange - self.originalY = self.rect.bottom - self.targetYChange = 0 - elif self.targetYChange > 0: - if self.rect.bottom < self.originalY + self.targetYChange: # 注意这里加的是负数 + self.rect.bottom = self.original_y + self.target_y_change + self.original_y = self.rect.bottom + self.target_y_change = 0 + elif self.target_y_change > 0: + if self.rect.bottom < self.original_y + self.target_y_change: # 注意这里加的是负数 self.rect.bottom += 3 # 过半时换行 - if ((self.toChangeGroup) and - (self.rect.bottom <= self.originalY + 0.5*self.targetYChange)): - self.level.zombie_groups[self.mapY].remove(self) - self.level.zombie_groups[self.targetMapY].add(self) - self.toChangeGroup = False + if ((self.to_change_group) and + (self.rect.bottom <= self.original_y + 0.5*self.target_y_change)): + self.level.zombie_groups[self.map_y].remove(self) + self.level.zombie_groups[self.target_map_y].add(self) + self.to_change_group = False else: - self.rect.bottom = self.originalY + self.targetYChange - self.originalY = self.rect.bottom - self.targetYChange = 0 + self.rect.bottom = self.original_y + self.target_y_change + self.original_y = self.rect.bottom + self.target_y_change = 0 def attacking(self): if self.checkToDie(self.losthead_attack_frames): return - if self.helmetHealth <= 0 and self.helmet: + if self.helmet_health <= 0 and self.helmet: self.changeFrames(self.attack_frames) self.helmet = False - if self.helmetType2Health <= 0 and self.helmetType2: + if self.helmet_type2_health <= 0 and self.helmet_type2: self.changeFrames(self.attack_frames) - self.helmetType2 = False + self.helmet_type2 = False if self.name == c.NEWSPAPER_ZOMBIE: self.speed = 2.65 self.walk_animate_interval = 300 if (((self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getAttackTimeRatio())) - and (not self.lostHead)): + and (not self.losthead)): if self.prey.health > 0: if self.prey_is_plant: self.prey.setDamage(self.damage, self) @@ -281,8 +284,8 @@ class Zombie(pg.sprite.Sprite): def setLostHead(self): self.losthead_timer = self.current_time - self.lostHead = True - self.animate_interval = self.lostHead_animate_interval + self.losthead = True + self.animate_interval = self.losthead_animate_interval if self.head_group is not None: self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom)) @@ -347,87 +350,87 @@ class Zombie(pg.sprite.Sprite): # 冰冻减速效果 if effect == c.BULLET_EFFECT_ICE: if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速 - if not self.helmetType2: + if not self.helmet_type2: self.setIceSlow() else: self.setIceSlow() # 解冻 elif effect == c.BULLET_EFFECT_UNICE: if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速 - if not self.helmetType2: + if not self.helmet_type2: self.ice_slow_ratio = 1 else: self.ice_slow_ratio = 1 if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 不穿透二类防具的攻击 # 从第二类防具开始逐级传递 - if self.helmetType2: - self.helmetType2Health -= damage - if self.helmetType2Health <= 0: + if self.helmet_type2: + self.helmet_type2_health -= damage + if self.helmet_type2_health <= 0: if self.helmet: - self.helmetHealth += self.helmetType2Health # 注意self.helmetType2Health已经带有正负 - self.helmetType2Health = 0 # 注意合并后清零 - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health += self.helmet_type2_health # 注意self.helmet_type2_health已经带有正负 + self.helmet_type2_health = 0 # 注意合并后清零 + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: - self.health += self.helmetType2Health - self.helmetType2Health = 0 + self.health += self.helmet_type2_health + self.helmet_type2_health = 0 elif self.helmet: # 不存在二类防具,但是存在一类防具 - self.helmetHealth -= damage - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health -= damage + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: # 没有防具 self.health -= damage elif damageType == c.ZOMBIE_COMMON_DAMAGE: # 无视二类防具,将攻击一类防具与本体视为整体的攻击 if self.helmet: # 存在一类防具 - self.helmetHealth -= damage - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health -= damage + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: # 没有一类防具 self.health -= damage elif damageType == c.ZOMBIE_RANGE_DAMAGE: # 从第二类防具开始逐级传递 - if self.helmetType2: - self.helmetType2Health -= damage - if self.helmetType2Health <= 0: + if self.helmet_type2: + self.helmet_type2_health -= damage + if self.helmet_type2_health <= 0: if self.helmet: - self.helmetHealth -= damage # 注意范围伤害中这里还有一个攻击 - self.helmetHealth += self.helmetType2Health # 注意self.helmetType2Health已经带有正负 - self.helmetType2Health = 0 # 注意合并后清零 - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health -= damage # 注意范围伤害中这里还有一个攻击 + self.helmet_health += self.helmet_type2_health # 注意self.helmet_type2_health已经带有正负 + self.helmet_type2_health = 0 # 注意合并后清零 + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: self.health -= damage # 注意范围伤害中这里还有一个攻击 - self.health += self.helmetType2Health - self.helmetType2Health = 0 + self.health += self.helmet_type2_health + self.helmet_type2_health = 0 else: if self.helmet: - self.helmetHealth -= damage - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health -= damage + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: self.health -= damage elif self.helmet: # 不存在二类防具,但是存在一类防具 - self.helmetHealth -= damage - if self.helmetHealth <= 0: - self.health += self.helmetHealth - self.helmetHealth = 0 # 注意合并后清零 + self.helmet_health -= damage + if self.helmet_health <= 0: + self.health += self.helmet_health + self.helmet_health = 0 # 注意合并后清零 else: # 没有防具 self.health -= damage elif damageType == c.ZOMBIE_ASH_DAMAGE: self.health -= damage # 无视任何防具 elif damageType == c.ZOMBIE_WALLNUT_BOWLING_DANMAGE: # 逻辑:对防具的多余伤害不传递 - if self.helmetType2: + if self.helmet_type2: # 对二类防具伤害较一般情况低,拟合铁门需要砸3次的设定 - self.helmetType2Health -= int(damage * 0.8) + self.helmet_type2_health -= int(damage * 0.8) elif self.helmet: # 不存在二类防具,但是存在一类防具 - self.helmetHealth -= damage + self.helmet_health -= damage else: # 没有防具 self.health -= damage else: @@ -441,28 +444,28 @@ class Zombie(pg.sprite.Sprite): self.state = c.WALK self.animate_interval = self.walk_animate_interval - if self.helmet or self.helmetType2: # 这里暂时没有考虑同时有两种防具的僵尸 + if self.helmet or self.helmet_type2: # 这里暂时没有考虑同时有两种防具的僵尸 self.changeFrames(self.helmet_walk_frames) - elif self.lostHead: + elif self.losthead: self.changeFrames(self.losthead_walk_frames) else: self.changeFrames(self.walk_frames) - if self.canSwim: + if self.can_swim: if self.rect.right <= c.MAP_POOL_FRONT_X: self.swimming = True self.changeFrames(self.swim_frames) # 同样没有兼容双防具 if self.helmet: - if self.helmetHealth <= 0: + if self.helmet_health <= 0: self.changeFrames(self.swim_frames) self.helmet = False else: self.changeFrames(self.helmet_swim_frames) - if self.helmetType2: - if self.helmetType2Health <= 0: + if self.helmet_type2: + if self.helmet_type2_health <= 0: self.changeFrames(self.swim_frames) - self.helmetType2 = False + self.helmet_type2 = False else: self.changeFrames(self.helmet_swim_frames) @@ -473,9 +476,9 @@ class Zombie(pg.sprite.Sprite): self.attack_timer = self.current_time self.animate_interval = self.attack_animate_interval - if self.helmet or self.helmetType2: # 这里暂时没有考虑同时有两种防具的僵尸 + if self.helmet or self.helmet_type2: # 这里暂时没有考虑同时有两种防具的僵尸 self.changeFrames(self.helmet_attack_frames) - elif self.lostHead: + elif self.losthead: self.changeFrames(self.losthead_attack_frames) else: self.changeFrames(self.attack_frames) @@ -558,7 +561,7 @@ class NormalZombie(Zombie): # 路障僵尸 class ConeHeadZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, head_group, helmetHealth=c.CONEHEAD_HEALTH) + Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, head_group, helmet_health=c.CONEHEAD_HEALTH) def loadImages(self): self.helmet_walk_frames = [] @@ -594,7 +597,7 @@ class ConeHeadZombie(Zombie): class BucketHeadZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.BUCKETHEAD_ZOMBIE, head_group, helmetHealth=c.BUCKETHEAD_HEALTH) + Zombie.__init__(self, x, y, c.BUCKETHEAD_ZOMBIE, head_group, helmet_health=c.BUCKETHEAD_HEALTH) def loadImages(self): self.helmet_walk_frames = [] @@ -661,8 +664,8 @@ class FlagZombie(Zombie): class NewspaperZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, head_group, helmetType2Health=c.NEWSPAPER_HEALTH) - self.speedUp = False + Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, head_group, helmet_type2_health=c.NEWSPAPER_HEALTH) + self.speed_up = False def loadImages(self): self.helmet_walk_frames = [] @@ -707,9 +710,9 @@ class NewspaperZombie(Zombie): if self.checkToDie(self.losthead_walk_frames): return - if self.helmetType2Health <= 0 and self.helmetType2: + if self.helmet_type2_health <= 0 and self.helmet_type2: self.changeFrames(self.lostnewspaper_frames) - self.helmetType2 = False + self.helmet_type2 = False # 触发报纸撕裂音效 c.SOUND_NEWSPAPER_RIP.play() if ((self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio())): @@ -733,9 +736,9 @@ class NewspaperZombie(Zombie): if self.state == c.DIE: self.kill() return - elif self.frames == self.lostnewspaper_frames and (not self.speedUp): + elif self.frames == self.lostnewspaper_frames and (not self.speed_up): self.changeFrames(self.walk_frames) - self.speedUp = True + self.speed_up = True self.speed = 2.65 self.walk_animate_interval = 300 # 触发报纸僵尸暴走音效 @@ -755,12 +758,12 @@ class NewspaperZombie(Zombie): class FootballZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.FOOTBALL_ZOMBIE, head_group, helmetHealth=c.FOOTBALL_HELMET_HEALTH) + Zombie.__init__(self, x, y, c.FOOTBALL_ZOMBIE, head_group, helmet_health=c.FOOTBALL_HELMET_HEALTH) self.speed = 1.88 self.animate_interval = 50 self.walk_animate_interval = 50 self.attack_animate_interval = 60 - self.lostHead_animate_interval = 180 + self.losthead_animate_interval = 180 self.die_animate_interval = 150 def loadImages(self): @@ -796,7 +799,7 @@ class FootballZombie(Zombie): class DuckyTubeZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.DUCKY_TUBE_ZOMBIE, head_group, canSwim=True) + Zombie.__init__(self, x, y, c.DUCKY_TUBE_ZOMBIE, head_group, can_swim=True) def loadImages(self): self.walk_frames = [] @@ -827,7 +830,7 @@ class DuckyTubeZombie(Zombie): class ConeHeadDuckyTubeZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.CONEHEAD_DUCKY_TUBE_ZOMBIE, head_group, helmetHealth=c.CONEHEAD_HEALTH ,canSwim=True) + Zombie.__init__(self, x, y, c.CONEHEAD_DUCKY_TUBE_ZOMBIE, head_group, helmet_health=c.CONEHEAD_HEALTH ,can_swim=True) def loadImages(self): self.helmet_walk_frames = [] @@ -865,7 +868,7 @@ class ConeHeadDuckyTubeZombie(Zombie): class BucketHeadDuckyTubeZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.BUCKETHEAD_DUCKY_TUBE_ZOMBIE, head_group, helmetHealth=c.BUCKETHEAD_HEALTH ,canSwim=True) + Zombie.__init__(self, x, y, c.BUCKETHEAD_DUCKY_TUBE_ZOMBIE, head_group, helmet_health=c.BUCKETHEAD_HEALTH ,can_swim=True) def loadImages(self): self.helmet_walk_frames = [] @@ -903,7 +906,7 @@ class BucketHeadDuckyTubeZombie(Zombie): class ScreenDoorZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.SCREEN_DOOR_ZOMBIE, head_group, helmetType2Health=c.SCREEN_DOOR_HEALTH) + Zombie.__init__(self, x, y, c.SCREEN_DOOR_ZOMBIE, head_group, helmet_type2_health=c.SCREEN_DOOR_HEALTH) def loadImages(self): self.helmet_walk_frames = [] @@ -939,7 +942,7 @@ class ScreenDoorZombie(Zombie): class PoleVaultingZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.POLE_VAULTING_ZOMBIE, head_group=head_group, bodyHealth=c.POLE_VAULTING_HEALTH, lostHeadHealth=c.POLE_VAULTING_LOSTHEAD_HEALTH) + Zombie.__init__(self, x, y, c.POLE_VAULTING_ZOMBIE, head_group=head_group, body_health=c.POLE_VAULTING_HEALTH, losthead_health=c.POLE_VAULTING_LOSTHEAD_HEALTH) self.speed = 1.88 self.jumped = False self.jumping = False @@ -975,12 +978,12 @@ class PoleVaultingZombie(Zombie): self.frames = self.walk_before_jump_frames - def setJump(self, successfullyJumped, jumpX): + def setJump(self, successfullyJumped, jump_x): if not self.jumping: self.jumping = True self.changeFrames(self.jump_frames) self.successfullyJumped = successfullyJumped - self.jumpX = jumpX + self.jump_x = jump_x # 播放跳跃音效 c.SOUND_POLEVAULT_JUMP.play() @@ -1005,7 +1008,7 @@ class PoleVaultingZombie(Zombie): if self.jumping and (not self.jumped): self.changeFrames(self.walk_frames) if self.successfullyJumped: - self.rect.centerx = self.jumpX + self.rect.centerx = self.jump_x self.jumped = True self.speed = 1.04 self.animate_timer = self.current_time @@ -1043,7 +1046,7 @@ class PoleVaultingZombie(Zombie): # 注意:冰车僵尸移动变速 class Zomboni(Zombie): def __init__(self, x, y, plant_group, map, IceFrozenPlot): - Zombie.__init__(self, x, y, c.ZOMBONI, bodyHealth=c.ZOMBONI_HEALTH) + Zombie.__init__(self, x, y, c.ZOMBONI, body_health=c.ZOMBONI_HEALTH) self.plant_group = plant_group self.map = map self.IceFrozenPlot = IceFrozenPlot @@ -1095,7 +1098,7 @@ class Zomboni(Zombie): elif self.health <= c.ZOMBONI_DAMAGED1_HEALTH: self.changeFrames(self.walk_damaged1_frames) - if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()) and (not self.lostHead): + if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()) and (not self.losthead): self.walk_timer = self.current_time if self.is_hypno: self.rect.x += 1 @@ -1111,14 +1114,14 @@ class Zomboni(Zombie): plant.health -= 8000 # 造冰 - mapX, mapY = self.map.getMapIndex(self.rect.right - 40, self.rect.bottom) - if 0 <= mapX < c.GRID_X_LEN: - if c.ICEFROZENPLOT not in self.map.map[mapY][mapX]: - x, y = self.map.getMapGridPos(mapX, mapY) + map_x, map_y = self.map.getMapIndex(self.rect.right - 40, self.rect.bottom) + if 0 <= map_x < c.GRID_X_LEN: + if c.ICEFROZENPLOT not in self.map.map[map_y][map_x]: + x, y = self.map.getMapGridPos(map_x, map_y) self.plant_group.add(self.IceFrozenPlot(x, y)) - self.map.map[mapY][mapX][c.MAP_PLANT].add(c.ICEFROZENPLOT) + self.map.map[map_y][map_x][c.MAP_PLANT].add(c.ICEFROZENPLOT) - self.speed = max(0.6, 1.5 - (c.GRID_X_LEN + 1 - mapX)*0.225) + self.speed = max(0.6, 1.5 - (c.GRID_X_LEN + 1 - map_x)*0.225) def setDie(self): self.state = c.DIE @@ -1130,7 +1133,7 @@ class Zomboni(Zombie): class SnorkelZombie(Zombie): def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.SNORKELZOMBIE, canSwim=True) + Zombie.__init__(self, x, y, c.SNORKELZOMBIE, can_swim=True) self.speed = 1.175 self.walk_animate_interval = 60 self.canSetAttack = True @@ -1250,7 +1253,7 @@ class SnorkelZombie(Zombie): self.prey_is_plant = is_plant self.animate_interval = self.attack_animate_interval - if self.lostHead: + if self.losthead: self.changeFrames(self.losthead_attack_frames) elif self.canSetAttack: self.changeFrames(self.float_frames) diff --git a/source/constants.py b/source/constants.py index dc9e2e8..dc38fc5 100755 --- a/source/constants.py +++ b/source/constants.py @@ -71,6 +71,7 @@ PARCHMENT_YELLOW = (207, 146, 83) # 退出游戏按钮 EXIT = "exit" +HELP = "help" # 游戏界面可选的菜单 LITTLE_MENU = "littleMenu" BIG_MENU = "bigMenu" @@ -110,6 +111,7 @@ GAME_LOSE = "game lose" GAME_VICTORY = "game victory" LEVEL = "level" AWARD_SCREEN = "award screen" +HELP_SCREEN = "help screen" # 界面图片文件名 MAIN_MENU_IMAGE = "MainMenu" @@ -117,6 +119,7 @@ OPTION_ADVENTURE = "Adventure" GAME_LOSE_IMAGE = "GameLose" GAME_VICTORY_IMAGE = "GameVictory" AWARD_SCREEN_IMAGE = "AwardScreen" +HELP_SCREEN_IMAGE = "HelpScreen" # 地图相关内容 BACKGROUND_NAME = "Background" @@ -166,8 +169,8 @@ GRAVES_GRADE_INFO = (0, 4, 7, 11) # 僵尸生成方式 SPAWN_ZOMBIES = "spawn_zombies" -SPAWN_ZOMBIES_AUTO = "auto" -SPAWN_ZOMBIES_LIST = "list" +SPAWN_ZOMBIES_AUTO = 1 +SPAWN_ZOMBIES_LIST = 0 INCLUDED_ZOMBIES = "included_zombies" NUM_FLAGS = "num_flags" INEVITABLE_ZOMBIE_DICT = "inevitable_zombie_list" @@ -302,7 +305,7 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间) 50000), (DOOMSHROOM := "DoomShroom", CARD_DOOMSHROOM := "card_doomshroom", - 75, + 125, 50000), (LILYPAD := "LilyPad", CARD_LILYPAD := "card_lilypad", @@ -509,8 +512,7 @@ SNORKELZOMBIE = "SnorkelZombie" BOOMDIE = "BoomDie" # 对僵尸的攻击类型设置 -ZOMBIE_DEAFULT_DAMAGE = "helmet2First" -ZOMBIE_HELMET_2_FIRST = "helmet2First" # 优先攻击二类防具 +ZOMBIE_DEAFULT_DAMAGE = ZOMBIE_HELMET_2_FIRST = "helmet2First" # 优先攻击二类防具 ZOMBIE_COMMON_DAMAGE = "commonDamage" # 优先攻击僵尸与一类防具的整体 ZOMBIE_RANGE_DAMAGE = "rangeDamage" # 范围攻击,同时伤害二类防具与(僵尸与一类防具的整体) ZOMBIE_ASH_DAMAGE = "ashDamage" # 灰烬植物攻击,直接伤害本体 diff --git a/source/state/level.py b/source/state/level.py index 61c7833..d383241 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -18,10 +18,10 @@ class Level(tool.State): # 暂停状态 self.pause = False - self.pauseTime = 0 + self.pause_time = 0 # 默认显然不用显示菜单 - self.showLittleMenu = False + self.show_game_menu = False # 导入地图参数 self.loadMap() @@ -35,6 +35,7 @@ class Level(tool.State): if self.game_info[c.GAME_MODE] == c.MODE_ADVENTURE: if 0 <= self.game_info[c.LEVEL_NUM] < map.TOTAL_LEVEL: self.map_data = map.LEVEL_MAP_DATA[self.game_info[c.LEVEL_NUM]] + pg.display.set_caption(f"pypvz: 冒险模式 第{self.game_info[c.LEVEL_NUM]}关") else: self.game_info[c.LEVEL_NUM] = 1 self.saveUserData() @@ -44,13 +45,14 @@ class Level(tool.State): elif self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME: if 0 <= self.game_info[c.LITTLEGAME_NUM] < map.TOTAL_LITTLE_GAME: self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]] + pg.display.set_caption(f"pypvz: 玩玩小游戏 第{self.game_info[c.LITTLEGAME_NUM]}关") else: self.game_info[c.LITTLEGAME_NUM] = 1 self.saveUserData() self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]] logger.warning("关卡数设定错误!进入默认的第一关!") # 是否有铲子的信息:无铲子时为0,有铲子时为1,故直接赋值即可 - self.hasShovel = self.map_data[c.SHOVEL] + self.has_shovel = self.map_data[c.SHOVEL] # 同时指定音乐 # 缺省音乐为进入的音乐,方便发现错误 @@ -171,128 +173,128 @@ class Level(tool.State): # 最后一波或者大于最后一波 # 如果在夜晚按需从墓碑生成僵尸 # 否则直接return - if self.waveNum >= self.map_data[c.NUM_FLAGS] * 10: + if self.wave_num >= self.map_data[c.NUM_FLAGS] * 10: if self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_NIGHT: # 生长墓碑 - if not self.graveInLevelAdded: - if current_time - self.waveTime > 100: + if not self.new_grave_added: + if current_time - self.wave_time > 100: # 墓碑最多有12个 - if len(self.graveSet) < 12: + if len(self.grave_set) < 12: unoccupied = [] occupied = [] # 毁灭菇坑与冰道应当特殊化 exceptionObjects = {c.HOLE, c.ICEFROZENPLOT} # 遍历能生成墓碑的区域 - for mapY in range(0, 4): - for mapX in range(4, 8): + for map_y in range(0, 4): + for map_x in range(4, 8): # 为空、为毁灭菇坑、为冰道时看作未被植物占据 - if ((not self.map.map[mapY][mapX][c.MAP_PLANT]) or - (all((i in exceptionObjects) for i in self.map.map[mapY][mapX][c.MAP_PLANT]))): - unoccupied.append((mapX, mapY)) + if ((not self.map.map[map_y][map_x][c.MAP_PLANT]) or + (all((i in exceptionObjects) for i in self.map.map[map_y][map_x][c.MAP_PLANT]))): + unoccupied.append((map_x, map_y)) # 已有墓碑的格子不应该放到任何列表中 - elif c.GRAVE not in self.map.map[mapY][mapX][c.MAP_PLANT]: - occupied.append((mapX, mapY)) + elif c.GRAVE not in self.map.map[map_y][map_x][c.MAP_PLANT]: + occupied.append((map_x, map_y)) if unoccupied: target = unoccupied[random.randint(0, len(unoccupied) - 1)] - mapX, mapY = target - posX, posY = self.map.getMapGridPos(mapX, mapY) - self.plant_groups[mapY].add(plant.Grave(posX, posY)) - self.map.map[mapY][mapX][c.MAP_PLANT].add(c.GRAVE) - self.graveSet.add((mapX, mapY)) + map_x, map_y = target + posX, posY = self.map.getMapGridPos(map_x, map_y) + self.plant_groups[map_y].add(plant.Grave(posX, posY)) + self.map.map[map_y][map_x][c.MAP_PLANT].add(c.GRAVE) + self.grave_set.add((map_x, map_y)) elif occupied: target = occupied[random.randint(0, len(occupied) - 1)] - mapX, mapY = target - posX, posY = self.map.getMapGridPos(mapX, mapY) - for i in self.plant_groups[mapY]: + map_x, map_y = target + posX, posY = self.map.getMapGridPos(map_x, map_y) + for i in self.plant_groups[map_y]: checkMapX, _ = self.map.getMapIndex(i.rect.centerx, i.rect.bottom) - if mapX == checkMapX: + if map_x == checkMapX: # 不杀死毁灭菇坑和冰道 if i.name not in exceptionObjects: i.health = 0 - self.plant_groups[mapY].add(plant.Grave(posX, posY)) - self.map.map[mapY][mapX][c.MAP_PLANT].add(c.GRAVE) - self.graveSet.add((mapX, mapY)) - self.graveInLevelAdded = True + self.plant_groups[map_y].add(plant.Grave(posX, posY)) + self.map.map[map_y][map_x][c.MAP_PLANT].add(c.GRAVE) + self.grave_set.add((map_x, map_y)) + self.new_grave_added = True # 从墓碑中生成僵尸 - if not self.graveZombieCreated: - if current_time - self.waveTime > 1500: - for item in self.graveSet: - itemX, itemY = self.map.getMapGridPos(*item) - # 目前设定:2/3概率普通僵尸,1/3概率路障僵尸 - if random.randint(0, 2): - self.zombie_groups[item[1]].add(zombie.NormalZombie(itemX, itemY, self.head_group)) + if not self.grave_zombie_created: + if current_time - self.wave_time > 1500: + for item in self.grave_set: + item_x, item_y = self.map.getMapGridPos(*item) + # 目前设定:1/2概率普通僵尸,1/2概率路障僵尸 + if random.randint(0, 1): + self.zombie_groups[item[1]].add(zombie.NormalZombie(item_x, item_y, self.head_group)) else: - self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(itemX, itemY, self.head_group)) - self.graveZombieCreated = True + self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(item_x, item_y, self.head_group)) + self.grave_zombie_created = True elif self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS: if not self.createdZombieFromPool: - if current_time - self.waveTime > 1500: + if current_time - self.wave_time > 1500: for i in range(3): # 水中倒数四列内可以在此时产生僵尸。共产生3个 - mapX, mapY = random.randint(5, 8), random.randint(2, 3) - itemX, itemY = self.map.getMapGridPos(mapX, mapY) + map_x, map_y = random.randint(5, 8), random.randint(2, 3) + item_x, item_y = self.map.getMapGridPos(map_x, map_y) # 用随机数指定产生的僵尸类型 - # 带有权重 - zombieType = random.randint(1, 6) + # 暂时设定为生成概率相同 + zombieType = random.randint(1, 3) if zombieType == 1: - self.zombie_groups[mapY].add(zombie.BucketHeadDuckyTubeZombie(itemX, itemY, self.head_group)) - elif zombieType <= 3: - self.zombie_groups[mapY].add(zombie.ConeHeadDuckyTubeZombie(itemX, itemY, self.head_group)) + self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(item_x, item_y, self.head_group)) + elif zombieType == 2: + self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(item_x, item_y, self.head_group)) else: - self.zombie_groups[mapY].add(zombie.DuckyTubeZombie(itemX, itemY, self.head_group)) + self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(item_x, item_y, self.head_group)) self.createdZombieFromPool = True return # 还未开始出现僵尸 - if (self.waveNum == 0): - if (self.waveTime == 0): # 表明刚刚开始游戏 - self.waveTime = current_time + if (self.wave_num == 0): + if (self.wave_time == 0): # 表明刚刚开始游戏 + self.wave_time = current_time else: if (survivalRounds == 0) and (self.bar_type == c.CHOOSEBAR_STATIC): # 首次选卡等待时间较长 - if current_time - self.waveTime >= 18000: - self.waveNum += 1 - self.waveTime = current_time - self.waveZombies = self.waves[self.waveNum - 1] - self.numZombie = len(self.waveZombies) + if current_time - self.wave_time >= 18000: + self.wave_num += 1 + self.wave_time = current_time + self.wave_zombies = self.waves[self.wave_num - 1] + self.zombie_num = len(self.wave_zombies) c.SOUND_ZOMBIE_COMING.play() else: - if (current_time - self.waveTime >= 6000): - self.waveNum += 1 - self.waveTime = current_time - self.waveZombies = self.waves[self.waveNum - 1] - self.numZombie = len(self.waveZombies) + if (current_time - self.wave_time >= 6000): + self.wave_num += 1 + self.wave_time = current_time + self.wave_zombies = self.waves[self.wave_num - 1] + self.zombie_num = len(self.wave_zombies) c.SOUND_ZOMBIE_COMING.play() return - if (self.waveNum % 10 != 9): - if ((current_time - self.waveTime >= 25000 + random.randint(0, 6000)) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.waveTime >= 12500 + random.randint(0, 3000))): - self.waveNum += 1 - self.waveTime = current_time - self.waveZombies = self.waves[self.waveNum - 1] - self.numZombie = len(self.waveZombies) + if (self.wave_num % 10 != 9): + if ((current_time - self.wave_time >= 25000 + random.randint(0, 6000)) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.wave_time >= 12500 + random.randint(0, 3000))): + self.wave_num += 1 + self.wave_time = current_time + self.wave_zombies = self.waves[self.wave_num - 1] + self.zombie_num = len(self.wave_zombies) c.SOUND_ZOMBIE_VOICE.play() else: - if ((current_time - self.waveTime >= 45000) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.waveTime >= 25000)): - self.waveNum += 1 - self.waveTime = current_time - self.waveZombies = self.waves[self.waveNum - 1] - self.numZombie = len(self.waveZombies) + if ((current_time - self.wave_time >= 45000) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.wave_time >= 25000)): + self.wave_num += 1 + self.wave_time = current_time + self.wave_zombies = self.waves[self.wave_num - 1] + self.zombie_num = len(self.wave_zombies) # 一大波时播放音效 c.SOUND_HUGE_WAVE_APPROCHING.play() return - elif ((current_time - self.waveTime >= 43000) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.waveTime >= 23000)): - self.showHugeWaveApprochingTime = current_time + elif ((current_time - self.wave_time >= 43000) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.wave_time >= 23000)): + self.show_hugewave_approching_time = current_time - numZombies = 0 + zombie_nums = 0 for i in range(self.map_y_len): - numZombies += len(self.zombie_groups[i]) - if (numZombies / self.numZombie < random.uniform(0.15, 0.25)) and (current_time - self.waveTime > 4000): + zombie_nums += len(self.zombie_groups[i]) + if (zombie_nums / self.zombie_num < random.uniform(0.15, 0.25)) and (current_time - self.wave_time > 4000): # 当僵尸所剩无几并且时间过了4000 ms以上时,改变时间记录,使得2000 ms后刷新僵尸(所以需要判断剩余时间是否大于2000 ms) if self.bar_type == c.CHOOSEBAR_STATIC: - if current_time - 43000 < self.waveTime: # 判断剩余时间是否有2000 ms - self.waveTime = current_time - 43000 # 即倒计时2000 ms + if current_time - 43000 < self.wave_time: # 判断剩余时间是否有2000 ms + self.wave_time = current_time - 43000 # 即倒计时2000 ms else: - if current_time - 23000 < self.waveTime: # 判断剩余时间是否有2000 ms - self.waveTime = current_time - 23000 # 即倒计时2000 ms + if current_time - 23000 < self.wave_time: # 判断剩余时间是否有2000 ms + self.wave_time = current_time - 23000 # 即倒计时2000 ms # 旧机制,目前仅用于调试 @@ -314,7 +316,7 @@ class Level(tool.State): # 更新函数每帧被调用,将鼠标事件传入给状态处理函数 def update(self, surface, current_time, mouse_pos, mouse_click): - self.current_time = self.game_info[c.CURRENT_TIME] = self.pvzTime(current_time) + self.current_time = self.game_info[c.CURRENT_TIME] = self.gameTime(current_time) if self.state == c.CHOOSE: self.choose(mouse_pos, mouse_click) elif self.state == c.PLAY: @@ -322,13 +324,13 @@ class Level(tool.State): self.draw(surface) - def pvzTime(self, current_time): + def gameTime(self, current_time): # 扣除暂停时间 if not self.pause: - self.beforePauseTime = current_time - self.pauseTime + self.before_pause_time = current_time - self.pause_time else: - self.pauseTime = current_time - self.beforePauseTime - return self.beforePauseTime + self.pause_time = current_time - self.before_pause_time + return self.before_pause_time def initBowlingMap(self): for x in range(3, self.map.width): @@ -363,7 +365,7 @@ class Level(tool.State): def choose(self, mouse_pos, mouse_click): # 如果暂停 - if self.showLittleMenu: + if self.show_game_menu: self.pauseAndCheckLittleMenuOptions(mouse_pos, mouse_click) return @@ -372,7 +374,7 @@ class Level(tool.State): if self.panel.checkStartButtonClick(mouse_pos): self.initPlay(self.panel.getSelectedCards()) elif self.inArea(self.little_menu_rect, *mouse_pos): - self.showLittleMenu = True + self.show_game_menu = True c.SOUND_BUTTON_CLICK.play() def initPlay(self, card_list): @@ -398,7 +400,7 @@ class Level(tool.State): # 用种下植物的名称与位置元组判断是否需要刷新僵尸的攻击对象 # 种植植物后应当刷新僵尸的攻击对象,当然,默认初始时不用刷新 - self.newPlantAndPositon = None + self.new_plant_and_positon = None if self.background_type in c.DAYTIME_BACKGROUNDS and self.bar_type == c.CHOOSEBAR_STATIC: self.produce_sun = True @@ -412,10 +414,10 @@ class Level(tool.State): self.setupZombies() else: # 僵尸波数数据及僵尸生成数据 - self.waveNum = 0 # 还未出现僵尸时定义为0 - self.waveTime = 0 - self.waveZombies = [] - self.numZombie = 0 + self.wave_num = 0 # 还未出现僵尸时定义为0 + self.wave_time = 0 + self.wave_zombies = [] + self.zombie_num = 0 # 暂时没有生存模式,所以 survivalRounds = 0 if c.INEVITABLE_ZOMBIE_DICT in self.map_data: @@ -430,14 +432,14 @@ class Level(tool.State): self.setupCars() # 地图有铲子才添加铲子 - if self.hasShovel: + if self.has_shovel: # 导入小铲子 frame_rect = [0, 0, 71, 67] - self.shovel = tool.get_image_menu(tool.GFX[c.SHOVEL], *frame_rect, c.BLACK, 1.1) + self.shovel = tool.get_image_alpha(tool.GFX[c.SHOVEL], *frame_rect, c.BLACK, 1.1) self.shovel_rect = self.shovel.get_rect() frame_rect = [0, 0, 77, 75] self.shovel_positon = (608, 1) - self.shovel_box = tool.get_image_menu(tool.GFX[c.SHOVEL_BOX], *frame_rect, c.BLACK, 1.1) + self.shovel_box = tool.get_image_alpha(tool.GFX[c.SHOVEL_BOX], *frame_rect, c.BLACK, 1.1) self.shovel_box_rect = self.shovel_box.get_rect() self.shovel_rect.x = self.shovel_box_rect.x = self.shovel_positon[0] self.shovel_rect.y = self.shovel_box_rect.y = self.shovel_positon[1] @@ -445,45 +447,45 @@ class Level(tool.State): self.setupLevelProgressBarImage() self.setupHugeWaveApprochingImage() - self.showHugeWaveApprochingTime = -2000 # 防止设置为0时刚刚打开游戏就已经启动红字 + self.show_hugewave_approching_time = -2000 # 防止设置为0时刚刚打开游戏就已经启动红字 if self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_NIGHT: # 判断墓碑数量等级 # 0为无墓碑,1为少量墓碑,2为中等量墓碑,3为大量墓碑 if c.GRADE_GRAVES in self.map_data: - gradeGraves = self.map_data[c.GRADE_GRAVES] + grade_graves = self.map_data[c.GRADE_GRAVES] # 缺省为少量墓碑 else: - gradeGraves = 1 + grade_graves = 1 - graveVolume = c.GRAVES_GRADE_INFO[gradeGraves] - self.graveSet = set() - while len(self.graveSet) < graveVolume: - mapX = random.randint(4, 8) # 注意是从0开始编号 - mapY = random.randint(0, 4) - self.graveSet.add((mapX, mapY)) - if self.graveSet: - for i in self.graveSet: - mapX, mapY = i - posX, posY = self.map.getMapGridPos(mapX, mapY) - self.plant_groups[mapY].add(plant.Grave(posX, posY)) - self.map.map[mapY][mapX][c.MAP_PLANT].add(c.GRAVE) - self.graveZombieCreated = False - self.graveInLevelAdded = False + graveVolume = c.GRAVES_GRADE_INFO[grade_graves] + self.grave_set = set() + while len(self.grave_set) < graveVolume: + map_x = random.randint(4, 8) # 注意是从0开始编号 + map_y = random.randint(0, 4) + self.grave_set.add((map_x, map_y)) + if self.grave_set: + for i in self.grave_set: + map_x, map_y = i + posX, posY = self.map.getMapGridPos(map_x, map_y) + self.plant_groups[map_y].add(plant.Grave(posX, posY)) + self.map.map[map_y][map_x][c.MAP_PLANT].add(c.GRAVE) + self.grave_zombie_created = False + self.new_grave_added = False # 小菜单 def setupLittleMenu(self): # 具体运行游戏必定有个小菜单, 导入菜单和选项 frame_rect = (0, 0, 108, 31) - self.little_menu = tool.get_image_menu(tool.GFX[c.LITTLE_MENU], *frame_rect, c.BLACK, 1.1) + self.little_menu = tool.get_image_alpha(tool.GFX[c.LITTLE_MENU], *frame_rect, c.BLACK, 1.1) self.little_menu_rect = self.little_menu.get_rect() self.little_menu_rect.x = 690 self.little_menu_rect.y = 0 # 弹出的菜单框 frame_rect = (0, 0, 500, 500) - self.big_menu = tool.get_image_menu(tool.GFX[c.BIG_MENU], *frame_rect, c.BLACK, 1.1) + self.big_menu = tool.get_image_alpha(tool.GFX[c.BIG_MENU], *frame_rect, c.BLACK, 1.1) self.big_menu_rect = self.big_menu.get_rect() self.big_menu_rect.x = 150 self.big_menu_rect.y = 0 @@ -505,14 +507,14 @@ class Level(tool.State): # 重新开始按钮 frame_rect = (0, 0, 207, 45) - self.restart_button = tool.get_image_menu(tool.GFX[c.RESTART_BUTTON], *frame_rect, c.BLACK, 1.1) + self.restart_button = tool.get_image_alpha(tool.GFX[c.RESTART_BUTTON], *frame_rect, c.BLACK, 1.1) self.restart_button_rect = self.restart_button.get_rect() self.restart_button_rect.x = 295 self.restart_button_rect.y = 325 # 主菜单按钮 frame_rect = (0, 0, 206, 43) - self.mainMenu_button = tool.get_image_menu(tool.GFX[c.MAINMENU_BUTTON], *frame_rect, c.BLACK, 1.1) + self.mainMenu_button = tool.get_image_alpha(tool.GFX[c.MAINMENU_BUTTON], *frame_rect, c.BLACK, 1.1) self.mainMenu_button_rect = self.mainMenu_button.get_rect() self.mainMenu_button_rect.x = 299 self.mainMenu_button_rect.y = 372 @@ -522,7 +524,7 @@ class Level(tool.State): font = pg.font.Font(c.FONT_PATH, 35) font.bold = True # 音量+ - self.sound_volume_plus_button = tool.get_image_menu(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) + self.sound_volume_plus_button = tool.get_image_alpha(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) sign = font.render("+", True, c.YELLOWGREEN) sign_rect = sign.get_rect() sign_rect.x = 8 @@ -531,7 +533,7 @@ class Level(tool.State): self.sound_volume_plus_button_rect = self.sound_volume_plus_button.get_rect() self.sound_volume_plus_button_rect.x = 500 # 音量- - self.sound_volume_minus_button = tool.get_image_menu(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) + self.sound_volume_minus_button = tool.get_image_alpha(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) sign = font.render("-", True, c.YELLOWGREEN) sign_rect = sign.get_rect() sign_rect.x = 12 @@ -552,7 +554,7 @@ class Level(tool.State): if self.inArea(self.return_button_rect, *mouse_pos): # 终止暂停,停止显示菜单 self.pause = False - self.showLittleMenu = False + self.show_game_menu = False # 继续播放音乐 pg.mixer.music.unpause() # 播放点击音效 @@ -595,7 +597,7 @@ class Level(tool.State): # 一大波僵尸来袭图片显示 def setupHugeWaveApprochingImage(self): frame_rect = (0, 0, 492, 80) - self.huge_wave_approching_image = tool.get_image_menu(tool.GFX[c.HUGE_WAVE_APPROCHING], *frame_rect, c.BLACK, 1) + self.huge_wave_approching_image = tool.get_image_alpha(tool.GFX[c.HUGE_WAVE_APPROCHING], *frame_rect, c.BLACK, 1) self.huge_wave_approching_image_rect = self.huge_wave_approching_image.get_rect() self.huge_wave_approching_image_rect.x = 140 # 猜的 self.huge_wave_approching_image_rect.y = 250 # 猜的 @@ -606,21 +608,21 @@ class Level(tool.State): # 主进度条 frame_rect = (0, 0, 158, 26) - self.level_progress_bar_image = tool.get_image_menu(tool.GFX[c.LEVEL_PROGRESS_BAR], *frame_rect, c.BLACK, 1) + self.level_progress_bar_image = tool.get_image_alpha(tool.GFX[c.LEVEL_PROGRESS_BAR], *frame_rect, c.BLACK, 1) self.level_progress_bar_image_rect = self.level_progress_bar_image.get_rect() self.level_progress_bar_image_rect.x = 600 self.level_progress_bar_image_rect.y = 574 # 僵尸头 frame_rect = (0, 0, 23, 25) - self.level_progress_zombie_head_image = tool.get_image_menu(tool.GFX[c.LEVEL_PROGRESS_ZOMBIE_HEAD], *frame_rect, c.BLACK, 1) + self.level_progress_zombie_head_image = tool.get_image_alpha(tool.GFX[c.LEVEL_PROGRESS_ZOMBIE_HEAD], *frame_rect, c.BLACK, 1) self.level_progress_zombie_head_image_rect = self.level_progress_zombie_head_image.get_rect() self.level_progress_zombie_head_image_rect.x = self.level_progress_bar_image_rect.x + 75 self.level_progress_zombie_head_image_rect.y = self.level_progress_bar_image_rect.y - 3 # 旗帜(这里只包括最后一面) frame_rect = (0, 0, 20, 18) - self.level_progress_flag = tool.get_image_menu(tool.GFX[c.LEVEL_PROGRESS_FLAG], *frame_rect, c.BLACK, 1) + self.level_progress_flag = tool.get_image_alpha(tool.GFX[c.LEVEL_PROGRESS_FLAG], *frame_rect, c.BLACK, 1) self.level_progress_flag_rect = self.level_progress_flag.get_rect() self.level_progress_flag_rect.x = self.level_progress_bar_image_rect.x - 78 self.level_progress_flag_rect.y = self.level_progress_bar_image_rect.y - 3 @@ -654,10 +656,10 @@ class Level(tool.State): def play(self, mouse_pos, mouse_click): # 原版阳光掉落机制需要 # 已掉落的阳光 - self.fallenSun = 0 + self.fallen_sun = 0 # 如果暂停 - if self.showLittleMenu: + if self.show_game_menu: self.pauseAndCheckLittleMenuOptions(mouse_pos, mouse_click) return @@ -674,10 +676,10 @@ class Level(tool.State): else: # 新僵尸生成方式 self.refreshWaves(self.current_time) - for i in self.waveZombies: + for i in self.wave_zombies: self.createZombie(i) else: - self.waveZombies = [] + self.wave_zombies = [] for i in range(self.map_y_len): @@ -695,42 +697,42 @@ class Level(tool.State): if self.produce_sun: # 原版阳光掉落机制:(已掉落阳光数*100 ms + 4250 ms) 与 9500 ms的最小值,再加 0 ~ 2750 ms 之间的一个数 - if (self.current_time - self.sun_timer) > min(c.PRODUCE_SUN_INTERVAL + 100*self.fallenSun, 9500) + random.randint(0, 2750): + if (self.current_time - self.sun_timer) > min(c.PRODUCE_SUN_INTERVAL + 100*self.fallen_sun, 9500) + random.randint(0, 2750): self.sun_timer = self.current_time map_x, map_y = self.map.getRandomMapIndex() x, y = self.map.getMapGridPos(map_x, map_y) self.sun_group.add(plant.Sun(x, 0, x, y)) - self.fallenSun += 1 + self.fallen_sun += 1 # wcb 添加 # 检查有没有捡到阳光 - clickedSun = False - clickedCardsOrMap = False + clicked_sun = False + clicked_cards_or_map = False if not self.drag_plant and not self.drag_shovel and mouse_pos and mouse_click[0]: for sun in self.sun_group: if sun.checkCollision(mouse_pos[0], mouse_pos[1]): self.menubar.increaseSunValue(sun.sun_value) - clickedSun = True + clicked_sun = True # 播放收集阳光的音效 c.SOUND_COLLECT_SUN.play() # 拖动植物或者铲子 - if not self.drag_plant and mouse_pos and mouse_click[0] and not clickedSun: - self.clickResult = self.menubar.checkCardClick(mouse_pos) - if self.clickResult: - self.setupMouseImage(self.clickResult[0], self.clickResult[1]) - self.clickResult[1].clicked = True - clickedCardsOrMap = True + if not self.drag_plant and mouse_pos and mouse_click[0] and not clicked_sun: + self.click_result = self.menubar.checkCardClick(mouse_pos) + if self.click_result: + self.setupMouseImage(self.click_result[0], self.click_result[1]) + self.click_result[1].clicked = True + clicked_cards_or_map = True # 播放音效 c.SOUND_CLICK_CARD.play() elif self.drag_plant: if mouse_click[1]: self.removeMouseImage() - clickedCardsOrMap = True - self.clickResult[1].clicked = False + clicked_cards_or_map = True + self.click_result[1].clicked = False elif mouse_click[0]: if self.menubar.checkMenuBarClick(mouse_pos): - self.clickResult[1].clicked = False + self.click_result[1].clicked = False self.removeMouseImage() else: self.addPlant() @@ -741,13 +743,13 @@ class Level(tool.State): self.removeMouseImagePlus() # 检查是否点击菜单 - if mouse_click[0] and (not clickedSun) and (not clickedCardsOrMap): + if mouse_click[0] and (not clicked_sun) and (not clicked_cards_or_map): if self.inArea(self.little_menu_rect, *mouse_pos): # 暂停 显示菜单 - self.showLittleMenu = True + self.show_game_menu = True # 播放点击音效 c.SOUND_BUTTON_CLICK.play() - elif self.hasShovel: + elif self.has_shovel: if self.inArea(self.shovel_box_rect, *mouse_pos): self.drag_shovel = not self.drag_shovel if not self.drag_shovel: @@ -797,51 +799,51 @@ class Level(tool.State): if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_AUTO: # 旗帜波出生点右移 - if self.waveNum % 10: - hugeWaveMove = 0 + if self.wave_num % 10: + huge_wave_move = 0 else: - hugeWaveMove = 40 + huge_wave_move = 40 else: - hugeWaveMove = 0 + huge_wave_move = 0 x, y = self.map.getMapGridPos(0, map_y) # 新增的僵尸也需要在这里声明 if name == c.NORMAL_ZOMBIE: - self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.CONEHEAD_ZOMBIE: - self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.BUCKETHEAD_ZOMBIE: - self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.FLAG_ZOMBIE: self.zombie_groups[map_y].add(zombie.FlagZombie(c.ZOMBIE_START_X, y, self.head_group)) elif name == c.NEWSPAPER_ZOMBIE: - self.zombie_groups[map_y].add(zombie.NewspaperZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.NewspaperZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.FOOTBALL_ZOMBIE: - self.zombie_groups[map_y].add(zombie.FootballZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.FootballZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.DUCKY_TUBE_ZOMBIE: - self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.CONEHEAD_DUCKY_TUBE_ZOMBIE: - self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.BUCKETHEAD_DUCKY_TUBE_ZOMBIE: - self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.SCREEN_DOOR_ZOMBIE: - self.zombie_groups[map_y].add(zombie.ScreenDoorZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.ScreenDoorZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + huge_wave_move, y, self.head_group)) elif name == c.POLE_VAULTING_ZOMBIE: # 本来撑杆跳生成位置不同,对齐左端可认为修正了一部分(看作移动了70),只需要相对修改即可 - self.zombie_groups[map_y].add(zombie.PoleVaultingZombie(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.PoleVaultingZombie(c.ZOMBIE_START_X + random.randint(0, 10) + huge_wave_move, y, self.head_group)) elif name == c.ZOMBONI: # 冰车僵尸生成位置不同 - self.zombie_groups[map_y].add(zombie.Zomboni(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.plant_groups[map_y], self.map, plant.IceFrozenPlot)) + self.zombie_groups[map_y].add(zombie.Zomboni(c.ZOMBIE_START_X + random.randint(0, 10) + huge_wave_move, y, self.plant_groups[map_y], self.map, plant.IceFrozenPlot)) elif name == c.SNORKELZOMBIE: # 潜水僵尸生成位置不同 - self.zombie_groups[map_y].add(zombie.SnorkelZombie(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.head_group)) + self.zombie_groups[map_y].add(zombie.SnorkelZombie(c.ZOMBIE_START_X + random.randint(0, 10) + huge_wave_move, y, self.head_group)) # 能否种植物的判断: # 先判断位置是否合法 isValid(map_x, map_y) # 再判断位置是否可用 isMovable(map_x, map_y) - def canSeedPlant(self, plantName): + def canSeedPlant(self, plant_name): x, y = pg.mouse.get_pos() - return self.map.checkPlantToSeed(x, y, plantName) + return self.map.checkPlantToSeed(x, y, plant_name) # 种植物 def addPlant(self): @@ -850,7 +852,7 @@ class Level(tool.State): return # 恢复植物卡片样式 - self.clickResult[1].clicked = False + self.click_result[1].clicked = False if self.hint_image is None: self.setupHintImage() @@ -911,7 +913,7 @@ class Level(tool.State): elif self.plant_name == c.TANGLEKLEP: new_plant = plant.TangleKlep(x, y) elif self.plant_name == c.DOOMSHROOM: - if self.map.gridHeightSize == c.GRID_Y_SIZE: + if self.map.grid_height_size == c.GRID_Y_SIZE: new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=2) else: new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=3) @@ -927,13 +929,13 @@ class Level(tool.State): if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS: new_plant.setSleep() - mushroomSleep = True + mushroom_sleep = True else: - mushroomSleep = False + mushroom_sleep = False self.plant_groups[map_y].add(new_plant) # 种植植物后应当刷新僵尸的攻击对象 # 用元组表示植物的名称和格子坐标 - self.newPlantAndPositon = (new_plant.name, (map_x, map_y)) + self.new_plant_and_positon = (new_plant.name, (map_x, map_y)) if self.bar_type == c.CHOOSEBAR_STATIC: self.menubar.decreaseSunValue(self.select_plant.sun_cost) self.menubar.setCardFrozenTime(self.plant_name) @@ -941,10 +943,10 @@ class Level(tool.State): self.menubar.deleateCard(self.select_plant) if self.bar_type != c.CHOOSEBAR_BOWLING: # 坚果保龄球关卡无需考虑格子被占用的情况 - self.map.addMapPlant(map_x, map_y, self.plant_name, sleep=mushroomSleep) + self.map.addMapPlant(map_x, map_y, self.plant_name, sleep=mushroom_sleep) self.removeMouseImage() - # print(self.newPlantAndPositon) + # print(self.new_plant_and_positon) # 播放种植音效 c.SOUND_PLANT.play() @@ -1026,7 +1028,6 @@ class Level(tool.State): def checkZombieCollisions(self): for i in range(self.map_y_len): - hypo_zombies = [] for zombie in self.zombie_groups[i]: if zombie.name == c.ZOMBONI: continue @@ -1039,107 +1040,107 @@ class Level(tool.State): if zombie.state != c.ATTACK: continue # 没有新的植物种下时不用刷新 - if not self.newPlantAndPositon: + if not self.new_plant_and_positon: continue # 被攻击对象是植物时才可能刷新 if zombie.prey_is_plant: # 新植物种在被攻击植物同一格时才可能刷新 - if (zombie.preyMapX, zombie.preyMapY) == self.newPlantAndPositon[1]: + if (zombie.prey_map_x, zombie.prey_map_y) == self.new_plant_and_positon[1]: # 如果被攻击植物是睡莲和花盆,同一格种了植物必然刷新 # 如果被攻击植物不是睡莲和花盆,同一格种了南瓜头才刷新 if ((zombie.prey.name not in {c.LILYPAD, "花盆(未实现)"}) - and (self.newPlantAndPositon[0] != c.PUMPKINHEAD)): + and (self.new_plant_and_positon[0] != c.PUMPKINHEAD)): continue else: continue else: continue - if zombie.canSwim and (not zombie.swimming): + if zombie.can_swim and (not zombie.swimming): continue # 以下代码为了实现各个功能,较为凌乱 - attackableCommonPlants = [] - attackableBackupPlant = [] + attackable_common_plants = [] + attackable_backup_plants = [] # 利用更加精细的循环判断啃咬优先顺序 for plant in self.plant_groups[i]: if collided_func(plant, zombie): # 优先攻击南瓜头 if plant.name == c.PUMPKINHEAD: - targetPlant = plant + target_plant = plant break # 衬底植物情形 elif plant.name in {c.LILYPAD, "花盆(未实现)"}: - attackableBackupPlant.append(plant) + attackable_backup_plants.append(plant) # 一般植物情形 # 同时也忽略了不可啃食对象 elif plant.name not in c.CAN_SKIP_ZOMBIE_COLLISION_CHECK: - attackableCommonPlants.append(plant) + attackable_common_plants.append(plant) # 在生效状态下忽略啃食碰撞但其他状况下不能忽略的情形 elif plant.name in c.SKIP_ZOMBIE_COLLISION_CHECK_WHEN_WORKING: if not plant.start_boom: - attackableCommonPlants.append(plant) + attackable_common_plants.append(plant) else: - if attackableCommonPlants: + if attackable_common_plants: # 默认为最右侧的一个植物 - targetPlant = max(attackableCommonPlants, key=lambda i: i.rect.x) - elif attackableBackupPlant: - targetPlant = max(attackableBackupPlant, key=lambda i: i.rect.x) - map_x, map_y = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.centery) + target_plant = max(attackable_common_plants, key=lambda i: i.rect.x) + elif attackable_backup_plants: + target_plant = max(attackable_backup_plants, key=lambda i: i.rect.x) + map_x, map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery) if len(self.map.map[map_y][map_x][c.MAP_PLANT]) >= 2: - for actualTargetPlant in self.plant_groups[i]: + for actual_target_plant in self.plant_groups[i]: # 检测同一格的其他植物 - if self.map.getMapIndex(actualTargetPlant.rect.centerx, actualTargetPlant.rect.bottom) == (map_x, map_y): - if actualTargetPlant.name == c.PUMPKINHEAD: - targetPlant = actualTargetPlant + if self.map.getMapIndex(actual_target_plant.rect.centerx, actual_target_plant.rect.bottom) == (map_x, map_y): + if actual_target_plant.name == c.PUMPKINHEAD: + target_plant = actual_target_plant break - elif actualTargetPlant.name not in {c.LILYPAD, "花盆(未实现)"}: - attackableCommonPlants.append(actualTargetPlant) + elif actual_target_plant.name not in {c.LILYPAD, "花盆(未实现)"}: + attackable_common_plants.append(actual_target_plant) else: - if attackableCommonPlants: - targetPlant = attackableCommonPlants[-1] + if attackable_common_plants: + target_plant = attackable_common_plants[-1] else: - targetPlant = None + target_plant = None - if targetPlant: - zombie.preyMapX, zombie.preyMapY = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.centery) + if target_plant: + zombie.prey_map_x, zombie.prey_map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery) # 撑杆跳的特殊情况 if zombie.name in {c.POLE_VAULTING_ZOMBIE} and (not zombie.jumped): if not zombie.jumping: - zombie.jumpMap_x, zombie.jumpMap_y = min(c.GRID_X_LEN - 1, zombie.preyMapX), min(self.map_y_len - 1, zombie.preyMapY) - jumpX = targetPlant.rect.x - c.GRID_X_SIZE * 0.6 - if c.TALLNUT in self.map.map[zombie.jumpMap_y][zombie.jumpMap_x][c.MAP_PLANT]: - zombie.setJump(False, jumpX) + zombie.jump_map_x, zombie.jump_map_y = min(c.GRID_X_LEN - 1, zombie.prey_map_x), min(self.map_y_len - 1, zombie.prey_map_y) + jump_x = target_plant.rect.x - c.GRID_X_SIZE * 0.6 + if c.TALLNUT in self.map.map[zombie.jump_map_y][zombie.jump_map_x][c.MAP_PLANT]: + zombie.setJump(False, jump_x) else: - zombie.setJump(True, jumpX) + zombie.setJump(True, jump_x) else: - if c.TALLNUT in self.map.map[zombie.jumpMap_y][zombie.jumpMap_x][c.MAP_PLANT]: - zombie.setJump(False, zombie.jumpX) + if c.TALLNUT in self.map.map[zombie.jump_map_y][zombie.jump_map_x][c.MAP_PLANT]: + zombie.setJump(False, zombie.jump_x) else: - zombie.setJump(True, zombie.jumpX) + zombie.setJump(True, zombie.jump_x) continue - if targetPlant.name == c.WALLNUTBOWLING: - if targetPlant.canHit(i): - # targetPlant.vel_y不为0,有纵向速度,表明已经发生过碰撞,对铁门秒杀(这里实现为忽略二类防具攻击) - if targetPlant.vel_y and zombie.name == c.SCREEN_DOOR_ZOMBIE: + if target_plant.name == c.WALLNUTBOWLING: + if target_plant.canHit(i): + # target_plant.vel_y不为0,有纵向速度,表明已经发生过碰撞,对铁门秒杀(这里实现为忽略二类防具攻击) + if target_plant.vel_y and zombie.name == c.SCREEN_DOOR_ZOMBIE: zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damageType=c.ZOMBIE_COMMON_DAMAGE) else: zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damageType=c.ZOMBIE_WALLNUT_BOWLING_DANMAGE) - targetPlant.changeDirection(i) + target_plant.changeDirection(i) # 播放撞击音效 c.SOUND_BOWLING_IMPACT.play() - elif targetPlant.name == c.REDWALLNUTBOWLING: - if targetPlant.state == c.IDLE: - targetPlant.setAttack() - elif zombie.targetYChange: + elif target_plant.name == c.REDWALLNUTBOWLING: + if target_plant.state == c.IDLE: + target_plant.setAttack() + elif zombie.target_y_change: # 大蒜作用正在生效的僵尸不进行传递 continue - elif targetPlant.name == c.GARLIC: - zombie.setAttack(targetPlant) + elif target_plant.name == c.GARLIC: + zombie.setAttack(target_plant) # 向吃过大蒜的僵尸传入level zombie.level = self - zombie.toChangeGroup = True - zombie.mapY = i + zombie.to_change_group = True + zombie.map_y = i if i == 0: _move = 1 elif i == self.map_y_len - 1: @@ -1148,10 +1149,10 @@ class Level(tool.State): _move = random.randint(0, 1)*2 - 1 if self.map.map[i][0][c.MAP_PLOT_TYPE] != self.map.map[i + _move][0][c.MAP_PLOT_TYPE]: _move = -(_move) - zombie.targetMapY = i + _move - zombie.targetYChange = _move * self.map.gridHeightSize + zombie.target_map_y = i + _move + zombie.target_y_change = _move * self.map.grid_height_size else: - zombie.setAttack(targetPlant) + zombie.setAttack(target_plant) for hypno_zombie in self.hypno_zombie_groups[i]: if hypno_zombie.health <= 0: @@ -1162,23 +1163,24 @@ class Level(tool.State): for zombie in zombie_list: if zombie.state == c.DIE: continue + # 正常僵尸攻击被魅惑的僵尸 if zombie.state == c.WALK: zombie.setAttack(hypno_zombie, False) + # 被魅惑的僵尸攻击正常僵尸 if hypno_zombie.state == c.WALK: hypno_zombie.setAttack(zombie, False) else: - self.newPlantAndPositon = None # 生效后需要解除刷新设置 + self.new_plant_and_positon = None # 生效后需要解除刷新设置 def checkCarCollisions(self): for i in range(len(self.cars)): if self.cars[i]: for zombie in self.zombie_groups[i]: - if zombie and zombie.state != c.DIE and (not zombie.lostHead) and (zombie.rect.centerx <= 0): + if zombie and zombie.state != c.DIE and (not zombie.losthead) and (zombie.rect.centerx <= 0): self.cars[i].setWalk() if zombie.rect.centerx <= self.cars[i].rect.x: zombie.health = 0 - # zombie.kill() if self.cars[i].dead: self.cars[i] = None @@ -1204,29 +1206,29 @@ class Level(tool.State): zombie.setFreeze(plant.trap_frames[0]) zombie.setDamage(20, damageType=c.ZOMBIE_RANGE_DAMAGE) # 寒冰菇还有全场20的伤害 - def killPlant(self, targetPlant, shovel=False): - x, y = targetPlant.getPosition() + def killPlant(self, target_plant, shovel=False): + x, y = target_plant.getPosition() map_x, map_y = self.map.getMapIndex(x, y) # 用铲子铲不用触发植物功能 if not shovel: - if targetPlant.name == c.HYPNOSHROOM and targetPlant.state != c.SLEEP: - if targetPlant.zombie_to_hypno: - zombie = targetPlant.zombie_to_hypno + if target_plant.name == c.HYPNOSHROOM and target_plant.state != c.SLEEP: + if target_plant.zombie_to_hypno: + zombie = target_plant.zombie_to_hypno zombie.setHypno() self.zombie_groups[map_y].remove(zombie) self.hypno_zombie_groups[map_y].add(zombie) # 对于墓碑:移除存储在墓碑集合中的坐标 # 注意这里是在描述墓碑而非墓碑吞噬者 - elif targetPlant.name == c.GRAVE: - self.graveSet.remove((map_x, map_y)) - elif ((targetPlant.name in { c.DOOMSHROOM, c.ICESHROOM, + elif target_plant.name == c.GRAVE: + self.grave_set.remove((map_x, map_y)) + elif ((target_plant.name in { c.DOOMSHROOM, c.ICESHROOM, c.POTATOMINE, }) - and (targetPlant.boomed)): + and (target_plant.boomed)): # 毁灭菇的情况:爆炸时为了防止蘑菇云被坑掩盖没有加入坑,这里毁灭菇死亡(即爆炸动画结束)后再加入 - if targetPlant.name == c.DOOMSHROOM: - self.plant_groups[map_y].add(plant.Hole(targetPlant.originalX, targetPlant.originalY, self.map.map[map_y][map_x][c.MAP_PLOT_TYPE])) - elif targetPlant.name not in c.PLANT_DIE_SOUND_EXCEPTIONS: + if target_plant.name == c.DOOMSHROOM: + self.plant_groups[map_y].add(plant.Hole(target_plant.original_x, target_plant.original_y, self.map.map[map_y][map_x][c.MAP_PLOT_TYPE])) + elif target_plant.name not in c.PLANT_DIE_SOUND_EXCEPTIONS: # 触发植物死亡音效 c.SOUND_PLANT_DIE.play() else: @@ -1235,29 +1237,29 @@ class Level(tool.State): # 整理地图信息 if self.bar_type != c.CHOOSEBAR_BOWLING: - self.map.removeMapPlant(map_x, map_y, targetPlant.name) + self.map.removeMapPlant(map_x, map_y, target_plant.name) # 将睡眠植物移除后更新睡眠状态 - if targetPlant.state == c.SLEEP: + if target_plant.state == c.SLEEP: self.map.map[map_y][map_x][c.MAP_SLEEP] = False # 避免僵尸在用铲子移除植物后还在原位啃食 - targetPlant.health = 0 - targetPlant.kill() + target_plant.health = 0 + target_plant.kill() - def checkPlant(self, targetPlant, i): + def checkPlant(self, target_plant, i): zombie_len = len(self.zombie_groups[i]) # 不用检查攻击状况的情况 - if targetPlant.name in c.PLANT_NON_CHECK_ATTACK_STATE: + if target_plant.name in c.PLANT_NON_CHECK_ATTACK_STATE: pass - elif targetPlant.name == c.THREEPEASHOOTER: - if targetPlant.state == c.IDLE: + elif target_plant.name == c.THREEPEASHOOTER: + if target_plant.state == c.IDLE: if zombie_len > 0: - targetPlant.setAttack() + target_plant.setAttack() elif (i-1) >= 0 and len(self.zombie_groups[i-1]) > 0: - targetPlant.setAttack() + target_plant.setAttack() elif (i+1) < self.map_y_len and len(self.zombie_groups[i+1]) > 0: - targetPlant.setAttack() - elif targetPlant.state == c.ATTACK: + target_plant.setAttack() + elif target_plant.state == c.ATTACK: if zombie_len > 0: pass elif (i-1) >= 0 and len(self.zombie_groups[i-1]) > 0: @@ -1265,111 +1267,111 @@ class Level(tool.State): elif (i+1) < self.map_y_len and len(self.zombie_groups[i+1]) > 0: pass else: - targetPlant.setIdle() - elif targetPlant.name == c.CHOMPER: + target_plant.setIdle() + elif target_plant.name == c.CHOMPER: for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): - targetPlant.setAttack(zombie, self.zombie_groups[i]) + if target_plant.canAttack(zombie): + target_plant.setAttack(zombie, self.zombie_groups[i]) break - elif targetPlant.name == c.POTATOMINE: + elif target_plant.name == c.POTATOMINE: for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): - targetPlant.setAttack() + if target_plant.canAttack(zombie): + target_plant.setAttack() break - if targetPlant.start_boom and (not targetPlant.boomed): + if target_plant.start_boom and (not target_plant.boomed): for zombie in self.zombie_groups[i]: # 双判断:发生碰撞或在攻击范围内 - if ((pg.sprite.collide_mask(zombie, targetPlant)) or - (abs(zombie.rect.centerx - targetPlant.rect.centerx) <= targetPlant.explode_x_range)): + if ((pg.sprite.collide_mask(zombie, target_plant)) or + (abs(zombie.rect.centerx - target_plant.rect.centerx) <= target_plant.explode_x_range)): zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE) - targetPlant.boomed = True - elif targetPlant.name == c.SQUASH: + target_plant.boomed = True + elif target_plant.name == c.SQUASH: for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): - targetPlant.setAttack(zombie, self.zombie_groups[i]) + if target_plant.canAttack(zombie): + target_plant.setAttack(zombie, self.zombie_groups[i]) break - elif targetPlant.name == c.SPIKEWEED: + elif target_plant.name == c.SPIKEWEED: can_attack = False for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): + if target_plant.canAttack(zombie): can_attack = True break - if targetPlant.state == c.IDLE and can_attack: - targetPlant.setAttack(self.zombie_groups[i]) - elif targetPlant.state == c.ATTACK and not can_attack: - targetPlant.setIdle() - elif targetPlant.name == c.SCAREDYSHROOM: + if target_plant.state == c.IDLE and can_attack: + target_plant.setAttack(self.zombie_groups[i]) + elif target_plant.state == c.ATTACK and not can_attack: + target_plant.setIdle() + elif target_plant.name == c.SCAREDYSHROOM: need_cry = False can_attack = False for zombie in self.zombie_groups[i]: - if targetPlant.needCry(zombie): + if target_plant.needCry(zombie): need_cry = True break - elif targetPlant.canAttack(zombie): + elif target_plant.canAttack(zombie): can_attack = True if need_cry: - if targetPlant.state != c.CRY: - targetPlant.setCry() + if target_plant.state != c.CRY: + target_plant.setCry() elif can_attack: - if targetPlant.state != c.ATTACK: - targetPlant.setAttack() - elif targetPlant.state != c.IDLE: - targetPlant.setIdle() - elif targetPlant.name == c.STARFRUIT: + if target_plant.state != c.ATTACK: + target_plant.setAttack() + elif target_plant.state != c.IDLE: + target_plant.setIdle() + elif target_plant.name == c.STARFRUIT: can_attack = False for zombie_group in self.zombie_groups: # 遍历循环所有僵尸 for zombie in zombie_group: - if targetPlant.canAttack(zombie): + if target_plant.canAttack(zombie): can_attack = True break - if targetPlant.state == c.IDLE and can_attack: - targetPlant.setAttack() - elif (targetPlant.state == c.ATTACK and not can_attack): - targetPlant.setIdle() - elif targetPlant.name == c.TANGLEKLEP: + if target_plant.state == c.IDLE and can_attack: + target_plant.setAttack() + elif (target_plant.state == c.ATTACK and not can_attack): + target_plant.setIdle() + elif target_plant.name == c.TANGLEKLEP: for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): - targetPlant.setAttack(zombie, self.zombie_groups[i]) + if target_plant.canAttack(zombie): + target_plant.setAttack(zombie, self.zombie_groups[i]) break # 灰烬植物与寒冰菇 - elif targetPlant.name in c.ASH_PLANTS_AND_ICESHROOM: - if targetPlant.start_boom and (not targetPlant.boomed): + elif target_plant.name in c.ASH_PLANTS_AND_ICESHROOM: + if target_plant.start_boom and (not target_plant.boomed): # 这样分成两层是因为场上灰烬植物肯定少,一个一个判断代价高,先笼统判断灰烬即可 - if targetPlant.name in {c.REDWALLNUTBOWLING, c.CHERRYBOMB}: - self.boomZombies(targetPlant.rect.centerx, i, targetPlant.explode_y_range, - targetPlant.explode_x_range) - elif (targetPlant.name == c.DOOMSHROOM): - x, y = targetPlant.originalX, targetPlant.originalY + if target_plant.name in {c.REDWALLNUTBOWLING, c.CHERRYBOMB}: + self.boomZombies(target_plant.rect.centerx, i, target_plant.explode_y_range, + target_plant.explode_x_range) + elif (target_plant.name == c.DOOMSHROOM): + x, y = target_plant.original_x, target_plant.original_y map_x, map_y = self.map.getMapIndex(x, y) - self.boomZombies(targetPlant.rect.centerx, i, targetPlant.explode_y_range, - targetPlant.explode_x_range) + self.boomZombies(target_plant.rect.centerx, i, target_plant.explode_y_range, + target_plant.explode_x_range) for item in self.plant_groups[map_y]: checkMapX, _ = self.map.getMapIndex(item.rect.centerx, item.rect.bottom) if map_x == checkMapX: item.health = 0 # 为了防止坑显示在蘑菇云前面,这里先不生成坑,仅填位置 self.map.map[map_y][map_x][c.MAP_PLANT].add(c.HOLE) - elif targetPlant.name == c.JALAPENO: - self.boomZombies(targetPlant.rect.centerx, i, targetPlant.explode_y_range, - targetPlant.explode_x_range, effect=c.BULLET_EFFECT_UNICE) + elif target_plant.name == c.JALAPENO: + self.boomZombies(target_plant.rect.centerx, i, target_plant.explode_y_range, + target_plant.explode_x_range, effect=c.BULLET_EFFECT_UNICE) # 消除冰道 for item in self.plant_groups[i]: if item.name == c.ICEFROZENPLOT: item.health = 0 - elif targetPlant.name == c.ICESHROOM: - self.freezeZombies(targetPlant) - targetPlant.boomed = True + elif target_plant.name == c.ICESHROOM: + self.freezeZombies(target_plant) + target_plant.boomed = True else: can_attack = False if (zombie_len > 0): for zombie in self.zombie_groups[i]: - if targetPlant.canAttack(zombie): + if target_plant.canAttack(zombie): can_attack = True break - if targetPlant.state == c.IDLE and can_attack: - targetPlant.setAttack() - elif (targetPlant.state == c.ATTACK and (not can_attack)): - targetPlant.setIdle() + if target_plant.state == c.IDLE and can_attack: + target_plant.setAttack() + elif (target_plant.state == c.ATTACK and (not can_attack)): + target_plant.setIdle() def checkPlants(self): for i in range(self.map_y_len): @@ -1387,7 +1389,7 @@ class Level(tool.State): if len(self.zombie_groups[i]) > 0: return False else: - if self.waveNum < self.map_data[c.NUM_FLAGS] * 10: + if self.wave_num < self.map_data[c.NUM_FLAGS] * 10: return False for i in range(self.map_y_len): if len(self.zombie_groups[i]) > 0: @@ -1397,8 +1399,8 @@ class Level(tool.State): def checkLose(self): for i in range(self.map_y_len): for zombie in self.zombie_groups[i]: - if zombie.rect.right < -20 and (not zombie.lostHead) and (zombie.state != c.DIE): - print(zombie.rect.right, zombie.lostHead, zombie.state,zombie.name) + if zombie.rect.right < -20 and (not zombie.losthead) and (zombie.state != c.DIE): + print(zombie.rect.right, zombie.losthead, zombie.state,zombie.name) return True return False @@ -1468,7 +1470,7 @@ class Level(tool.State): elif "花盆(未实现)" in self.map.map[map_y][map_x][c.MAP_PLANT]: if i.name == "花盆(未实现)": continue - i.highlightTime = self.current_time + i.highlight_time = self.current_time return def drawZombieFreezeTrap(self, i, surface): @@ -1481,12 +1483,12 @@ class Level(tool.State): surface.blit(self.level_progress_bar_image, self.level_progress_bar_image_rect) # 按照当前波数生成僵尸头位置 - self.level_progress_zombie_head_image_rect.x = self.level_progress_bar_image_rect.x - int((150 * self.waveNum) / (self.map_data[c.NUM_FLAGS] * 10)) + 145 # 常数为拟合值 + self.level_progress_zombie_head_image_rect.x = self.level_progress_bar_image_rect.x - int((150 * self.wave_num) / (self.map_data[c.NUM_FLAGS] * 10)) + 145 # 常数为拟合值 self.level_progress_zombie_head_image_rect.y = self.level_progress_bar_image_rect.y - 3 # 常数为拟合值 # 填充的进度条信息 # 常数为拟合值 - filledBarRect = (self.level_progress_zombie_head_image_rect.x + 3, self.level_progress_bar_image_rect.y + 6, int((150 * self.waveNum) / (self.map_data[c.NUM_FLAGS] * 10)) + 5, 9) + filledBarRect = (self.level_progress_zombie_head_image_rect.x + 3, self.level_progress_bar_image_rect.y + 6, int((150 * self.wave_num) / (self.map_data[c.NUM_FLAGS] * 10)) + 5, 9) # 画填充的进度条 pg.draw.rect(surface, c.YELLOWGREEN, filledBarRect) @@ -1528,11 +1530,11 @@ class Level(tool.State): self.panel.draw(surface) # 画小菜单 surface.blit(self.little_menu, self.little_menu_rect) - if self.showLittleMenu: + if self.show_game_menu: self.showAllContentOfMenu(surface) # 以后可能需要插入一个预备的状态(预览显示僵尸、返回战场) elif self.state == c.PLAY: - if self.hasShovel: + if self.has_shovel: # 画铲子 surface.blit(self.shovel_box, self.shovel_box_rect) surface.blit(self.shovel, self.shovel_rect) @@ -1554,13 +1556,13 @@ class Level(tool.State): if self.drag_plant: self.drawMouseShow(surface) - if self.hasShovel and self.drag_shovel: + if self.has_shovel and self.drag_shovel: self.drawMouseShowPlus(surface) - if self.showLittleMenu: + if self.show_game_menu: self.showAllContentOfMenu(surface) if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_AUTO: self.showLevelProgress(surface) - if self.current_time - self.showHugeWaveApprochingTime <= 2000: + if self.current_time - self.show_hugewave_approching_time <= 2000: surface.blit(self.huge_wave_approching_image, self.huge_wave_approching_image_rect) diff --git a/source/state/mainmenu.py b/source/state/mainmenu.py index 57702cc..5fc70ef 100644 --- a/source/state/mainmenu.py +++ b/source/state/mainmenu.py @@ -34,26 +34,30 @@ class Menu(tool.State): self.bg_rect = self.bg_image.get_rect() self.bg_rect.x = 0 self.bg_rect.y = 0 - + def setupOptions(self): # 冒险模式 - self.adventure_frames = [] - frame_names = (f"{c.OPTION_ADVENTURE}_0", f"{c.OPTION_ADVENTURE}_1") frame_rect = (0, 0, 330, 144) - for name in frame_names: - self.adventure_frames.append(tool.get_image_menu(tool.GFX[name], *frame_rect, c.BLACK, 1)) + # 写成列表生成器方便IDE识别与自动补全 + self.adventure_frames = [tool.get_image_alpha(tool.GFX[f"{c.OPTION_ADVENTURE}_{i}"], *frame_rect) for i in range(2)] self.adventure_image = self.adventure_frames[0] self.adventure_rect = self.adventure_image.get_rect() self.adventure_rect.x = 400 self.adventure_rect.y = 60 self.adventure_highlight_time = 0 - + + # 小游戏 + littleGame_frame_rect = (0, 7, 317, 135) + self.littleGame_frames = [tool.get_image_alpha(tool.GFX[f"{c.LITTLEGAME_BUTTON}_{i}"], *littleGame_frame_rect) for i in range(2)] + self.littleGame_image = self.littleGame_frames[0] + self.littleGame_rect = self.littleGame_image.get_rect() + self.littleGame_rect.x = 397 + self.littleGame_rect.y = 175 + self.littleGame_highlight_time = 0 + # 退出按钮 - self.exit_frames = [] - exit_frame_names = (f"{c.EXIT}_0", f"{c.EXIT}_1") exit_frame_rect = (0, 0, 47, 27) - for name in exit_frame_names: - self.exit_frames.append(tool.get_image_menu(tool.GFX[name], *exit_frame_rect, c.BLACK, 1.1)) + self.exit_frames = [tool.get_image_alpha(tool.GFX[f"{c.EXIT}_{i}"], *exit_frame_rect, scale=1.1) for i in range(2)] self.exit_image = self.exit_frames[0] self.exit_rect = self.exit_image.get_rect() self.exit_rect.x = 730 @@ -61,29 +65,24 @@ class Menu(tool.State): self.exit_highlight_time = 0 # 选项按钮 - self.option_button_frames = [] - option_button_frame_names = (f"{c.OPTION_BUTTON}_0", f"{c.OPTION_BUTTON}_1") option_button_frame_rect = (0, 0, 81, 31) - for name in option_button_frame_names: - self.option_button_frames.append(tool.get_image_menu(tool.GFX[name], *option_button_frame_rect, c.BLACK)) + self.option_button_frames = [tool.get_image_alpha(tool.GFX[f"{c.OPTION_BUTTON}_{i}"], *option_button_frame_rect) for i in range(2)] self.option_button_image = self.option_button_frames[0] self.option_button_rect = self.option_button_image.get_rect() self.option_button_rect.x = 560 self.option_button_rect.y = 490 - self.option_button_hightlight_time = 0 - - # 小游戏 - self.littleGame_frames = [] - littleGame_frame_names = (c.LITTLEGAME_BUTTON + "_0", c.LITTLEGAME_BUTTON + "_1") - littleGame_frame_rect = (0, 7, 317, 135) - for name in littleGame_frame_names: - self.littleGame_frames.append(tool.get_image_menu(tool.GFX[name], *littleGame_frame_rect, c.BLACK, 1)) - self.littleGame_image = self.littleGame_frames[0] - self.littleGame_rect = self.littleGame_image.get_rect() - self.littleGame_rect.x = 397 - self.littleGame_rect.y = 175 - self.littleGame_highlight_time = 0 + self.option_button_highlight_time = 0 + # 帮助菜单 + help_frame_rect = (0, 0, 48, 22) + self.help_frames = [tool.get_image_alpha(tool.GFX[f"{c.HELP}_{i}"], *help_frame_rect) for i in range(2)] + self.help_image = self.help_frames[0] + self.help_rect = self.help_image.get_rect() + self.help_rect.x = 653 + self.help_rect.y = 520 + self.help_hilight_time = 0 + + # 计时器与点击信号记录器 self.adventure_start = 0 self.adventure_timer = 0 self.adventure_clicked = False @@ -93,21 +92,25 @@ class Menu(tool.State): # 高亮冒险模式按钮 if self.inArea(self.adventure_rect, x, y): self.adventure_highlight_time = self.current_time + # 高亮小游戏按钮 + elif self.inArea(self.littleGame_rect, x, y): + self.littleGame_highlight_time = self.current_time # 高亮退出按钮 elif self.inArea(self.exit_rect, x, y): self.exit_highlight_time = self.current_time # 高亮选项按钮 elif self.inArea(self.option_button_rect, x, y): - self.option_button_hightlight_time = self.current_time - # 高亮小游戏按钮 - elif self.inArea(self.littleGame_rect, x, y): - self.littleGame_highlight_time = self.current_time + self.option_button_highlight_time = self.current_time + # 高亮帮助按钮 + elif self.inArea(self.help_rect, x, y): + self.help_hilight_time = self.current_time # 处理按钮高亮情况 self.adventure_image = self.chooseHilightImage(self.adventure_highlight_time, self.adventure_frames) self.exit_image = self.chooseHilightImage(self.exit_highlight_time, self.exit_frames) - self.option_button_image = self.chooseHilightImage(self.option_button_hightlight_time, self.option_button_frames) + self.option_button_image = self.chooseHilightImage(self.option_button_highlight_time, self.option_button_frames) self.littleGame_image = self.chooseHilightImage(self.littleGame_highlight_time, self.littleGame_frames) + self.help_image = self.chooseHilightImage(self.help_hilight_time, self.help_frames) def chooseHilightImage(self, hilightTime, frames): if (self.current_time - hilightTime) < 80: @@ -116,36 +119,35 @@ class Menu(tool.State): index = 0 return frames[index] - def checkAdventureClick(self, mouse_pos): - x, y = mouse_pos - if self.inArea(self.adventure_rect, x, y): - self.adventure_clicked = True - self.adventure_timer = self.adventure_start = self.current_time - self.persist[c.GAME_MODE] = c.MODE_ADVENTURE - # 播放进入音效 - c.SOUND_EVILLAUGH.play() - c.SOUND_LOSE.play() - - # 点击到按钮,修改转态的done属性 - def checkExitClick(self, mouse_pos): - x, y = mouse_pos - if self.inArea(self.exit_rect, x, y): - self.done = True - self.next = c.EXIT + def respondAdventureClick(self): + self.adventure_clicked = True + self.adventure_timer = self.adventure_start = self.current_time + self.persist[c.GAME_MODE] = c.MODE_ADVENTURE + # 播放进入音效 + c.SOUND_EVILLAUGH.play() + c.SOUND_LOSE.play() - # 检查有没有按到小游戏 - def checkLittleGameClick(self, mouse_pos): - x, y = mouse_pos - if self.inArea(self.littleGame_rect, x, y): - self.done = True - self.persist[c.GAME_MODE] = c.MODE_LITTLEGAME - # 播放点击音效 - c.SOUND_BUTTON_CLICK.play() + # 按到小游戏 + def respondLittleGameClick(self): + self.done = True + self.persist[c.GAME_MODE] = c.MODE_LITTLEGAME + # 播放点击音效 + c.SOUND_BUTTON_CLICK.play() + + # 点击到退出按钮,修改转态的done属性 + def respondExitClick(self): + self.done = True + self.next = c.EXIT + + # 帮助按钮点击 + def respondHelpClick(self): + self.done = True + self.next = c.HELP_SCREEN def setupOptionMenu(self): # 选项菜单框 frame_rect = (0, 0, 500, 500) - self.big_menu = tool.get_image_menu(tool.GFX[c.BIG_MENU], *frame_rect, c.BLACK, 1.1) + self.big_menu = tool.get_image_alpha(tool.GFX[c.BIG_MENU], *frame_rect, c.BLACK, 1.1) self.big_menu_rect = self.big_menu.get_rect() self.big_menu_rect.x = 150 self.big_menu_rect.y = 0 @@ -170,7 +172,7 @@ class Menu(tool.State): font = pg.font.Font(c.FONT_PATH, 35) font.bold = True # 音量+ - self.sound_volume_plus_button = tool.get_image_menu(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) + self.sound_volume_plus_button = tool.get_image_alpha(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) sign = font.render("+", True, c.YELLOWGREEN) sign_rect = sign.get_rect() sign_rect.x = 8 @@ -179,7 +181,7 @@ class Menu(tool.State): self.sound_volume_plus_button_rect = self.sound_volume_plus_button.get_rect() self.sound_volume_plus_button_rect.x = 500 # 音量- - self.sound_volume_minus_button = tool.get_image_menu(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) + self.sound_volume_minus_button = tool.get_image_alpha(tool.GFX[c.SOUND_VOLUME_BUTTON], *frame_rect, c.BLACK) sign = font.render("-", True, c.YELLOWGREEN) sign_rect = sign.get_rect() sign_rect.x = 12 @@ -197,7 +199,7 @@ class Menu(tool.State): frame_rect = (157, 0, 157, 269) else: frame_rect = (0, 0, 157, 269) - self.sunflower_trophy = tool.get_image_menu(tool.GFX[c.TROPHY_SUNFLOWER], *frame_rect, c.BLACK) + self.sunflower_trophy = tool.get_image_alpha(tool.GFX[c.TROPHY_SUNFLOWER], *frame_rect, c.BLACK) self.sunflower_trophy_rect = self.sunflower_trophy.get_rect() self.sunflower_trophy_rect.x = 0 self.sunflower_trophy_rect.y = 280 @@ -216,16 +218,14 @@ class Menu(tool.State): infoText = f"目前您一共完成了:玩玩小游戏{self.game_info[c.LITTLEGAME_COMPLETIONS]}轮;完成其他所有游戏模式以获得金向日葵奖杯!" infoImg = font.render(infoText , True, c.BLACK, c.LIGHTYELLOW) infoImg_rect = infoImg.get_rect() - infoImg_rect.x = x - infoImg_rect.y = y + infoImg_rect.x = self.sunflower_trophy_rect.x + infoImg_rect.y = self.sunflower_trophy_rect.bottom - 14 surface.blit(infoImg, infoImg_rect) - def checkOptionButtonClick(self, mouse_pos): - x, y = mouse_pos - if self.inArea(self.option_button_rect, x, y): - self.option_button_clicked = True - # 播放点击音效 - c.SOUND_BUTTON_CLICK.play() + def respondOptionButtonClick(self): + self.option_button_clicked = True + # 播放点击音效 + c.SOUND_BUTTON_CLICK.play() def showCurrentVolumeImage(self, surface): # 由于音量可变,因此这一内容不能在一开始就结束加载,而应当不断刷新不断显示 @@ -241,9 +241,10 @@ class Menu(tool.State): surface.blit(self.bg_image, self.bg_rect) surface.blit(self.adventure_image, self.adventure_rect) + surface.blit(self.littleGame_image, self.littleGame_rect) surface.blit(self.exit_image, self.exit_rect) surface.blit(self.option_button_image, self.option_button_rect) - surface.blit(self.littleGame_image, self.littleGame_rect) + surface.blit(self.help_image, self.help_rect) if self.game_info[c.LEVEL_COMPLETIONS] or self.game_info[c.LITTLEGAME_COMPLETIONS]: surface.blit(self.sunflower_trophy, self.sunflower_trophy_rect) @@ -294,7 +295,13 @@ class Menu(tool.State): if (self.game_info[c.LEVEL_COMPLETIONS] or self.game_info[c.LITTLEGAME_COMPLETIONS]): self.checkSunflowerTrophyInfo(surface, x, y) if mouse_pos: - self.checkExitClick(mouse_pos) - self.checkOptionButtonClick(mouse_pos) - self.checkLittleGameClick(mouse_pos) - self.checkAdventureClick(mouse_pos) + if self.inArea(self.adventure_rect, *mouse_pos): + self.respondAdventureClick() + elif self.inArea(self.littleGame_rect, *mouse_pos): + self.respondLittleGameClick() + elif self.inArea(self.option_button_rect, *mouse_pos): + self.respondOptionButtonClick() + elif self.inArea(self.exit_rect, *mouse_pos): + self.respondExitClick() + elif self.inArea(self.help_rect, *mouse_pos): + self.respondHelpClick() diff --git a/source/state/screen.py b/source/state/screen.py index 6580576..4a6e873 100644 --- a/source/state/screen.py +++ b/source/state/screen.py @@ -20,7 +20,7 @@ class Screen(tool.State): # 按钮 frame_rect = (0, 0, 111, 26) ## 主菜单按钮 - self.main_menu_button_image = tool.get_image_menu(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.main_menu_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) self.main_menu_button_image_rect = self.main_menu_button_image.get_rect() self.main_menu_button_image_rect.x = 620 ### 主菜单按钮上的文字 @@ -29,7 +29,7 @@ class Screen(tool.State): main_menu_text_rect = main_menu_text.get_rect() main_menu_text_rect.x = 29 ## 继续按钮 - self.next_button_image = tool.get_image_menu(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.next_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) self.next_button_image_rect = self.next_button_image.get_rect() self.next_button_image_rect.x = 70 ### 继续按钮上的文字 @@ -116,7 +116,7 @@ class AwardScreen(tool.State): frame_rect = (0, 0, 111, 26) if self.show_only_one_option: ## 主菜单按钮 - self.main_menu_button_image = tool.get_image_menu(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.main_menu_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) self.main_menu_button_image_rect = self.main_menu_button_image.get_rect() self.main_menu_button_image_rect.x = 343 self.main_menu_button_image_rect.y = 520 @@ -127,32 +127,7 @@ class AwardScreen(tool.State): main_menu_text_rect.x = 29 self.main_menu_button_image.blit(main_menu_text, main_menu_text_rect) self.image.blit(self.main_menu_button_image, self.main_menu_button_image_rect) - else: - ## 继续按钮 - self.next_button_image = tool.get_image_menu(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) - self.next_button_image_rect = self.next_button_image.get_rect() - self.next_button_image_rect.x = 70 - ### 继续按钮上的文字 - font = pg.font.Font(c.FONT_PATH, 18) - next_text = font.render("继续", True, c.NAVYBLUE) - next_text_rect = next_text.get_rect() - next_text_rect.x = 37 - ## 主菜单按钮 - self.main_menu_button_image = tool.get_image_menu(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) - self.main_menu_button_image_rect = self.main_menu_button_image.get_rect() - self.main_menu_button_image_rect.x = 620 - self.next_button_image_rect.y = self.main_menu_button_image_rect.y = 540 - ### 主菜单按钮上的文字 - main_menu_text = font.render("主菜单", True, c.NAVYBLUE) - main_menu_text_rect = main_menu_text.get_rect() - main_menu_text_rect.x = 29 - self.next_button_image.blit(next_text, next_text_rect) - self.main_menu_button_image.blit(main_menu_text, main_menu_text_rect) - self.image.blit(self.next_button_image, self.next_button_image_rect) - self.image.blit(self.main_menu_button_image, self.main_menu_button_image_rect) - # 显示向日葵奖杯的情况 - if self.show_only_one_option: # 绘制向日葵奖杯 if (self.game_info[c.LEVEL_COMPLETIONS] and self.game_info[c.LITTLEGAME_COMPLETIONS]): frame_rect = (157, 0, 157, 269) @@ -165,7 +140,7 @@ class AwardScreen(tool.State): intro_content = "您已完成冒险模式,获得此奖励!" else: intro_content = "您已完成玩玩小游戏,获得此奖励!" - sunflower_trophy_image = tool.get_image_menu(tool.GFX[c.TROPHY_SUNFLOWER], *frame_rect, scale=0.7) + sunflower_trophy_image = tool.get_image_alpha(tool.GFX[c.TROPHY_SUNFLOWER], *frame_rect, scale=0.7) sunflower_trophy_rect = sunflower_trophy_image.get_rect() sunflower_trophy_rect.x = 348 sunflower_trophy_rect.y = 108 @@ -186,7 +161,29 @@ class AwardScreen(tool.State): intro_content_rect.x = 290 intro_content_rect.y = 370 self.image.blit(intro_content_img, intro_content_rect) - + else: + ## 继续按钮 + self.next_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.next_button_image_rect = self.next_button_image.get_rect() + self.next_button_image_rect.x = 70 + ### 继续按钮上的文字 + font = pg.font.Font(c.FONT_PATH, 18) + next_text = font.render("继续", True, c.NAVYBLUE) + next_text_rect = next_text.get_rect() + next_text_rect.x = 37 + ## 主菜单按钮 + self.main_menu_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.main_menu_button_image_rect = self.main_menu_button_image.get_rect() + self.main_menu_button_image_rect.x = 620 + self.next_button_image_rect.y = self.main_menu_button_image_rect.y = 540 + ### 主菜单按钮上的文字 + main_menu_text = font.render("主菜单", True, c.NAVYBLUE) + main_menu_text_rect = main_menu_text.get_rect() + main_menu_text_rect.x = 29 + self.next_button_image.blit(next_text, next_text_rect) + self.main_menu_button_image.blit(main_menu_text, main_menu_text_rect) + self.image.blit(self.next_button_image, self.next_button_image_rect) + self.image.blit(self.main_menu_button_image, self.main_menu_button_image_rect) def startup(self, current_time, persist): self.start_time = current_time @@ -214,3 +211,46 @@ class AwardScreen(tool.State): if self.inArea(self.next_button_image_rect, *mouse_pos): self.next = c.LEVEL self.done = True + +class HelpScreen(tool.State): + def __init__(self): + tool.State.__init__(self) + + def startup(self, current_time, persist): + self.start_time = current_time + self.persist = persist + self.game_info = persist + self.setupImage() + pg.display.set_caption("pypvz: 帮助") + pg.mixer.music.stop() + + def setupImage(self): + # 主体 + frame_rect = (-100, -50, 800, 600) + self.image = tool.get_image(tool.GFX[c.HELP_SCREEN_IMAGE], *frame_rect, colorkey=(0, 255, 255)) + self.rect = self.image.get_rect() + self.rect.x = 0 + self.rect.y = 0 + + # 主菜单按钮 + frame_rect = (0, 0, 111, 26) + self.main_menu_button_image = tool.get_image_alpha(tool.GFX[c.UNIVERSAL_BUTTON], *frame_rect) + self.main_menu_button_image_rect = self.main_menu_button_image.get_rect() + self.main_menu_button_image_rect.x = 343 + self.main_menu_button_image_rect.y = 500 + ### 主菜单按钮上的文字 + font = pg.font.Font(c.FONT_PATH, 18) + main_menu_text = font.render("主菜单", True, c.NAVYBLUE) + main_menu_text_rect = main_menu_text.get_rect() + main_menu_text_rect.x = 29 + self.main_menu_button_image.blit(main_menu_text, main_menu_text_rect) + self.image.blit(self.main_menu_button_image, self.main_menu_button_image_rect) + + def update(self, surface, current_time, mouse_pos, mouse_click): + surface.fill(c.BLACK) + surface.blit(self.image, self.rect) + if mouse_pos: + # 检查主菜单点击 + if self.inArea(self.main_menu_button_image_rect, *mouse_pos): + self.next = c.MAIN_MENU + self.done = True diff --git a/source/tool.py b/source/tool.py index 04cb8b9..9f5e2a3 100755 --- a/source/tool.py +++ b/source/tool.py @@ -5,7 +5,7 @@ import pygame as pg from pygame.locals import * from . import constants as c -# an abstract class, one state of automata +# 状态机 抽象基类 class State(): def __init__(self): self.start_time = 0 @@ -17,7 +17,7 @@ class State(): # 当从其他状态进入这个状态时,需要进行的初始化操作 @abstractmethod def startup(self, current_time, persist): - # abstract method + # 前面加了@abstractmethod表示抽象基类中必须要重新定义的method(method是对象和函数的结合) pass # 当从这个状态退出时,需要进行的清除操作 def cleanup(self): @@ -26,7 +26,7 @@ class State(): # 在这个状态运行时进行的更新操作 @abstractmethod def update(self, surface, keys, current_time): - # abstract method + # 前面加了@abstractmethod表示抽象基类中必须要重新定义的method pass # 工具:范围判断函数,用于判断点击 @@ -47,7 +47,7 @@ class State(): data_to_save = json.dumps(userdata, sort_keys=True, indent=4) f.write(data_to_save) -# control this game. do event loops +# 进行游戏控制 循环 事件响应 class Control(): def __init__(self): self.screen = pg.display.get_surface() @@ -100,7 +100,7 @@ class Control(): self.state.startup(self.current_time, self.game_info) def update(self): - # 返回自 pygame_init() 调用以来的毫秒数 * 游戏速度倍率 + # 自 pygame_init() 调用以来的毫秒数 * 游戏速度倍率,即游戏时间 self.current_time = pg.time.get_ticks() * self.game_info[c.GAME_RATE] if self.state.done: @@ -116,7 +116,6 @@ class Control(): if self.state.next == c.EXIT: pg.quit() os._exit(0) - # previous, self.state_name = self.state_name, self.state.next self.state_name = self.state.next persist = self.state.cleanup() self.state = self.state_dict[self.state_name] @@ -162,7 +161,7 @@ def get_image(sheet, x, y, width, height, colorkey=c.BLACK, scale=1): int(rect.height*scale))) return image -def get_image_menu(sheet, x, y, width, height, colorkey=c.BLACK, scale=1): +def get_image_alpha(sheet, x, y, width, height, colorkey=c.BLACK, scale=1): # 保留alpha通道的图片导入 image = pg.Surface([width, height], SRCALPHA) rect = image.get_rect() @@ -198,7 +197,7 @@ def load_image_frames(directory, image_name, colorkey, accept): return frame_list # colorkeys 是设置图像中的某个颜色值为透明,这里用来消除白边 -def load_all_gfx(directory, colorkey=c.WHITE, accept=(".png", ".jpg", ".bmp", ".gif", "webp")): +def load_all_gfx(directory, colorkey=c.WHITE, accept=(".png", ".jpg", ".bmp", ".gif", ".webp")): graphics = {} for name1 in os.listdir(directory): # subfolders under the folder resources\graphics