diff --git a/source/component/map.py b/source/component/map.py index e4c1ea5..fca7b9c 100755 --- a/source/component/map.py +++ b/source/component/map.py @@ -9,11 +9,11 @@ class Map(): self.background_type = background_type # 注意:从0开始编号 # 集合内容需要deepcopy - if self.background_type in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: self.width = c.GRID_POOL_X_LEN self.height = c.GRID_POOL_Y_LEN self.map = [[(deepcopy(c.MAP_STATE_EMPTY), deepcopy(c.MAP_STATE_WATER))[y in {2, 3}] for x in range(self.width)] for y in range(self.height)] - elif self.background_type in {c.BACKGROUND_ROOF, c.BACKGROUND_ROOFNIGHT}: + elif self.background_type in c.ON_ROOF_BACKGROUNDS: self.width = c.GRID_ROOF_X_LEN self.height = c.GRID_ROOF_Y_LEN self.map = [[deepcopy(c.MAP_STATE_TILE) for x in range(self.width)] for y in range(self.height)] @@ -52,11 +52,11 @@ class Map(): return True else: return False - if any((i in {c.HOLE, c.ICE_FROZEN_PLOT, c.GRAVE}) for i in self.map[map_y][map_x][c.MAP_PLANT]): + if any((i in c.NON_PLANT_OBJECTS) for i in self.map[map_y][map_x][c.MAP_PLANT]): return False if self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_GRASS: # 草地 # 首先需要判断植物是否是水生植物,水生植物不能种植在陆地上 - if plantName not in {c.LILYPAD, c.SEASHROOM, c.TANGLEKLEP}: # 这里的集合也可以换成存储在某一文件中的常数的表达 + if plantName not in c.WATER_PLANTS: if not self.map[map_y][map_x][c.MAP_PLANT]: # 没有植物肯定可以种植 return True elif (all((i in {'花盆(未实现)', '南瓜头(未实现)'}) for i in self.map[map_y][map_x][c.MAP_PLANT]) @@ -68,7 +68,7 @@ class Map(): return False elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_TILE: # 屋顶 # 首先需要判断植物是否是水生植物,水生植物不能种植在陆地上 - if plantName not in {c.LILYPAD, c.SEASHROOM, c.TANGLEKLEP}: # 这里的集合也可以换成存储在某一文件中的常数的表达 + if plantName not in c.WATER_PLANTS: if '花盆(未实现)' in self.map[map_y][map_x][c.MAP_PLANT]: if (all((i in {'花盆(未实现)', '南瓜头(未实现)'}) 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])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植;判断方法:并集 @@ -83,7 +83,7 @@ class Map(): else: return False elif self.map[map_y][map_x][c.MAP_PLOT_TYPE] == c.MAP_WATER: # 水里 - if plantName in {c.LILYPAD, c.SEASHROOM, c.TANGLEKLEP}: # 是水生植物 + if plantName in c.WATER_PLANTS: # 是水生植物 if not self.map[map_y][map_x][c.MAP_PLANT]: # 只有无植物时才能在水里种植水生植物 return True else: @@ -92,7 +92,7 @@ class Map(): if c.LILYPAD in self.map[map_y][map_x][c.MAP_PLANT]: if (all((i in {c.LILYPAD, '南瓜头(未实现)'}) 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,'花盆(未实现)'}: # 不能在睡莲上种植的植物 + if plantName in {c.SPIKEWEED, c.POTATOMINE, '花盆(未实现)'}: # 不能在睡莲上种植的植物 return False else: return True @@ -105,11 +105,11 @@ class Map(): def getMapIndex(self, x, y): # 引入新地图后需要增加这里的内容 - if self.background_type in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: x -= c.MAP_POOL_OFFSET_X y -= c.MAP_POOL_OFFSET_Y return (x // c.GRID_POOL_X_SIZE, y // c.GRID_POOL_Y_SIZE) - elif self.background_type in {c.BACKGROUND_ROOF, c.BACKGROUND_ROOFNIGHT}: + elif self.background_type in c.ON_ROOF_BACKGROUNDS: x -= c.MAP_ROOF_OFFSET_X y -= c.MAP_ROOF_OFFSET_X gridX = x // c.GRID_ROOF_X_SIZE @@ -124,10 +124,10 @@ class Map(): return (x // c.GRID_X_SIZE, y // c.GRID_Y_SIZE) def getMapGridPos(self, map_x, map_y): - if self.background_type in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: return (map_x * c.GRID_POOL_X_SIZE + c.GRID_POOL_X_SIZE//2 + c.MAP_POOL_OFFSET_X, map_y * c.GRID_POOL_Y_SIZE + c.GRID_POOL_Y_SIZE//5 * 3 + c.MAP_POOL_OFFSET_Y) - elif self.background_type in {c.BACKGROUND_ROOF, c.BACKGROUND_ROOFNIGHT}: + elif self.background_type in c.ON_ROOF_BACKGROUNDS: return (map_x * c.GRID_ROOF_X_SIZE + c.GRID_ROOF_X_SIZE//2 + c.MAP_ROOF_OFFSET_X, map_y * c.GRID_ROOF_Y_SIZE + 20 * max(0, (6 - map_y)) + c.GRID_ROOF_Y_SIZE//5 * 3 + c.MAP_POOL_OFFSET_Y) else: diff --git a/source/component/plant.py b/source/component/plant.py index 8a8cfc5..4aa947a 100755 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -467,7 +467,7 @@ class ThreePeaShooter(Plant): offset_y = 9 # modify bullet in the same y position with bullets of other plants for i in range(3): tmp_y = self.map_y + (i - 1) - if self.background_type in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: if tmp_y < 0 or tmp_y >= c.GRID_POOL_Y_LEN: continue else: diff --git a/source/constants.py b/source/constants.py index 0be6c86..9395c8b 100755 --- a/source/constants.py +++ b/source/constants.py @@ -104,6 +104,19 @@ BACKGROUND_WALLNUTBOWLING = 6 BACKGROUND_SINGLE = 7 BACKGROUND_TRIPLE = 8 +# 地图类型集合 +# 白天场地 +DAYTIME_BACKGROUNDS = { BACKGROUND_DAY, BACKGROUND_POOL, + BACKGROUND_ROOF, BACKGROUND_WALLNUTBOWLING, + BACKGROUND_SINGLE, BACKGROUND_TRIPLE, + } +# 带有泳池的场地 +POOL_EQUIPPED_BACKGROUNDS = { BACKGROUND_POOL, BACKGROUND_FOG, + } +# 屋顶上的场地 +ON_ROOF_BACKGROUNDS = { BACKGROUND_ROOF, BACKGROUND_ROOFNIGHT, + } + # 夜晚地图的墓碑数量等级 GRADE_GRAVES = 'grade_graves' GRADE0_GRAVES = 0 # 无墓碑 @@ -218,6 +231,60 @@ GRAVE = 'Grave' GRAVEBUSTER = 'GraveBuster' FUMESHROOM = 'FumeShroom' +# 植物集体属性 +# 在生效时不用与僵尸进行碰撞检测的对象 +SKIP_ZOMBIE_COLLISION_CHECK_WHEN_WORKING = {# 注意爆炸坚果的触发也是啃食类碰撞,因此这里不能省略 + SQUASH, ICESHROOM, + REDWALLNUTBOWLING, CHERRYBOMB, + JALAPENO, DOOMSHROOM, + POTATOMINE, + } +# 非植物对象 +NON_PLANT_OBJECTS = { HOLE, ICE_FROZEN_PLOT, + GRAVE, + } +# 所有可能不用与僵尸进行碰撞检测的对象 +CAN_SKIP_ZOMBIE_COLLISION_CHECK = ( # 生效时不检测的植物 + SKIP_ZOMBIE_COLLISION_CHECK_WHEN_WORKING | + # 非植物对象 + NON_PLANT_OBJECTS | + # 地刺类 + {SPIKEWEED, } + ) +# 死亡时不触发音效的对象 +PLANT_DIE_SOUND_EXCEPTIONS = { WALLNUTBOWLING, TANGLEKLEP, + ICE_FROZEN_PLOT, HOLE, + GRAVE, JALAPENO, + REDWALLNUTBOWLING, CHERRYBOMB, + } +# color_key为白色的对象 +PLANT_COLOR_KEY_WHITE = { POTATOMINE, SPIKEWEED, + JALAPENO, SCAREDYSHROOM, + SUNSHROOM, ICESHROOM, + HYPNOSHROOM, SQUASH, + WALLNUTBOWLING, REDWALLNUTBOWLING, + } +# 直接水生植物 +WATER_PLANTS = { LILYPAD, SEASHROOM, + TANGLEKLEP, + } +# 不用使用通用方法检验攻击状态的植物 +PLANT_NON_CHECK_ATTACK_STATE = ({ # 单独指定攻击状态的植物 + WALLNUTBOWLING, + # 没有攻击状态的植物 + WALLNUT, TALLNUT, + TORCHWOOD, SUNFLOWER, + SUNSHROOM, COFFEEBEAN, + GRAVEBUSTER, LILYPAD, + HYPNOSHROOM, + } | + # 非植物类 + NON_PLANT_OBJECTS + ) +# 范围爆炸植物,即灰烬植物与寒冰菇 +ASH_PLANTS_AND_ICESHROOM = { REDWALLNUTBOWLING, CHERRYBOMB, + JALAPENO, DOOMSHROOM, + ICESHROOM,} # 植物生命值 PLANT_HEALTH = 300 @@ -316,6 +383,12 @@ ZOMBONI = 'Zomboni' BOOMDIE = 'BoomDie' +# 僵尸集体属性 +# 水上僵尸集合 +WATER_ZOMBIE = { DUCKY_TUBE_ZOMBIE, CONEHEAD_DUCKY_TUBE_ZOMBIE, + BUCKETHEAD_DUCKY_TUBE_ZOMBIE, + } + # 对僵尸的攻击类型设置 ZOMBIE_DEAFULT_DAMAGE = 'helmet2First' ZOMBIE_HELMET_2_FIRST = 'helmet2First' # 优先攻击二类防具 diff --git a/source/state/level.py b/source/state/level.py index 039c358..bd64fc6 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -149,7 +149,7 @@ class Level(tool.State): while (volume >= minCost) and (len(zombieList) < 50): newZombie = choices(useableZombies, weights)[0] # 普通僵尸、路障僵尸、铁桶僵尸有概率生成水中变种 - if self.background_type in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS: # 有泳池第一轮的第四波设定上生成水生僵尸 if survivalRounds == 0 and wave == 4: if newZombie in self.convertZombieInPool: @@ -226,7 +226,7 @@ class Level(tool.State): else: self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(itemX, itemY, self.head_group)) self.graveZombieCreated = True - elif self.map_data[c.BACKGROUND_TYPE] in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: + elif self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS: if not self.createdZombieFromPool: if current_time - self.waveTime > 1500: for i in range(3): @@ -637,7 +637,7 @@ class Level(tool.State): for i in self.plant_groups[map_y]: if (x >= i.rect.x and x <= i.rect.right and y >= i.rect.y and y <= i.rect.bottom): - if i.name in {c.HOLE, c.ICE_FROZEN_PLOT, c.GRAVE}: + if i.name in c.NON_PLANT_OBJECTS: continue # 优先移除花盆、睡莲上的植物而非花盆、睡莲本身 if len(self.map.map[map_y][map_x][c.MAP_PLANT]) >= 2: @@ -791,8 +791,8 @@ class Level(tool.State): if map_y == None: # 情况复杂:分水路和陆路,不能简单实现,需要另外加判断 # 0, 1, 4, 5路为陆路,2, 3路为水路 - if self.map_data[c.BACKGROUND_TYPE] in {c.BACKGROUND_POOL, c.BACKGROUND_FOG}: - if name in {c.DUCKY_TUBE_ZOMBIE, c.CONEHEAD_DUCKY_TUBE_ZOMBIE, c.BUCKETHEAD_DUCKY_TUBE_ZOMBIE}: # 水生僵尸集合 + if self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS: + if name in c.WATER_ZOMBIE: # 水生僵尸集合 map_y = randint(2, 3) elif name == '这里应该换成气球僵尸的名字(最好写调用的变量名,最好不要直接写,保持风格统一)': map_y = randint(0, 5) @@ -923,7 +923,7 @@ class Level(tool.State): new_plant = plant.FumeShroom(x, y, self.bullet_groups[map_y], self.zombie_groups[map_y]) - if new_plant.can_sleep and self.background_type in {c.BACKGROUND_DAY, c.BACKGROUND_POOL, c.BACKGROUND_ROOF, c.BACKGROUND_WALLNUTBOWLING, c.BACKGROUND_SINGLE, c.BACKGROUND_TRIPLE}: + if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS: new_plant.setSleep() mushroomSleep = True else: @@ -981,12 +981,7 @@ class Level(tool.State): rect = frame_list[0].get_rect() width, height = rect.w, rect.h - if (plant_name in { c.POTATOMINE, c.SPIKEWEED, - c.JALAPENO, c.SCAREDYSHROOM, - c.SUNSHROOM, c.ICESHROOM, - c.HYPNOSHROOM, c.SQUASH, - c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, - }): + if (plant_name in c.PLANT_COLOR_KEY_WHITE): color = c.WHITE else: color = c.BLACK @@ -1087,27 +1082,10 @@ class Level(tool.State): attackableBackupPlant.append(plant) # 一般植物情形 # 同时也忽略了不可啃食对象 - elif plant.name not in {# 不可啃食对象 - # 非植物对象 - c.HOLE, c.ICE_FROZEN_PLOT, - c.GRAVE, - # 对一般僵尸无条件不可啃食植物:地刺 - c.SPIKEWEED, - # 对一般僵尸有条件不可啃食植物:跳起的倭瓜、释放效果后的爆炸类植物 - # 这类在后面还需要判断 - c.SQUASH, c.ICESHROOM, - c.REDWALLNUTBOWLING, c.CHERRYBOMB, - c.JALAPENO, c.DOOMSHROOM, - c.POTATOMINE - }: + elif plant.name not in c.CAN_SKIP_ZOMBIE_COLLISION_CHECK: attackableCommonPlants.append(plant) # 在某些状态下忽略啃食碰撞但某些状况下不能忽略的情形 - elif plant.name in {# 注意爆炸坚果的触发也是啃食类碰撞,因此这里不能省略 - c.SQUASH, c.ICESHROOM, - c.REDWALLNUTBOWLING, c.CHERRYBOMB, - c.JALAPENO, c.DOOMSHROOM, - c.POTATOMINE, - }: + elif plant.name in c.SKIP_ZOMBIE_COLLISION_CHECK_WHEN_WORKING: if plant.name == c.SQUASH: if not plant.squashing: attackableCommonPlants.append(plant) @@ -1125,7 +1103,7 @@ class Level(tool.State): for actualTargetPlant in self.plant_groups[i]: # 检测同一格的其他植物 if self.map.getMapIndex(actualTargetPlant.rect.centerx, actualTargetPlant.rect.bottom) == (map_x, map_y): - if actualTargetPlant.name in {"南瓜头(未实现)"}: + if actualTargetPlant.name == "南瓜头(未实现)": targetPlant = actualTargetPlant break elif actualTargetPlant.name not in {c.LILYPAD, "花盆(未实现)"}: @@ -1241,10 +1219,7 @@ class Level(tool.State): # 毁灭菇的情况:爆炸时为了防止蘑菇云被坑掩盖没有加入坑,这里毁灭菇死亡(即爆炸动画结束)后再加入 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.WALLNUTBOWLING, c.TANGLEKLEP, - c.ICE_FROZEN_PLOT, c.HOLE, - c.GRAVE, c.JALAPENO, - c.REDWALLNUTBOWLING, c.CHERRYBOMB,}: + elif targetPlant.name not in c.PLANT_DIE_SOUND_EXCEPTIONS: # 触发植物死亡音效 pg.mixer.Sound(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "sound", "plantDie.ogg")).play() else: @@ -1265,17 +1240,7 @@ class Level(tool.State): def checkPlant(self, targetPlant, i): zombie_len = len(self.zombie_groups[i]) # 不用检查攻击状况的情况 - if targetPlant.name in { # 单独指定攻击状态的植物 - c.WALLNUTBOWLING, - # 没有攻击状态的植物 - c.WALLNUT, c.TALLNUT, - c.TORCHWOOD, c.SUNFLOWER, - c.SUNSHROOM, c.COFFEEBEAN, - c.GRAVEBUSTER, c.LILYPAD, - c.HYPNOSHROOM, - # 非植物类 - c.HOLE, c.GRAVE, - c.ICE_FROZEN_PLOT}: + if targetPlant.name in c.PLANT_NON_CHECK_ATTACK_STATE: pass elif targetPlant.name == c.THREEPEASHOOTER: if targetPlant.state == c.IDLE: @@ -1360,9 +1325,7 @@ class Level(tool.State): targetPlant.setAttack(zombie, self.zombie_groups[i]) break # 灰烬植物与寒冰菇 - elif targetPlant.name in { c.REDWALLNUTBOWLING, c.CHERRYBOMB, - c.JALAPENO, c.DOOMSHROOM, - c.ICESHROOM,}: + elif targetPlant.name in c.ASH_PLANTS_AND_ICESHROOM: if targetPlant.start_boom and (not targetPlant.boomed): # 这样分成两层是因为场上灰烬植物肯定少,一个一个判断代价高,先笼统判断灰烬即可 if targetPlant.name in {c.REDWALLNUTBOWLING, c.CHERRYBOMB}: @@ -1467,7 +1430,7 @@ class Level(tool.State): for i in self.plant_groups[map_y]: if (x >= i.rect.x and x <= i.rect.right and y >= i.rect.y and y <= i.rect.bottom): - if i.name in {c.HOLE, c.ICE_FROZEN_PLOT, c.GRAVE}: + if i.name in c.NON_PLANT_OBJECTS: continue # 优先选中睡莲、花盆上的植物 if len(self.map.map[map_y][map_x][c.MAP_PLANT]) >= 2: