Merge branch 'master' into opengl

This commit is contained in:
星外之神 2022-08-01 14:49:22 +08:00
commit c2992ebbbf
14 changed files with 723 additions and 664 deletions

2
.gitignore vendored
View File

@ -7,4 +7,4 @@ release/
__pycache__/ __pycache__/
*/__pycache__/ */__pycache__/
# 忽略测试文件 # 忽略测试文件
test.py test*.py

View File

@ -33,9 +33,10 @@
* 支持自定义游戏速度倍率 * 支持自定义游戏速度倍率
* 保存在游戏存档文件中,可以通过修改`game rate`值更改速度倍率 * 保存在游戏存档文件中,可以通过修改`game rate`值更改速度倍率
* 游戏完成成就显示 * 游戏完成成就显示
* 冒险模式全部完成显示银向日葵奖杯 * 任意一游戏模式全部完成显示银向日葵奖杯
* 所有模式全部完成显示金向日葵奖杯 * 所有模式全部完成显示金向日葵奖杯
* 光标移动到向日葵奖杯上是显示当前各个模式通关次数 * 光标移动到向日葵奖杯上是显示当前各个模式通关次数
* 含有游戏帮助界面 QwQ
## 环境要求 ## 环境要求
@ -312,6 +313,8 @@ pyinstaller -F pypvz.py `
![截屏19](/demo/demo19.webp) ![截屏19](/demo/demo19.webp)
![截屏20](/demo/demo20.webp) ![截屏20](/demo/demo20.webp)
![截屏21](/demo/demo21.webp) ![截屏21](/demo/demo21.webp)
![截屏22](/demo/demo22.webp)
![截屏23](/demo/demo23.webp)
## 关于日志与反馈 ## 关于日志与反馈

BIN
demo/demo22.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
demo/demo23.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -32,6 +32,7 @@ if __name__=="__main__":
c.GAME_LOSE: screen.GameLoseScreen(), c.GAME_LOSE: screen.GameLoseScreen(),
c.LEVEL: level.Level(), c.LEVEL: level.Level(),
c.AWARD_SCREEN: screen.AwardScreen(), c.AWARD_SCREEN: screen.AwardScreen(),
c.HELP_SCREEN: screen.HelpScreen(),
} }
game.setup_states(state_dict, c.MAIN_MENU) game.setup_states(state_dict, c.MAIN_MENU)
game.run() game.run()

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -9,27 +9,27 @@ class Map():
if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS:
self.width = c.GRID_POOL_X_LEN self.width = c.GRID_POOL_X_LEN
self.height = c.GRID_POOL_Y_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)] 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: elif self.background_type in c.ON_ROOF_BACKGROUNDS:
self.width = c.GRID_ROOF_X_LEN self.width = c.GRID_ROOF_X_LEN
self.height = c.GRID_ROOF_Y_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)] 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: elif self.background_type == c.BACKGROUND_SINGLE:
self.width = c.GRID_X_LEN self.width = c.GRID_X_LEN
self.height = c.GRID_Y_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)] 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: elif self.background_type == c.BACKGROUND_TRIPLE:
self.width = c.GRID_X_LEN self.width = c.GRID_X_LEN
self.height = c.GRID_Y_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)] 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: else:
self.width = c.GRID_X_LEN self.width = c.GRID_X_LEN
self.height = c.GRID_Y_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)] 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): 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 plant_name == 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 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 return True
else: else:
return False return False
if plantName == c.GRAVEBUSTER: if plant_name == c.GRAVEBUSTER:
if (c.GRAVE in self.map[map_y][map_x][c.MAP_PLANT]): if (c.GRAVE in self.map[map_y][map_x][c.MAP_PLANT]):
return True return True
else: else:
@ -64,13 +64,13 @@ class Map():
return False return False
if self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_GRASS: # 草地 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]: # 没有植物肯定可以种植 if not self.map[map_y][map_x][c.MAP_PLANT]: # 没有植物肯定可以种植
return True return True
elif (all((i in {"花盆(未实现)", c.PUMPKINHEAD}) for i in self.map[map_y][map_x][c.MAP_PLANT]) 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 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 return True
else: else:
return False return False
@ -78,26 +78,26 @@ class Map():
return False return False
elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_TILE: # 屋顶 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 "花盆(未实现)" 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]) 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])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植
if plantName in {c.SPIKEWEED}: # 不能在花盆上种植的植物 if plant_name in {c.SPIKEWEED}: # 不能在花盆上种植的植物
return False return False
else: else:
return True 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 return True
else: else:
return False return False
elif plantName == "花盆(未实现)": # 这一格本来没有花盆而且新来的植物是花盆,可以种 elif plant_name == "花盆(未实现)": # 这一格本来没有花盆而且新来的植物是花盆,可以种
return True return True
else: else:
return False return False
else: else:
return False return False
elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_WATER: # 水里 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]: # 只有无植物时才能在水里种植水生植物 if not self.map[map_y][map_x][c.MAP_PLANT]: # 只有无植物时才能在水里种植水生植物
return True return True
else: else:
@ -105,12 +105,12 @@ class Map():
else: # 非水生植物,依赖睡莲 else: # 非水生植物,依赖睡莲
if c.LILYPAD in self.map[map_y][map_x][c.MAP_PLANT]: 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]) 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])): and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])):
if plantName in {c.SPIKEWEED, c.POTATOMINE, "花盆(未实现)"}: # 不能在睡莲上种植的植物 if plant_name in {c.SPIKEWEED, c.POTATOMINE, "花盆(未实现)"}: # 不能在睡莲上种植的植物
return False return False
else: else:
return True 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 return True
else: else:
return False return False
@ -152,22 +152,22 @@ class Map():
def setMapGridType(self, map_x, map_y, plot_type): def setMapGridType(self, map_x, map_y, plot_type):
self.map[map_y][map_x][c.MAP_PLOT_TYPE] = plot_type self.map[map_y][map_x][c.MAP_PLOT_TYPE] = plot_type
def addMapPlant(self, map_x, map_y, plantName, sleep=False): def addMapPlant(self, map_x, map_y, plant_name, sleep=False):
self.map[map_y][map_x][c.MAP_PLANT].add(plantName) self.map[map_y][map_x][c.MAP_PLANT].add(plant_name)
self.map[map_y][map_x][c.MAP_SLEEP] = sleep self.map[map_y][map_x][c.MAP_SLEEP] = sleep
def removeMapPlant(self, map_x, map_y, plantName): def removeMapPlant(self, map_x, map_y, plant_name):
self.map[map_y][map_x][c.MAP_PLANT].discard(plantName) self.map[map_y][map_x][c.MAP_PLANT].discard(plant_name)
def getRandomMapIndex(self): def getRandomMapIndex(self):
map_x = random.randint(0, self.width-1) map_x = random.randint(0, self.width-1)
map_y = random.randint(0, self.height-1) map_y = random.randint(0, self.height-1)
return (map_x, map_y) return (map_x, map_y)
def checkPlantToSeed(self, x, y, plantName): def checkPlantToSeed(self, x, y, plant_name):
pos = None pos = None
map_x, map_y = self.getMapIndex(x, y) 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) pos = self.getMapGridPos(map_x, map_y)
return pos return pos
@ -212,7 +212,7 @@ LEVEL_MAP_DATA = (
# 第2关三行草皮 # 第2关三行草皮
{ {
c.BACKGROUND_TYPE: 8, c.BACKGROUND_TYPE: 8,
c.INIT_SUN_NAME: 150, c.INIT_SUN_NAME: 50,
c.SHOVEL: 1, c.SHOVEL: 1,
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO, c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
c.INCLUDED_ZOMBIES:(c.NORMAL_ZOMBIE,), c.INCLUDED_ZOMBIES:(c.NORMAL_ZOMBIE,),
@ -412,7 +412,7 @@ LITTLE_GAME_MAP_DATA = (
c.SPIKEWEED: 100, c.SPIKEWEED: 100,
c.SQUASH: 100, c.SQUASH: 100,
c.JALAPENO: 50, c.JALAPENO: 50,
c.THREEPEASHOOTER: 400,} c.THREEPEASHOOTER: 300,}
}, },
) )

View File

@ -37,7 +37,9 @@ class Car(pg.sprite.Sprite):
# 豌豆及孢子类普通子弹 # 豌豆及孢子类普通子弹
class Bullet(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) pg.sprite.Sprite.__init__(self)
self.name = name self.name = name
@ -60,7 +62,7 @@ class Bullet(pg.sprite.Sprite):
self.current_time = 0 self.current_time = 0
self.animate_timer = 0 self.animate_timer = 0
self.animate_interval = 70 self.animate_interval = 70
self.passedTorchWood = passedTorchWood # 记录最近通过的火炬树横坐标如果没有缺省为None self.passed_torchwood_x = passed_torchwood_x # 记录最近通过的火炬树横坐标如果没有缺省为None
def loadFrames(self, frames, name): def loadFrames(self, frames, name):
frame_list = tool.GFX[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: if self.y_vel * (self.dest_y - self.rect.y) < 0:
self.rect.y = self.dest_y self.rect.y = self.dest_y
self.rect.x += self.x_vel self.rect.x += self.x_vel
if self.rect.x >= c.SCREEN_WIDTH + 60: if self.rect.x >= c.SCREEN_WIDTH + 20:
self.kill() self.kill()
elif self.state == c.EXPLODE: elif self.state == c.EXPLODE:
if (self.current_time - self.explode_timer) > 250: if (self.current_time - self.explode_timer) > 250:
@ -206,7 +208,7 @@ class StarBullet(Bullet):
else: else:
self.rect.x -= 10 self.rect.x -= 10
self.handleMapYPosition() 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)): or (self.rect.y > c.SCREEN_HEIGHT) or (self.rect.y < 0)):
self.kill() self.kill()
elif self.state == c.EXPLODE: elif self.state == c.EXPLODE:
@ -248,7 +250,7 @@ class Plant(pg.sprite.Sprite):
self.animate_interval = 70 # 帧播放间隔 self.animate_interval = 70 # 帧播放间隔
self.hit_timer = 0 self.hit_timer = 0
# 被铲子指向时间 # 被铲子指向时间
self.highlightTime = 0 self.highlight_time = 0
def loadFrames(self, frames, name, scale=1, color=c.BLACK): def loadFrames(self, frames, name, scale=1, color=c.BLACK):
frame_list = tool.GFX[name] frame_list = tool.GFX[name]
@ -267,7 +269,7 @@ class Plant(pg.sprite.Sprite):
self.loadFrames(self.frames, name, scale) self.loadFrames(self.frames, name, scale)
def changeFrames(self, frames): def changeFrames(self, frames):
"""change image frames and modify rect position""" # change image frames and modify rect position
self.frames = frames self.frames = frames
self.frame_num = len(self.frames) self.frame_num = len(self.frames)
self.frame_index = 0 self.frame_index = 0
@ -311,7 +313,7 @@ class Plant(pg.sprite.Sprite):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) 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): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False return False
if (self.state != c.SLEEP and zombie.state != c.DIE and 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 True
return False return False
@ -338,7 +340,7 @@ class Plant(pg.sprite.Sprite):
self.changeFrames(self.sleep_frames) self.changeFrames(self.sleep_frames)
def setDamage(self, damage, zombie): def setDamage(self, damage, zombie):
if not zombie.lostHead: if not zombie.losthead:
self.health -= damage self.health -= damage
self.hit_timer = self.current_time self.hit_timer = self.current_time
if ((self.name == c.HYPNOSHROOM) and if ((self.name == c.HYPNOSHROOM) and
@ -429,20 +431,20 @@ class RepeaterPea(Plant):
self.shoot_timer = 0 self.shoot_timer = 0
# 是否发射第一颗 # 是否发射第一颗
self.firstShot = False self.first_shot = False
def attacking(self): def attacking(self):
if self.shoot_timer == 0: if self.shoot_timer == 0:
self.shoot_timer = self.current_time - 700 self.shoot_timer = self.current_time - 700
elif (self.current_time - self.shoot_timer >= 1400): 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, self.bullet_group.add(Bullet(self.rect.right - 15, self.rect.y, self.rect.y,
c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None)) c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None))
self.shoot_timer = self.current_time self.shoot_timer = self.current_time
# 播放发射音效 # 播放发射音效
c.SOUND_SHOOT.play() c.SOUND_SHOOT.play()
elif self.firstShot and (self.current_time - self.shoot_timer) > 100: elif self.first_shot and (self.current_time - self.shoot_timer) > 100:
self.firstShot = False self.first_shot = False
self.bullet_group.add(Bullet(self.rect.right - 15, self.rect.y, self.rect.y, self.bullet_group.add(Bullet(self.rect.right - 15, self.rect.y, self.rect.y,
c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None)) c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None))
# 播放发射音效 # 播放发射音效
@ -580,7 +582,7 @@ class CherryBomb(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -596,7 +598,7 @@ class Chomper(Plant):
self.digest_interval = 15000 self.digest_interval = 15000
self.attack_zombie = None self.attack_zombie = None
self.zombie_group = None self.zombie_group = None
self.shouldDiggest = False self.should_diggest = False
def loadImages(self, name, scale): def loadImages(self, name, scale):
self.idle_frames = [] self.idle_frames = []
@ -624,7 +626,7 @@ class Chomper(Plant):
if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False return False
elif (self.state == c.IDLE and zombie.state != c.DIGEST and 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)): (self.rect.x + c.GRID_X_SIZE*2.7 >= zombie.rect.centerx)):
return True return True
return False return False
@ -648,12 +650,12 @@ class Chomper(Plant):
# 播放吞的音效 # 播放吞的音效
c.SOUND_BIGCHOMP.play() c.SOUND_BIGCHOMP.play()
if self.attack_zombie.alive(): if self.attack_zombie.alive():
self.shouldDiggest = True self.should_diggest = True
self.attack_zombie.kill() self.attack_zombie.kill()
if (self.frame_index + 1) == self.frame_num: if (self.frame_index + 1) == self.frame_num:
if self.shouldDiggest: if self.should_diggest:
self.setDigest() self.setDigest()
self.shouldDiggest = False self.should_diggest = False
else: else:
self.setIdle() self.setIdle()
@ -751,7 +753,7 @@ class PotatoMine(Plant):
return False return False
# 这里碰撞应当比碰撞一般更容易就设置成圆形或矩形模式不宜采用mask # 这里碰撞应当比碰撞一般更容易就设置成圆形或矩形模式不宜采用mask
elif (pg.sprite.collide_circle_ratio(0.7)(zombie, self) and 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 True
return False return False
@ -767,12 +769,12 @@ class PotatoMine(Plant):
class Squash(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) Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None)
self.orig_pos = (x, y) self.orig_pos = (x, y)
self.aim_timer = 0 self.aim_timer = 0
self.start_boom = False # 和灰烬等植物统一变量名,在这里表示倭瓜是否跳起 self.start_boom = False # 和灰烬等植物统一变量名,在这里表示倭瓜是否跳起
self.mapPlantsSet = mapPlantsSet self.map_plant_set = map_plant_set
def loadImages(self, name, scale): def loadImages(self, name, scale):
self.idle_frames = [] self.idle_frames = []
@ -816,7 +818,7 @@ class Squash(Plant):
if self.canAttack(zombie): if self.canAttack(zombie):
zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE) zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE)
self.health = 0 # 避免僵尸在原位啃食 self.health = 0 # 避免僵尸在原位啃食
self.mapPlantsSet.remove(c.SQUASH) self.map_plant_set.remove(c.SQUASH)
self.kill() self.kill()
# 播放碾压音效 # 播放碾压音效
c.SOUND_SQUASHING.play() c.SOUND_SQUASHING.play()
@ -870,7 +872,7 @@ class Spikeweed(Plant):
if self.canAttack(zombie): if self.canAttack(zombie):
# 有车的僵尸 # 有车的僵尸
if zombie.name in {c.ZOMBONI}: if zombie.name in {c.ZOMBONI}:
zombie.health = zombie.lostHeadHealth zombie.health = zombie.losthead_health
killSelf = True killSelf = True
else: else:
zombie.setDamage(20, damageType=c.ZOMBIE_COMMON_DAMAGE) zombie.setDamage(20, damageType=c.ZOMBIE_COMMON_DAMAGE)
@ -924,7 +926,7 @@ class Jalapeno(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -1091,7 +1093,7 @@ class IceShroom(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -1288,16 +1290,16 @@ class TorchWood(Plant):
def idling(self): def idling(self):
for i in self.bullet_group: for i in self.bullet_group:
if i.name == c.BULLET_PEA: 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: if abs(i.rect.centerx - self.rect.centerx) <= 20:
self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, 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() i.kill()
elif i.name == c.BULLET_PEA_ICE: 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: if abs(i.rect.centerx - self.rect.centerx) <= 20:
self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, 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() i.kill()
class StarFruit(Plant): class StarFruit(Plant):
@ -1311,8 +1313,8 @@ class StarFruit(Plant):
if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames): if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False return False
if zombie.state != c.DIE: if zombie.state != c.DIE:
zombieMapY = self.level.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom)[1] 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 == zombieMapY): # 对于同行且在杨桃后的僵尸 if (self.rect.x >= zombie.rect.x) and (self.map_y == zombie_map_y): # 对于同行且在杨桃后的僵尸
return True return True
# 斜向上理想直线方程为f(zombie.rect.x) = -0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10 # 斜向上理想直线方程为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): 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) Plant.__init__(self, x, y, c.COFFEEBEAN, c.PLANT_HEALTH, None)
self.plant_group = plant_group self.plant_group = plant_group
self.mapContent = mapContent self.map_content = map_content
self.map = map self.map = map
self.map_x = map_x self.map_x = map_x
@ -1360,7 +1362,7 @@ class CoffeeBean(Plant):
self.frame_index += 1 self.frame_index += 1
if self.frame_index >= self.frame_num: 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: for plant in self.plant_group:
if plant.can_sleep: if plant.can_sleep:
if plant.state == c.SLEEP: if plant.state == c.SLEEP:
@ -1371,7 +1373,7 @@ class CoffeeBean(Plant):
plant.changeFrames(plant.idle_frames) plant.changeFrames(plant.idle_frames)
# 播放唤醒音效 # 播放唤醒音效
c.SOUND_MUSHROOM_WAKEUP.play() 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.kill()
self.frame_index = self.frame_num - 1 self.frame_index = self.frame_num - 1
@ -1379,7 +1381,7 @@ class CoffeeBean(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -1480,7 +1482,7 @@ class TangleKlep(Plant):
self.frames = self.idle_frames self.frames = self.idle_frames
def canAttack(self, zombie): def canAttack(self, zombie):
if zombie.state != c.DIE and (not zombie.lostHead): if zombie.state != c.DIE and (not zombie.losthead):
# 这里碰撞应当比碰撞一般更容易就设置成圆形或矩形模式不宜采用mask # 这里碰撞应当比碰撞一般更容易就设置成圆形或矩形模式不宜采用mask
if pg.sprite.collide_circle_ratio(0.7)(zombie, self): if pg.sprite.collide_circle_ratio(0.7)(zombie, self):
return True return True
@ -1510,17 +1512,17 @@ class TangleKlep(Plant):
# 坑形态的毁灭菇同地刺一样不可以被啃食 # 坑形态的毁灭菇同地刺一样不可以被啃食
# 爆炸时杀死同一格的所有植物 # 爆炸时杀死同一格的所有植物
class DoomShroom(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) Plant.__init__(self, x, y, c.DOOMSHROOM, c.PLANT_HEALTH, None)
self.can_sleep = True self.can_sleep = True
self.mapPlantSet = mapPlantsSet self.map_plant_set = map_plant_set
self.bomb_timer = 0 self.bomb_timer = 0
self.explode_y_range = explode_y_range self.explode_y_range = explode_y_range
self.explode_x_range = 250 self.explode_x_range = 250
self.start_boom = False self.start_boom = False
self.boomed = False self.boomed = False
self.originalX = x self.original_x = x
self.originalY = y self.original_y = y
def loadImages(self, name, scale): def loadImages(self, name, scale):
self.idle_frames = [] self.idle_frames = []
@ -1556,7 +1558,7 @@ class DoomShroom(Plant):
if self.frame_index >= self.frame_num: if self.frame_index >= self.frame_num:
self.health = 0 self.health = 0
self.frame_index = self.frame_num - 1 self.frame_index = self.frame_num - 1
self.mapPlantSet.add(c.HOLE) self.map_plant_set.add(c.HOLE)
# 睡觉状态 # 睡觉状态
elif self.state == c.SLEEP: elif self.state == c.SLEEP:
if (self.current_time - self.animate_timer) > self.animate_interval: 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.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -1668,8 +1670,8 @@ class GraveBuster(Plant):
self.frame_index = self.frame_num - 1 self.frame_index = self.frame_num - 1
for item in self.plant_group: for item in self.plant_group:
if item.name == c.GRAVE: if item.name == c.GRAVE:
itemMapX, _ = self.map.getMapIndex(item.rect.centerx, item.rect.bottom) item_map_x, _ = self.map.getMapIndex(item.rect.centerx, item.rect.bottom)
if itemMapX == self.map_x: if item_map_x == self.map_x:
item.health = 0 item.health = 0
self.health = 0 self.health = 0
self.animate_timer = self.current_time self.animate_timer = self.current_time
@ -1677,7 +1679,7 @@ class GraveBuster(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)
@ -1689,7 +1691,7 @@ class FumeShroom(Plant):
Plant.__init__(self, x, y, c.FUMESHROOM, c.PLANT_HEALTH, bullet_group) Plant.__init__(self, x, y, c.FUMESHROOM, c.PLANT_HEALTH, bullet_group)
self.can_sleep = True self.can_sleep = True
self.shoot_timer = 0 self.shoot_timer = 0
self.showAttackFrames = True self.show_attack_frames = True
self.zombie_group = zombie_group self.zombie_group = zombie_group
def loadImages(self, name, scale): def loadImages(self, name, scale):
@ -1726,18 +1728,18 @@ class FumeShroom(Plant):
if self.shoot_timer == 0: if self.shoot_timer == 0:
self.shoot_timer = self.current_time - 700 self.shoot_timer = self.current_time - 700
elif self.current_time - self.shoot_timer >= 1100: elif self.current_time - self.shoot_timer >= 1100:
if self.showAttackFrames: if self.show_attack_frames:
self.showAttackFrames = False self.show_attack_frames = False
self.changeFrames(self.attack_frames) self.changeFrames(self.attack_frames)
if self.current_time - self.shoot_timer >= 1400: if self.current_time - self.shoot_timer >= 1400:
self.bullet_group.add(Fume(self.rect.right - 35, self.rect.y)) self.bullet_group.add(Fume(self.rect.right - 35, self.rect.y))
# 烟雾只是个动画,实际伤害由本身完成 # 烟雾只是个动画,实际伤害由本身完成
for targetZombie in self.zombie_group: for target_zombie in self.zombie_group:
if self.canAttack(targetZombie): if self.canAttack(target_zombie):
targetZombie.setDamage(c.BULLET_DAMAGE_NORMAL, damageType=c.ZOMBIE_RANGE_DAMAGE) target_zombie.setDamage(c.BULLET_DAMAGE_NORMAL, damageType=c.ZOMBIE_RANGE_DAMAGE)
self.shoot_timer = self.current_time self.shoot_timer = self.current_time
self.showAttackFrames = True self.show_attack_frames = True
# 播放发射音效 # 播放发射音效
c.SOUND_FUME.play() c.SOUND_FUME.play()
@ -1754,7 +1756,7 @@ class FumeShroom(Plant):
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image) 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) self.image.set_alpha(150)
elif ((self.current_time - self.hit_timer) < 200): elif ((self.current_time - self.hit_timer) < 200):
self.image.set_alpha(192) self.image.set_alpha(192)

View File

@ -5,7 +5,10 @@ from .. import constants as c
class Zombie(pg.sprite.Sprite): 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) pg.sprite.Sprite.__init__(self)
self.name = name self.name = name
@ -15,26 +18,26 @@ class Zombie(pg.sprite.Sprite):
self.frame_num = len(self.frames) self.frame_num = len(self.frames)
self.image = self.frames[self.frame_index] self.image = self.frames[self.frame_index]
self.mask = pg.mask.from_surface(self.image)
self.rect = self.image.get_rect() self.rect = self.image.get_rect()
self.mask = pg.mask.from_surface(self.image)
self.rect.x = x self.rect.x = x
self.rect.bottom = y self.rect.bottom = y
# 大蒜换行移动像素值,< 0时向上= 0时不变> 0时向上 # 大蒜换行移动像素值,< 0时向上= 0时不变> 0时向上
self.targetYChange = 0 self.target_y_change = 0
self.originalY = y self.original_y = y
self.toChangeGroup = False self.to_change_group = False
self.helmetHealth = helmetHealth self.helmet_health = helmet_health
self.helmetType2Health = helmetType2Health self.helmet_type2_health = helmet_type2_health
self.health = bodyHealth + lostHeadHealth self.health = body_health + losthead_health
self.lostHeadHealth = lostHeadHealth self.losthead_health = losthead_health
self.damage = damage self.damage = damage
self.dead = False self.dead = False
self.lostHead = False self.losthead = False
self.canSwim = canSwim self.can_swim = can_swim
self.swimming = False self.swimming = False
self.helmet = (self.helmetHealth > 0) self.helmet = (self.helmet_health > 0)
self.helmetType2 = (self.helmetType2Health > 0) self.helmet_type2 = (self.helmet_type2_health > 0)
self.head_group = head_group self.head_group = head_group
self.walk_timer = 0 self.walk_timer = 0
@ -44,7 +47,7 @@ class Zombie(pg.sprite.Sprite):
self.animate_interval = 150 self.animate_interval = 150
self.walk_animate_interval = 180 self.walk_animate_interval = 180
self.attack_animate_interval = 100 self.attack_animate_interval = 100
self.lostHead_animate_interval = 180 self.losthead_animate_interval = 180
self.die_animate_interval = 50 self.die_animate_interval = 50
self.boomDie_animate_interval = 100 self.boomDie_animate_interval = 100
self.ice_slow_ratio = 1 self.ice_slow_ratio = 1
@ -88,8 +91,8 @@ class Zombie(pg.sprite.Sprite):
if self.health <= 0: if self.health <= 0:
self.setDie() self.setDie()
return True return True
elif self.health <= self.lostHeadHealth: elif self.health <= self.losthead_health:
if not self.lostHead: if not self.losthead:
self.changeFrames(framesKind) self.changeFrames(framesKind)
self.setLostHead() self.setLostHead()
return True return True
@ -105,7 +108,7 @@ class Zombie(pg.sprite.Sprite):
return return
# 能游泳的僵尸 # 能游泳的僵尸
if self.canSwim: if self.can_swim:
# 在水池范围内 # 在水池范围内
# 在右侧岸左 # 在右侧岸左
if self.rect.right <= c.MAP_POOL_FRONT_X: if self.rect.right <= c.MAP_POOL_FRONT_X:
@ -119,25 +122,25 @@ class Zombie(pg.sprite.Sprite):
c.SOUND_ZOMBIE_ENTERING_WATER.play() c.SOUND_ZOMBIE_ENTERING_WATER.play()
# 同样没有兼容双防具 # 同样没有兼容双防具
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.helmet = False self.helmet = False
else: else:
self.changeFrames(self.helmet_swim_frames) self.changeFrames(self.helmet_swim_frames)
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.helmetType2 = False self.helmet_type2 = False
else: else:
self.changeFrames(self.helmet_swim_frames) self.changeFrames(self.helmet_swim_frames)
# 已经进入游泳状态 # 已经进入游泳状态
else: else:
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.changeFrames(self.swim_frames) self.changeFrames(self.swim_frames)
self.helmet = False self.helmet = False
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.changeFrames(self.swim_frames) self.changeFrames(self.swim_frames)
self.helmetType2 = False self.helmet_type2 = False
# 水生僵尸已经接近家门口并且上岸 # 水生僵尸已经接近家门口并且上岸
else: else:
if self.swimming: if self.swimming:
@ -145,55 +148,55 @@ class Zombie(pg.sprite.Sprite):
self.swimming = False self.swimming = False
# 同样没有兼容双防具 # 同样没有兼容双防具
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.helmet = False self.helmet = False
else: else:
self.changeFrames(self.helmet_walk_frames) self.changeFrames(self.helmet_walk_frames)
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.helmetType2 = False self.helmet_type2 = False
else: else:
self.changeFrames(self.helmet_walk_frames) self.changeFrames(self.helmet_walk_frames)
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.helmet = False self.helmet = False
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.helmetType2 = False self.helmet_type2 = False
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
elif self.is_hypno and self.rect.right > c.MAP_POOL_FRONT_X + 55: # 常数拟合暂时缺乏检验 elif self.is_hypno and self.rect.right > c.MAP_POOL_FRONT_X + 55: # 常数拟合暂时缺乏检验
if self.swimming: if self.swimming:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
self.helmet = False self.helmet = False
elif self.swimming: # 游泳状态需要改为步行 elif self.swimming: # 游泳状态需要改为步行
self.changeFrames(self.helmet_walk_frames) self.changeFrames(self.helmet_walk_frames)
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
self.helmetType2 = False self.helmet_type2 = False
elif self.swimming: # 游泳状态需要改为步行 elif self.swimming: # 游泳状态需要改为步行
self.changeFrames(self.helmet_walk_frames) self.changeFrames(self.helmet_walk_frames)
self.swimming = False self.swimming = False
# 尚未进入水池 # 尚未进入水池
else: else:
if self.helmetHealth <= 0 and self.helmet: if self.helmet_health <= 0 and self.helmet:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
self.helmet = False 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.changeFrames(self.walk_frames)
self.helmetType2 = False self.helmet_type2 = False
# 不能游泳的一般僵尸 # 不能游泳的一般僵尸
else: else:
if self.helmetHealth <= 0 and self.helmet: if self.helmet_health <= 0 and self.helmet:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
self.helmet = False 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.changeFrames(self.walk_frames)
self.helmetType2 = False self.helmet_type2 = False
if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()): if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()):
self.handleGarlicYChange() self.handleGarlicYChange()
@ -204,48 +207,48 @@ class Zombie(pg.sprite.Sprite):
self.rect.x -= 1 self.rect.x -= 1
def handleGarlicYChange(self): def handleGarlicYChange(self):
if self.targetYChange < 0: if self.target_y_change < 0:
if self.rect.bottom > self.originalY + self.targetYChange: # 注意这里加的是负数 if self.rect.bottom > self.original_y + self.target_y_change: # 注意这里加的是负数
self.rect.bottom -= 3 self.rect.bottom -= 3
# 过半时换行 # 过半时换行
if ((self.toChangeGroup) and if ((self.to_change_group) and
(self.rect.bottom >= self.originalY + 0.5*self.targetYChange)): (self.rect.bottom >= self.original_y + 0.5*self.target_y_change)):
self.level.zombie_groups[self.mapY].remove(self) self.level.zombie_groups[self.map_y].remove(self)
self.level.zombie_groups[self.targetMapY].add(self) self.level.zombie_groups[self.target_map_y].add(self)
self.toChangeGroup = False self.to_change_group = False
else: else:
self.rect.bottom = self.originalY + self.targetYChange self.rect.bottom = self.original_y + self.target_y_change
self.originalY = self.rect.bottom self.original_y = self.rect.bottom
self.targetYChange = 0 self.target_y_change = 0
elif self.targetYChange > 0: elif self.target_y_change > 0:
if self.rect.bottom < self.originalY + self.targetYChange: # 注意这里加的是负数 if self.rect.bottom < self.original_y + self.target_y_change: # 注意这里加的是负数
self.rect.bottom += 3 self.rect.bottom += 3
# 过半时换行 # 过半时换行
if ((self.toChangeGroup) and if ((self.to_change_group) and
(self.rect.bottom <= self.originalY + 0.5*self.targetYChange)): (self.rect.bottom <= self.original_y + 0.5*self.target_y_change)):
self.level.zombie_groups[self.mapY].remove(self) self.level.zombie_groups[self.map_y].remove(self)
self.level.zombie_groups[self.targetMapY].add(self) self.level.zombie_groups[self.target_map_y].add(self)
self.toChangeGroup = False self.to_change_group = False
else: else:
self.rect.bottom = self.originalY + self.targetYChange self.rect.bottom = self.original_y + self.target_y_change
self.originalY = self.rect.bottom self.original_y = self.rect.bottom
self.targetYChange = 0 self.target_y_change = 0
def attacking(self): def attacking(self):
if self.checkToDie(self.losthead_attack_frames): if self.checkToDie(self.losthead_attack_frames):
return return
if self.helmetHealth <= 0 and self.helmet: if self.helmet_health <= 0 and self.helmet:
self.changeFrames(self.attack_frames) self.changeFrames(self.attack_frames)
self.helmet = False 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.changeFrames(self.attack_frames)
self.helmetType2 = False self.helmet_type2 = False
if self.name == c.NEWSPAPER_ZOMBIE: if self.name == c.NEWSPAPER_ZOMBIE:
self.speed = 2.65 self.speed = 2.65
self.walk_animate_interval = 300 self.walk_animate_interval = 300
if (((self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getAttackTimeRatio())) 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.health > 0:
if self.prey_is_plant: if self.prey_is_plant:
self.prey.setDamage(self.damage, self) self.prey.setDamage(self.damage, self)
@ -281,8 +284,8 @@ class Zombie(pg.sprite.Sprite):
def setLostHead(self): def setLostHead(self):
self.losthead_timer = self.current_time self.losthead_timer = self.current_time
self.lostHead = True self.losthead = True
self.animate_interval = self.lostHead_animate_interval self.animate_interval = self.losthead_animate_interval
if self.head_group is not None: if self.head_group is not None:
self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom)) 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 effect == c.BULLET_EFFECT_ICE:
if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速 if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速
if not self.helmetType2: if not self.helmet_type2:
self.setIceSlow() self.setIceSlow()
else: else:
self.setIceSlow() self.setIceSlow()
# 解冻 # 解冻
elif effect == c.BULLET_EFFECT_UNICE: elif effect == c.BULLET_EFFECT_UNICE:
if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速 if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速
if not self.helmetType2: if not self.helmet_type2:
self.ice_slow_ratio = 1 self.ice_slow_ratio = 1
else: else:
self.ice_slow_ratio = 1 self.ice_slow_ratio = 1
if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 不穿透二类防具的攻击 if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 不穿透二类防具的攻击
# 从第二类防具开始逐级传递 # 从第二类防具开始逐级传递
if self.helmetType2: if self.helmet_type2:
self.helmetType2Health -= damage self.helmet_type2_health -= damage
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
if self.helmet: if self.helmet:
self.helmetHealth += self.helmetType2Health # 注意self.helmetType2Health已经带有正负 self.helmet_health += self.helmet_type2_health # 注意self.helmet_type2_health已经带有正负
self.helmetType2Health = 0 # 注意合并后清零 self.helmet_type2_health = 0 # 注意合并后清零
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: else:
self.health += self.helmetType2Health self.health += self.helmet_type2_health
self.helmetType2Health = 0 self.helmet_type2_health = 0
elif self.helmet: # 不存在二类防具,但是存在一类防具 elif self.helmet: # 不存在二类防具,但是存在一类防具
self.helmetHealth -= damage self.helmet_health -= damage
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: # 没有防具 else: # 没有防具
self.health -= damage self.health -= damage
elif damageType == c.ZOMBIE_COMMON_DAMAGE: # 无视二类防具,将攻击一类防具与本体视为整体的攻击 elif damageType == c.ZOMBIE_COMMON_DAMAGE: # 无视二类防具,将攻击一类防具与本体视为整体的攻击
if self.helmet: # 存在一类防具 if self.helmet: # 存在一类防具
self.helmetHealth -= damage self.helmet_health -= damage
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: # 没有一类防具 else: # 没有一类防具
self.health -= damage self.health -= damage
elif damageType == c.ZOMBIE_RANGE_DAMAGE: elif damageType == c.ZOMBIE_RANGE_DAMAGE:
# 从第二类防具开始逐级传递 # 从第二类防具开始逐级传递
if self.helmetType2: if self.helmet_type2:
self.helmetType2Health -= damage self.helmet_type2_health -= damage
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
if self.helmet: if self.helmet:
self.helmetHealth -= damage # 注意范围伤害中这里还有一个攻击 self.helmet_health -= damage # 注意范围伤害中这里还有一个攻击
self.helmetHealth += self.helmetType2Health # 注意self.helmetType2Health已经带有正负 self.helmet_health += self.helmet_type2_health # 注意self.helmet_type2_health已经带有正负
self.helmetType2Health = 0 # 注意合并后清零 self.helmet_type2_health = 0 # 注意合并后清零
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: else:
self.health -= damage # 注意范围伤害中这里还有一个攻击 self.health -= damage # 注意范围伤害中这里还有一个攻击
self.health += self.helmetType2Health self.health += self.helmet_type2_health
self.helmetType2Health = 0 self.helmet_type2_health = 0
else: else:
if self.helmet: if self.helmet:
self.helmetHealth -= damage self.helmet_health -= damage
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: else:
self.health -= damage self.health -= damage
elif self.helmet: # 不存在二类防具,但是存在一类防具 elif self.helmet: # 不存在二类防具,但是存在一类防具
self.helmetHealth -= damage self.helmet_health -= damage
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.health += self.helmetHealth self.health += self.helmet_health
self.helmetHealth = 0 # 注意合并后清零 self.helmet_health = 0 # 注意合并后清零
else: # 没有防具 else: # 没有防具
self.health -= damage self.health -= damage
elif damageType == c.ZOMBIE_ASH_DAMAGE: elif damageType == c.ZOMBIE_ASH_DAMAGE:
self.health -= damage # 无视任何防具 self.health -= damage # 无视任何防具
elif damageType == c.ZOMBIE_WALLNUT_BOWLING_DANMAGE: elif damageType == c.ZOMBIE_WALLNUT_BOWLING_DANMAGE:
# 逻辑:对防具的多余伤害不传递 # 逻辑:对防具的多余伤害不传递
if self.helmetType2: if self.helmet_type2:
# 对二类防具伤害较一般情况低拟合铁门需要砸3次的设定 # 对二类防具伤害较一般情况低拟合铁门需要砸3次的设定
self.helmetType2Health -= int(damage * 0.8) self.helmet_type2_health -= int(damage * 0.8)
elif self.helmet: # 不存在二类防具,但是存在一类防具 elif self.helmet: # 不存在二类防具,但是存在一类防具
self.helmetHealth -= damage self.helmet_health -= damage
else: # 没有防具 else: # 没有防具
self.health -= damage self.health -= damage
else: else:
@ -441,28 +444,28 @@ class Zombie(pg.sprite.Sprite):
self.state = c.WALK self.state = c.WALK
self.animate_interval = self.walk_animate_interval 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) self.changeFrames(self.helmet_walk_frames)
elif self.lostHead: elif self.losthead:
self.changeFrames(self.losthead_walk_frames) self.changeFrames(self.losthead_walk_frames)
else: else:
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
if self.canSwim: if self.can_swim:
if self.rect.right <= c.MAP_POOL_FRONT_X: if self.rect.right <= c.MAP_POOL_FRONT_X:
self.swimming = True self.swimming = True
self.changeFrames(self.swim_frames) self.changeFrames(self.swim_frames)
# 同样没有兼容双防具 # 同样没有兼容双防具
if self.helmet: if self.helmet:
if self.helmetHealth <= 0: if self.helmet_health <= 0:
self.changeFrames(self.swim_frames) self.changeFrames(self.swim_frames)
self.helmet = False self.helmet = False
else: else:
self.changeFrames(self.helmet_swim_frames) self.changeFrames(self.helmet_swim_frames)
if self.helmetType2: if self.helmet_type2:
if self.helmetType2Health <= 0: if self.helmet_type2_health <= 0:
self.changeFrames(self.swim_frames) self.changeFrames(self.swim_frames)
self.helmetType2 = False self.helmet_type2 = False
else: else:
self.changeFrames(self.helmet_swim_frames) self.changeFrames(self.helmet_swim_frames)
@ -473,9 +476,9 @@ class Zombie(pg.sprite.Sprite):
self.attack_timer = self.current_time self.attack_timer = self.current_time
self.animate_interval = self.attack_animate_interval 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) self.changeFrames(self.helmet_attack_frames)
elif self.lostHead: elif self.losthead:
self.changeFrames(self.losthead_attack_frames) self.changeFrames(self.losthead_attack_frames)
else: else:
self.changeFrames(self.attack_frames) self.changeFrames(self.attack_frames)
@ -558,7 +561,7 @@ class NormalZombie(Zombie):
# 路障僵尸 # 路障僵尸
class ConeHeadZombie(Zombie): class ConeHeadZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -594,7 +597,7 @@ class ConeHeadZombie(Zombie):
class BucketHeadZombie(Zombie): class BucketHeadZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -661,8 +664,8 @@ class FlagZombie(Zombie):
class NewspaperZombie(Zombie): class NewspaperZombie(Zombie):
def __init__(self, x, y, head_group): def __init__(self, x, y, head_group):
Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, head_group, helmetType2Health=c.NEWSPAPER_HEALTH) Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, head_group, helmet_type2_health=c.NEWSPAPER_HEALTH)
self.speedUp = False self.speed_up = False
def loadImages(self): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -707,9 +710,9 @@ class NewspaperZombie(Zombie):
if self.checkToDie(self.losthead_walk_frames): if self.checkToDie(self.losthead_walk_frames):
return return
if self.helmetType2Health <= 0 and self.helmetType2: if self.helmet_type2_health <= 0 and self.helmet_type2:
self.changeFrames(self.lostnewspaper_frames) self.changeFrames(self.lostnewspaper_frames)
self.helmetType2 = False self.helmet_type2 = False
# 触发报纸撕裂音效 # 触发报纸撕裂音效
c.SOUND_NEWSPAPER_RIP.play() c.SOUND_NEWSPAPER_RIP.play()
if ((self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio())): 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: if self.state == c.DIE:
self.kill() self.kill()
return 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.changeFrames(self.walk_frames)
self.speedUp = True self.speed_up = True
self.speed = 2.65 self.speed = 2.65
self.walk_animate_interval = 300 self.walk_animate_interval = 300
# 触发报纸僵尸暴走音效 # 触发报纸僵尸暴走音效
@ -755,12 +758,12 @@ class NewspaperZombie(Zombie):
class FootballZombie(Zombie): class FootballZombie(Zombie):
def __init__(self, x, y, head_group): 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.speed = 1.88
self.animate_interval = 50 self.animate_interval = 50
self.walk_animate_interval = 50 self.walk_animate_interval = 50
self.attack_animate_interval = 60 self.attack_animate_interval = 60
self.lostHead_animate_interval = 180 self.losthead_animate_interval = 180
self.die_animate_interval = 150 self.die_animate_interval = 150
def loadImages(self): def loadImages(self):
@ -796,7 +799,7 @@ class FootballZombie(Zombie):
class DuckyTubeZombie(Zombie): class DuckyTubeZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.walk_frames = [] self.walk_frames = []
@ -827,7 +830,7 @@ class DuckyTubeZombie(Zombie):
class ConeHeadDuckyTubeZombie(Zombie): class ConeHeadDuckyTubeZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -865,7 +868,7 @@ class ConeHeadDuckyTubeZombie(Zombie):
class BucketHeadDuckyTubeZombie(Zombie): class BucketHeadDuckyTubeZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -903,7 +906,7 @@ class BucketHeadDuckyTubeZombie(Zombie):
class ScreenDoorZombie(Zombie): class ScreenDoorZombie(Zombie):
def __init__(self, x, y, head_group): 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): def loadImages(self):
self.helmet_walk_frames = [] self.helmet_walk_frames = []
@ -939,7 +942,7 @@ class ScreenDoorZombie(Zombie):
class PoleVaultingZombie(Zombie): class PoleVaultingZombie(Zombie):
def __init__(self, x, y, head_group): 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.speed = 1.88
self.jumped = False self.jumped = False
self.jumping = False self.jumping = False
@ -975,12 +978,12 @@ class PoleVaultingZombie(Zombie):
self.frames = self.walk_before_jump_frames self.frames = self.walk_before_jump_frames
def setJump(self, successfullyJumped, jumpX): def setJump(self, successfullyJumped, jump_x):
if not self.jumping: if not self.jumping:
self.jumping = True self.jumping = True
self.changeFrames(self.jump_frames) self.changeFrames(self.jump_frames)
self.successfullyJumped = successfullyJumped self.successfullyJumped = successfullyJumped
self.jumpX = jumpX self.jump_x = jump_x
# 播放跳跃音效 # 播放跳跃音效
c.SOUND_POLEVAULT_JUMP.play() c.SOUND_POLEVAULT_JUMP.play()
@ -1005,7 +1008,7 @@ class PoleVaultingZombie(Zombie):
if self.jumping and (not self.jumped): if self.jumping and (not self.jumped):
self.changeFrames(self.walk_frames) self.changeFrames(self.walk_frames)
if self.successfullyJumped: if self.successfullyJumped:
self.rect.centerx = self.jumpX self.rect.centerx = self.jump_x
self.jumped = True self.jumped = True
self.speed = 1.04 self.speed = 1.04
self.animate_timer = self.current_time self.animate_timer = self.current_time
@ -1043,7 +1046,7 @@ class PoleVaultingZombie(Zombie):
# 注意:冰车僵尸移动变速 # 注意:冰车僵尸移动变速
class Zomboni(Zombie): class Zomboni(Zombie):
def __init__(self, x, y, plant_group, map, IceFrozenPlot): 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.plant_group = plant_group
self.map = map self.map = map
self.IceFrozenPlot = IceFrozenPlot self.IceFrozenPlot = IceFrozenPlot
@ -1095,7 +1098,7 @@ class Zomboni(Zombie):
elif self.health <= c.ZOMBONI_DAMAGED1_HEALTH: elif self.health <= c.ZOMBONI_DAMAGED1_HEALTH:
self.changeFrames(self.walk_damaged1_frames) 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 self.walk_timer = self.current_time
if self.is_hypno: if self.is_hypno:
self.rect.x += 1 self.rect.x += 1
@ -1111,14 +1114,14 @@ class Zomboni(Zombie):
plant.health -= 8000 plant.health -= 8000
# 造冰 # 造冰
mapX, mapY = self.map.getMapIndex(self.rect.right - 40, self.rect.bottom) map_x, map_y = self.map.getMapIndex(self.rect.right - 40, self.rect.bottom)
if 0 <= mapX < c.GRID_X_LEN: if 0 <= map_x < c.GRID_X_LEN:
if c.ICEFROZENPLOT not in self.map.map[mapY][mapX]: if c.ICEFROZENPLOT not in self.map.map[map_y][map_x]:
x, y = self.map.getMapGridPos(mapX, mapY) x, y = self.map.getMapGridPos(map_x, map_y)
self.plant_group.add(self.IceFrozenPlot(x, 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): def setDie(self):
self.state = c.DIE self.state = c.DIE
@ -1130,7 +1133,7 @@ class Zomboni(Zombie):
class SnorkelZombie(Zombie): class SnorkelZombie(Zombie):
def __init__(self, x, y, head_group): 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.speed = 1.175
self.walk_animate_interval = 60 self.walk_animate_interval = 60
self.canSetAttack = True self.canSetAttack = True
@ -1250,7 +1253,7 @@ class SnorkelZombie(Zombie):
self.prey_is_plant = is_plant self.prey_is_plant = is_plant
self.animate_interval = self.attack_animate_interval self.animate_interval = self.attack_animate_interval
if self.lostHead: if self.losthead:
self.changeFrames(self.losthead_attack_frames) self.changeFrames(self.losthead_attack_frames)
elif self.canSetAttack: elif self.canSetAttack:
self.changeFrames(self.float_frames) self.changeFrames(self.float_frames)

View File

@ -71,6 +71,7 @@ PARCHMENT_YELLOW = (207, 146, 83)
# 退出游戏按钮 # 退出游戏按钮
EXIT = "exit" EXIT = "exit"
HELP = "help"
# 游戏界面可选的菜单 # 游戏界面可选的菜单
LITTLE_MENU = "littleMenu" LITTLE_MENU = "littleMenu"
BIG_MENU = "bigMenu" BIG_MENU = "bigMenu"
@ -110,6 +111,7 @@ GAME_LOSE = "game lose"
GAME_VICTORY = "game victory" GAME_VICTORY = "game victory"
LEVEL = "level" LEVEL = "level"
AWARD_SCREEN = "award screen" AWARD_SCREEN = "award screen"
HELP_SCREEN = "help screen"
# 界面图片文件名 # 界面图片文件名
MAIN_MENU_IMAGE = "MainMenu" MAIN_MENU_IMAGE = "MainMenu"
@ -117,6 +119,7 @@ OPTION_ADVENTURE = "Adventure"
GAME_LOSE_IMAGE = "GameLose" GAME_LOSE_IMAGE = "GameLose"
GAME_VICTORY_IMAGE = "GameVictory" GAME_VICTORY_IMAGE = "GameVictory"
AWARD_SCREEN_IMAGE = "AwardScreen" AWARD_SCREEN_IMAGE = "AwardScreen"
HELP_SCREEN_IMAGE = "HelpScreen"
# 地图相关内容 # 地图相关内容
BACKGROUND_NAME = "Background" BACKGROUND_NAME = "Background"
@ -166,8 +169,8 @@ GRAVES_GRADE_INFO = (0, 4, 7, 11)
# 僵尸生成方式 # 僵尸生成方式
SPAWN_ZOMBIES = "spawn_zombies" SPAWN_ZOMBIES = "spawn_zombies"
SPAWN_ZOMBIES_AUTO = "auto" SPAWN_ZOMBIES_AUTO = 1
SPAWN_ZOMBIES_LIST = "list" SPAWN_ZOMBIES_LIST = 0
INCLUDED_ZOMBIES = "included_zombies" INCLUDED_ZOMBIES = "included_zombies"
NUM_FLAGS = "num_flags" NUM_FLAGS = "num_flags"
INEVITABLE_ZOMBIE_DICT = "inevitable_zombie_list" INEVITABLE_ZOMBIE_DICT = "inevitable_zombie_list"
@ -302,7 +305,7 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
50000), 50000),
(DOOMSHROOM := "DoomShroom", (DOOMSHROOM := "DoomShroom",
CARD_DOOMSHROOM := "card_doomshroom", CARD_DOOMSHROOM := "card_doomshroom",
75, 125,
50000), 50000),
(LILYPAD := "LilyPad", (LILYPAD := "LilyPad",
CARD_LILYPAD := "card_lilypad", CARD_LILYPAD := "card_lilypad",
@ -509,8 +512,7 @@ SNORKELZOMBIE = "SnorkelZombie"
BOOMDIE = "BoomDie" BOOMDIE = "BoomDie"
# 对僵尸的攻击类型设置 # 对僵尸的攻击类型设置
ZOMBIE_DEAFULT_DAMAGE = "helmet2First" ZOMBIE_DEAFULT_DAMAGE = ZOMBIE_HELMET_2_FIRST = "helmet2First" # 优先攻击二类防具
ZOMBIE_HELMET_2_FIRST = "helmet2First" # 优先攻击二类防具
ZOMBIE_COMMON_DAMAGE = "commonDamage" # 优先攻击僵尸与一类防具的整体 ZOMBIE_COMMON_DAMAGE = "commonDamage" # 优先攻击僵尸与一类防具的整体
ZOMBIE_RANGE_DAMAGE = "rangeDamage" # 范围攻击,同时伤害二类防具与(僵尸与一类防具的整体) ZOMBIE_RANGE_DAMAGE = "rangeDamage" # 范围攻击,同时伤害二类防具与(僵尸与一类防具的整体)
ZOMBIE_ASH_DAMAGE = "ashDamage" # 灰烬植物攻击,直接伤害本体 ZOMBIE_ASH_DAMAGE = "ashDamage" # 灰烬植物攻击,直接伤害本体

File diff suppressed because it is too large Load Diff

View File

@ -37,23 +37,27 @@ class Menu(tool.State):
def setupOptions(self): def setupOptions(self):
# 冒险模式 # 冒险模式
self.adventure_frames = []
frame_names = (f"{c.OPTION_ADVENTURE}_0", f"{c.OPTION_ADVENTURE}_1")
frame_rect = (0, 0, 330, 144) frame_rect = (0, 0, 330, 144)
for name in frame_names: # 写成列表生成器方便IDE识别与自动补全
self.adventure_frames.append(tool.get_image_menu(tool.GFX[name], *frame_rect, c.BLACK, 1)) 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_image = self.adventure_frames[0]
self.adventure_rect = self.adventure_image.get_rect() self.adventure_rect = self.adventure_image.get_rect()
self.adventure_rect.x = 400 self.adventure_rect.x = 400
self.adventure_rect.y = 60 self.adventure_rect.y = 60
self.adventure_highlight_time = 0 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) exit_frame_rect = (0, 0, 47, 27)
for name in exit_frame_names: 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_frames.append(tool.get_image_menu(tool.GFX[name], *exit_frame_rect, c.BLACK, 1.1))
self.exit_image = self.exit_frames[0] self.exit_image = self.exit_frames[0]
self.exit_rect = self.exit_image.get_rect() self.exit_rect = self.exit_image.get_rect()
self.exit_rect.x = 730 self.exit_rect.x = 730
@ -61,29 +65,24 @@ class Menu(tool.State):
self.exit_highlight_time = 0 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) option_button_frame_rect = (0, 0, 81, 31)
for name in option_button_frame_names: 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_frames.append(tool.get_image_menu(tool.GFX[name], *option_button_frame_rect, c.BLACK))
self.option_button_image = self.option_button_frames[0] self.option_button_image = self.option_button_frames[0]
self.option_button_rect = self.option_button_image.get_rect() self.option_button_rect = self.option_button_image.get_rect()
self.option_button_rect.x = 560 self.option_button_rect.x = 560
self.option_button_rect.y = 490 self.option_button_rect.y = 490
self.option_button_hightlight_time = 0 self.option_button_highlight_time = 0
# 小游戏 # 帮助菜单
self.littleGame_frames = [] help_frame_rect = (0, 0, 48, 22)
littleGame_frame_names = (c.LITTLEGAME_BUTTON + "_0", c.LITTLEGAME_BUTTON + "_1") self.help_frames = [tool.get_image_alpha(tool.GFX[f"{c.HELP}_{i}"], *help_frame_rect) for i in range(2)]
littleGame_frame_rect = (0, 7, 317, 135) self.help_image = self.help_frames[0]
for name in littleGame_frame_names: self.help_rect = self.help_image.get_rect()
self.littleGame_frames.append(tool.get_image_menu(tool.GFX[name], *littleGame_frame_rect, c.BLACK, 1)) self.help_rect.x = 653
self.littleGame_image = self.littleGame_frames[0] self.help_rect.y = 520
self.littleGame_rect = self.littleGame_image.get_rect() self.help_hilight_time = 0
self.littleGame_rect.x = 397
self.littleGame_rect.y = 175
self.littleGame_highlight_time = 0
# 计时器与点击信号记录器
self.adventure_start = 0 self.adventure_start = 0
self.adventure_timer = 0 self.adventure_timer = 0
self.adventure_clicked = False self.adventure_clicked = False
@ -93,21 +92,25 @@ class Menu(tool.State):
# 高亮冒险模式按钮 # 高亮冒险模式按钮
if self.inArea(self.adventure_rect, x, y): if self.inArea(self.adventure_rect, x, y):
self.adventure_highlight_time = self.current_time 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): elif self.inArea(self.exit_rect, x, y):
self.exit_highlight_time = self.current_time self.exit_highlight_time = self.current_time
# 高亮选项按钮 # 高亮选项按钮
elif self.inArea(self.option_button_rect, x, y): elif self.inArea(self.option_button_rect, x, y):
self.option_button_hightlight_time = self.current_time self.option_button_highlight_time = self.current_time
# 高亮小游戏按钮 # 高亮帮助按钮
elif self.inArea(self.littleGame_rect, x, y): elif self.inArea(self.help_rect, x, y):
self.littleGame_highlight_time = self.current_time self.help_hilight_time = self.current_time
# 处理按钮高亮情况 # 处理按钮高亮情况
self.adventure_image = self.chooseHilightImage(self.adventure_highlight_time, self.adventure_frames) 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.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.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): def chooseHilightImage(self, hilightTime, frames):
if (self.current_time - hilightTime) < 80: if (self.current_time - hilightTime) < 80:
@ -116,36 +119,35 @@ class Menu(tool.State):
index = 0 index = 0
return frames[index] return frames[index]
def checkAdventureClick(self, mouse_pos): def respondAdventureClick(self):
x, y = mouse_pos self.adventure_clicked = True
if self.inArea(self.adventure_rect, x, y): self.adventure_timer = self.adventure_start = self.current_time
self.adventure_clicked = True self.persist[c.GAME_MODE] = c.MODE_ADVENTURE
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()
c.SOUND_EVILLAUGH.play()
c.SOUND_LOSE.play()
# 点击到按钮修改转态的done属性 # 按到小游戏
def checkExitClick(self, mouse_pos): def respondLittleGameClick(self):
x, y = mouse_pos self.done = True
if self.inArea(self.exit_rect, x, y): self.persist[c.GAME_MODE] = c.MODE_LITTLEGAME
self.done = True # 播放点击音效
self.next = c.EXIT c.SOUND_BUTTON_CLICK.play()
# 检查有没有按到小游戏 # 点击到退出按钮修改转态的done属性
def checkLittleGameClick(self, mouse_pos): def respondExitClick(self):
x, y = mouse_pos self.done = True
if self.inArea(self.littleGame_rect, x, y): self.next = c.EXIT
self.done = True
self.persist[c.GAME_MODE] = c.MODE_LITTLEGAME # 帮助按钮点击
# 播放点击音效 def respondHelpClick(self):
c.SOUND_BUTTON_CLICK.play() self.done = True
self.next = c.HELP_SCREEN
def setupOptionMenu(self): def setupOptionMenu(self):
# 选项菜单框 # 选项菜单框
frame_rect = (0, 0, 500, 500) 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 = self.big_menu.get_rect()
self.big_menu_rect.x = 150 self.big_menu_rect.x = 150
self.big_menu_rect.y = 0 self.big_menu_rect.y = 0
@ -170,7 +172,7 @@ class Menu(tool.State):
font = pg.font.Font(c.FONT_PATH, 35) font = pg.font.Font(c.FONT_PATH, 35)
font.bold = True 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 = font.render("+", True, c.YELLOWGREEN)
sign_rect = sign.get_rect() sign_rect = sign.get_rect()
sign_rect.x = 8 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 = self.sound_volume_plus_button.get_rect()
self.sound_volume_plus_button_rect.x = 500 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 = font.render("-", True, c.YELLOWGREEN)
sign_rect = sign.get_rect() sign_rect = sign.get_rect()
sign_rect.x = 12 sign_rect.x = 12
@ -197,7 +199,7 @@ class Menu(tool.State):
frame_rect = (157, 0, 157, 269) frame_rect = (157, 0, 157, 269)
else: else:
frame_rect = (0, 0, 157, 269) 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 = self.sunflower_trophy.get_rect()
self.sunflower_trophy_rect.x = 0 self.sunflower_trophy_rect.x = 0
self.sunflower_trophy_rect.y = 280 self.sunflower_trophy_rect.y = 280
@ -216,16 +218,14 @@ class Menu(tool.State):
infoText = f"目前您一共完成了:玩玩小游戏{self.game_info[c.LITTLEGAME_COMPLETIONS]}轮;完成其他所有游戏模式以获得金向日葵奖杯!" infoText = f"目前您一共完成了:玩玩小游戏{self.game_info[c.LITTLEGAME_COMPLETIONS]}轮;完成其他所有游戏模式以获得金向日葵奖杯!"
infoImg = font.render(infoText , True, c.BLACK, c.LIGHTYELLOW) infoImg = font.render(infoText , True, c.BLACK, c.LIGHTYELLOW)
infoImg_rect = infoImg.get_rect() infoImg_rect = infoImg.get_rect()
infoImg_rect.x = x infoImg_rect.x = self.sunflower_trophy_rect.x
infoImg_rect.y = y infoImg_rect.y = self.sunflower_trophy_rect.bottom - 14
surface.blit(infoImg, infoImg_rect) surface.blit(infoImg, infoImg_rect)
def checkOptionButtonClick(self, mouse_pos): def respondOptionButtonClick(self):
x, y = mouse_pos self.option_button_clicked = True
if self.inArea(self.option_button_rect, x, y): # 播放点击音效
self.option_button_clicked = True c.SOUND_BUTTON_CLICK.play()
# 播放点击音效
c.SOUND_BUTTON_CLICK.play()
def showCurrentVolumeImage(self, surface): def showCurrentVolumeImage(self, surface):
# 由于音量可变,因此这一内容不能在一开始就结束加载,而应当不断刷新不断显示 # 由于音量可变,因此这一内容不能在一开始就结束加载,而应当不断刷新不断显示
@ -241,9 +241,10 @@ class Menu(tool.State):
surface.blit(self.bg_image, self.bg_rect) surface.blit(self.bg_image, self.bg_rect)
surface.blit(self.adventure_image, self.adventure_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.exit_image, self.exit_rect)
surface.blit(self.option_button_image, self.option_button_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]: if self.game_info[c.LEVEL_COMPLETIONS] or self.game_info[c.LITTLEGAME_COMPLETIONS]:
surface.blit(self.sunflower_trophy, self.sunflower_trophy_rect) 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]): if (self.game_info[c.LEVEL_COMPLETIONS] or self.game_info[c.LITTLEGAME_COMPLETIONS]):
self.checkSunflowerTrophyInfo(surface, x, y) self.checkSunflowerTrophyInfo(surface, x, y)
if mouse_pos: if mouse_pos:
self.checkExitClick(mouse_pos) if self.inArea(self.adventure_rect, *mouse_pos):
self.checkOptionButtonClick(mouse_pos) self.respondAdventureClick()
self.checkLittleGameClick(mouse_pos) elif self.inArea(self.littleGame_rect, *mouse_pos):
self.checkAdventureClick(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()

View File

@ -20,7 +20,7 @@ class Screen(tool.State):
# 按钮 # 按钮
frame_rect = (0, 0, 111, 26) 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 = self.main_menu_button_image.get_rect()
self.main_menu_button_image_rect.x = 620 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 = main_menu_text.get_rect()
main_menu_text_rect.x = 29 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 = self.next_button_image.get_rect()
self.next_button_image_rect.x = 70 self.next_button_image_rect.x = 70
### 继续按钮上的文字 ### 继续按钮上的文字
@ -116,7 +116,7 @@ class AwardScreen(tool.State):
frame_rect = (0, 0, 111, 26) frame_rect = (0, 0, 111, 26)
if self.show_only_one_option: 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 = self.main_menu_button_image.get_rect()
self.main_menu_button_image_rect.x = 343 self.main_menu_button_image_rect.x = 343
self.main_menu_button_image_rect.y = 520 self.main_menu_button_image_rect.y = 520
@ -127,32 +127,7 @@ class AwardScreen(tool.State):
main_menu_text_rect.x = 29 main_menu_text_rect.x = 29
self.main_menu_button_image.blit(main_menu_text, main_menu_text_rect) 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) 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]): if (self.game_info[c.LEVEL_COMPLETIONS] and self.game_info[c.LITTLEGAME_COMPLETIONS]):
frame_rect = (157, 0, 157, 269) frame_rect = (157, 0, 157, 269)
@ -165,7 +140,7 @@ class AwardScreen(tool.State):
intro_content = "您已完成冒险模式,获得此奖励!" intro_content = "您已完成冒险模式,获得此奖励!"
else: else:
intro_content = "您已完成玩玩小游戏,获得此奖励!" 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 = sunflower_trophy_image.get_rect()
sunflower_trophy_rect.x = 348 sunflower_trophy_rect.x = 348
sunflower_trophy_rect.y = 108 sunflower_trophy_rect.y = 108
@ -186,7 +161,29 @@ class AwardScreen(tool.State):
intro_content_rect.x = 290 intro_content_rect.x = 290
intro_content_rect.y = 370 intro_content_rect.y = 370
self.image.blit(intro_content_img, intro_content_rect) 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): def startup(self, current_time, persist):
self.start_time = current_time self.start_time = current_time
@ -214,3 +211,46 @@ class AwardScreen(tool.State):
if self.inArea(self.next_button_image_rect, *mouse_pos): if self.inArea(self.next_button_image_rect, *mouse_pos):
self.next = c.LEVEL self.next = c.LEVEL
self.done = True 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

View File

@ -5,7 +5,7 @@ import pygame as pg
from pygame.locals import * from pygame.locals import *
from . import constants as c from . import constants as c
# an abstract class, one state of automata # 状态机 抽象基类
class State(): class State():
def __init__(self): def __init__(self):
self.start_time = 0 self.start_time = 0
@ -17,7 +17,7 @@ class State():
# 当从其他状态进入这个状态时,需要进行的初始化操作 # 当从其他状态进入这个状态时,需要进行的初始化操作
@abstractmethod @abstractmethod
def startup(self, current_time, persist): def startup(self, current_time, persist):
# abstract method # 前面加了@abstractmethod表示抽象基类中必须要重新定义的methodmethod是对象和函数的结合
pass pass
# 当从这个状态退出时,需要进行的清除操作 # 当从这个状态退出时,需要进行的清除操作
def cleanup(self): def cleanup(self):
@ -26,7 +26,7 @@ class State():
# 在这个状态运行时进行的更新操作 # 在这个状态运行时进行的更新操作
@abstractmethod @abstractmethod
def update(self, surface, keys, current_time): def update(self, surface, keys, current_time):
# abstract method # 前面加了@abstractmethod表示抽象基类中必须要重新定义的method
pass pass
# 工具:范围判断函数,用于判断点击 # 工具:范围判断函数,用于判断点击
@ -47,7 +47,7 @@ class State():
data_to_save = json.dumps(userdata, sort_keys=True, indent=4) data_to_save = json.dumps(userdata, sort_keys=True, indent=4)
f.write(data_to_save) f.write(data_to_save)
# control this game. do event loops # 进行游戏控制 循环 事件响应
class Control(): class Control():
def __init__(self): def __init__(self):
self.screen = pg.display.get_surface() self.screen = pg.display.get_surface()
@ -100,7 +100,7 @@ class Control():
self.state.startup(self.current_time, self.game_info) self.state.startup(self.current_time, self.game_info)
def update(self): def update(self):
# 返回自 pygame_init() 调用以来的毫秒数 * 游戏速度倍率 # 自 pygame_init() 调用以来的毫秒数 * 游戏速度倍率,即游戏时间
self.current_time = pg.time.get_ticks() * self.game_info[c.GAME_RATE] self.current_time = pg.time.get_ticks() * self.game_info[c.GAME_RATE]
if self.state.done: if self.state.done:
@ -116,7 +116,6 @@ class Control():
if self.state.next == c.EXIT: if self.state.next == c.EXIT:
pg.quit() pg.quit()
os._exit(0) os._exit(0)
# previous, self.state_name = self.state_name, self.state.next
self.state_name = self.state.next self.state_name = self.state.next
persist = self.state.cleanup() persist = self.state.cleanup()
self.state = self.state_dict[self.state_name] 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))) int(rect.height*scale)))
return image 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通道的图片导入 # 保留alpha通道的图片导入
image = pg.Surface([width, height], SRCALPHA) image = pg.Surface([width, height], SRCALPHA)
rect = image.get_rect() rect = image.get_rect()
@ -198,7 +197,7 @@ def load_image_frames(directory, image_name, colorkey, accept):
return frame_list return frame_list
# colorkeys 是设置图像中的某个颜色值为透明,这里用来消除白边 # 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 = {} graphics = {}
for name1 in os.listdir(directory): for name1 in os.listdir(directory):
# subfolders under the folder resources\graphics # subfolders under the folder resources\graphics