From 2ce597bd48f07318235f6b5cdc1fe52d81deb412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E5=A4=96=E4=B9=8B=E7=A5=9E?= Date: Wed, 11 May 2022 15:19:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E9=9D=A2=E4=BF=AE=E6=94=B9=E7=A2=B0?= =?UTF-8?q?=E6=92=9E=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/data/map/littleGame_2.json | 2 +- source/component/plant.py | 55 ++++++++++++++++++++++------ source/component/zombie.py | 8 +++- source/constants.py | 2 +- source/state/level.py | 55 ++++++++++++++++++---------- 5 files changed, 87 insertions(+), 35 deletions(-) diff --git a/resources/data/map/littleGame_2.json b/resources/data/map/littleGame_2.json index 8931f35..948e572 100644 --- a/resources/data/map/littleGame_2.json +++ b/resources/data/map/littleGame_2.json @@ -3,7 +3,7 @@ "choosebar_type":2, "shovel":0, "spawn_zombies":"auto", - "included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "NewspaperZombie"], + "included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "NewspaperZombie", "PoleVaultingZombie"], "num_flags":4, "inevitable_zombie_list":{"20":["BucketheadZombie"]}, "card_pool":[ diff --git a/source/component/plant.py b/source/component/plant.py index 422e122..8606d82 100755 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -12,6 +12,7 @@ class Car(pg.sprite.Sprite): rect = tool.GFX[c.CAR].get_rect() width, height = rect.w, rect.h self.image = tool.get_image(tool.GFX[c.CAR], 0, 0, width, height) + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.x = x self.rect.bottom = y @@ -46,7 +47,9 @@ class Bullet(pg.sprite.Sprite): self.frames = [] self.frame_index = 0 self.load_images() + self.frame_num = len(self.frames) self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = start_y @@ -57,6 +60,8 @@ class Bullet(pg.sprite.Sprite): self.effect = effect self.state = c.FLY self.current_time = 0 + self.animate_timer = 0 + self.animate_interval = 70 self.passedTorchWood = passedTorchWood # 记录最近通过的火炬树横坐标,如果没有缺省为None def loadFrames(self, frames, name): @@ -106,12 +111,20 @@ class Bullet(pg.sprite.Sprite): elif self.state == c.EXPLODE: if (self.current_time - self.explode_timer) > 250: self.kill() + if self.current_time - self.animate_timer >= self.animate_interval: + self.frame_index += 1 + self.animate_timer = self.current_time + if self.frame_index >= self.frame_num: + self.frame_index = 0 + self.image = self.frames[self.frame_index] def setExplode(self): self.state = c.EXPLODE self.explode_timer = self.current_time self.frames = self.explode_frames - self.image = self.frames[self.frame_index] + self.frame_num = len(self.frames) + self.image = self.frames[0] + self.mask = pg.mask.from_surface(self.image) # 播放子弹爆炸音效 if self.name == c.BULLET_FIREBALL: @@ -133,6 +146,7 @@ class Fume(pg.sprite.Sprite): self.load_images() self.frame_num = len(self.frames) self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y @@ -223,6 +237,7 @@ class Plant(pg.sprite.Sprite): self.loadImages(name, scale) self.frame_num = len(self.frames) self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.centerx = x self.rect.bottom = y @@ -263,6 +278,7 @@ class Plant(pg.sprite.Sprite): bottom = self.rect.bottom x = self.rect.x self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.bottom = bottom self.rect.x = x @@ -297,6 +313,7 @@ class Plant(pg.sprite.Sprite): self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.highlightTime < 200): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): @@ -536,6 +553,7 @@ class CherryBomb(Plant): old_rect = self.rect image = tool.get_image(frame, 0, 0, width, height, c.BLACK, 1) self.image = image + self.mask = pg.mask.from_surface(self.image) self.rect = image.get_rect() self.rect.centerx = old_rect.centerx self.rect.centery = old_rect.centery @@ -558,6 +576,7 @@ class CherryBomb(Plant): self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) class Chomper(Plant): @@ -590,9 +609,11 @@ class Chomper(Plant): self.frames = self.idle_frames def canAttack(self, zombie): - if (self.state == c.IDLE and zombie.state != c.DIGEST and - self.rect.x <= zombie.rect.right and (not zombie.lostHead) and - (self.rect.right + c.GRID_X_SIZE >= zombie.rect.x)): + if (zombie.name in {c.POLE_VAULTING_ZOMBIE}) and (not zombie.jumped): + return False + elif (self.state == c.IDLE and zombie.state != c.DIGEST and + self.rect.x <= zombie.rect.right - 10 and (not zombie.lostHead) and + (self.rect.x + c.GRID_X_SIZE*2.6 >= zombie.rect.centerx)): return True return False @@ -707,7 +728,7 @@ class PotatoMine(Plant): def canAttack(self, zombie): if (self.name == c.POLE_VAULTING_ZOMBIE and (not self.jumped)): return False - elif (pg.sprite.collide_circle_ratio(0.55)(zombie, self) and + elif (pg.sprite.collide_mask(zombie, self) and (not self.is_init) and (not zombie.lostHead)): return True return False @@ -755,7 +776,7 @@ class Squash(Plant): # 攻击状态 elif (self.state == c.ATTACK): # 碰撞检测 - if pg.sprite.collide_circle_ratio(0.7)(zombie, self): + if pg.sprite.collide_mask(zombie, self): return True return False @@ -805,6 +826,7 @@ class Spikeweed(Plant): def canAttack(self, zombie): # 地刺能不能扎的判据:僵尸中心与地刺中心的距离或僵尸包括了地刺中心和右端(平衡得到合理的攻击范围,"僵尸包括了地刺中心和右端"是为以后巨人做准备) + # 暂时不能用碰撞判断,平衡性不好 if ((-45 <= zombie.rect.x - self.rect.x <= 30) or (zombie.rect.left <= self.rect.x <= zombie.rect.right and zombie.rect.left <= self.rect.right <= zombie.rect.right)): return True return False @@ -869,6 +891,7 @@ class Jalapeno(Plant): return self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) def getPosition(self): return self.orig_pos @@ -1027,6 +1050,7 @@ class IceShroom(Plant): return self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) def getPosition(self): return self.orig_pos @@ -1137,6 +1161,7 @@ class WallNutBowling(Plant): image = self.frames[self.frame_index] self.image = pg.transform.rotate(image, self.rotate_degree) + self.mask = pg.mask.from_surface(self.image) # must keep the center postion of image when rotate self.rect = self.image.get_rect(center=self.init_rect.center) @@ -1201,6 +1226,7 @@ class RedWallNutBowling(Plant): self.image = pg.transform.rotate(image, self.rotate_degree) else: self.image = image + self.mask = pg.mask.from_surface(self.image) # must keep the center postion of image when rotate self.rect = self.image.get_rect(center=self.init_rect.center) @@ -1218,16 +1244,16 @@ class TorchWood(Plant): def idling(self): for i in self.bullet_group: if i.name == c.BULLET_PEA: - if i.passedTorchWood != self.rect.x: - if -10 <= i.rect.x - self.rect.x <= 20: + if i.passedTorchWood != self.rect.centerx: + if abs(i.rect.centerx - self.rect.centerx) <= 20: self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.rect.y, - c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, effect=c.BULLET_EFFECT_UNICE, passedTorchWood=self.rect.x)) + c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, effect=c.BULLET_EFFECT_UNICE, passedTorchWood=self.rect.centerx)) i.kill() elif i.name == c.BULLET_PEA_ICE: - if i.passedTorchWood != self.rect.x: - if -10 <= i.rect.x - self.rect.x <= 20: + if i.passedTorchWood != self.rect.centerx: + if abs(i.rect.centerx - self.rect.centerx) <= 20: self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.rect.y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=False, passedTorchWood=self.rect.x)) + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=False, passedTorchWood=self.rect.centerx)) i.kill() class StarFruit(Plant): @@ -1304,6 +1330,7 @@ class CoffeeBean(Plant): self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.highlightTime < 200): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): @@ -1501,6 +1528,7 @@ class DoomShroom(Plant): return self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) # 用于描述毁灭菇的坑 class Hole(Plant): @@ -1563,6 +1591,7 @@ class Grave(Plant): Plant.__init__(self, x, y, c.GRAVE, c.INF, None) self.frame_index = randint(0, self.frame_num - 1) self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) def animation(self): pass @@ -1590,6 +1619,7 @@ class GraveBuster(Plant): self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.highlightTime < 200): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): @@ -1663,6 +1693,7 @@ class FumeShroom(Plant): self.animate_timer = self.current_time self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.highlightTime < 200): self.image.set_alpha(150) elif ((self.current_time - self.hit_timer) < 200): diff --git a/source/component/zombie.py b/source/component/zombie.py index 9aa11fd..c4b0ca2 100755 --- a/source/component/zombie.py +++ b/source/component/zombie.py @@ -16,6 +16,7 @@ class Zombie(pg.sprite.Sprite): self.frame_num = len(self.frames) self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.centerx = x self.rect.bottom = y @@ -261,6 +262,7 @@ class Zombie(pg.sprite.Sprite): bottom = self.rect.bottom centerx = self.rect.centerx self.image = self.frames[self.frame_index] + self.mask = pg.mask.from_surface(self.image) self.rect = self.image.get_rect() self.rect.bottom = bottom self.rect.centerx = centerx @@ -282,6 +284,7 @@ class Zombie(pg.sprite.Sprite): self.image = self.frames[self.frame_index] if self.is_hypno: self.image = pg.transform.flip(self.image, True, False) + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.hit_timer) >= 200: self.image.set_alpha(255) else: @@ -669,8 +672,8 @@ class FootballZombie(Zombie): self.animate_interval = 50 self.walk_animate_interval = 50 self.attack_animate_interval = 60 - self.lostHead_animate_interval = 50 - self.die_animate_interval = 50 + self.lostHead_animate_interval = 180 + self.die_animate_interval = 150 def loadImages(self): self.helmet_walk_frames = [] @@ -922,6 +925,7 @@ class PoleVaultingZombie(Zombie): self.image = self.frames[self.frame_index] if self.is_hypno: self.image = pg.transform.flip(self.image, True, False) + self.mask = pg.mask.from_surface(self.image) if (self.current_time - self.hit_timer) >= 200: self.image.set_alpha(255) else: diff --git a/source/constants.py b/source/constants.py index f12c384..a55ef44 100755 --- a/source/constants.py +++ b/source/constants.py @@ -166,7 +166,7 @@ PANEL_Y_INTERNAL = 73 PANEL_X_INTERNAL = 53 BAR_CARD_X_INTERNAL = 51 CARD_MAX_NUM = 10 # 这里以后可以增加解锁功能,从最初的6格逐渐解锁到10格 -CARD_LIST_NUM = CARD_MAX_NUM +CARD_LIST_NUM = 0#CARD_MAX_NUM # 所选植物信息索引 PLANT_NAME_INDEX = 0 diff --git a/source/state/level.py b/source/state/level.py index df1d3dc..787e45d 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -994,10 +994,11 @@ class Level(tool.State): for bullet in self.bullet_groups[i]: if bullet.name == c.FUME: continue - elif bullet.name == c.BULLET_STAR: - collided_func = pg.sprite.collide_circle_ratio(1) - else: - collided_func = pg.sprite.collide_circle_ratio(0.7) + # elif bullet.name == c.BULLET_STAR: + # collided_func = pg.sprite.collide_circle_ratio(1) + # else: + # collided_func = pg.sprite.collide_circle_ratio(0.7) + collided_func = pg.sprite.collide_mask if bullet.state == c.FLY: # 利用循环而非内建精灵组碰撞判断函数,处理更加灵活,可排除已死亡僵尸 for zombie in self.zombie_groups[i]: @@ -1014,14 +1015,18 @@ class Level(tool.State): def checkZombieCollisions(self): - if self.bar_type == c.CHOSSEBAR_BOWLING: - ratio = 0.6 - else: - ratio = 0.5 - collided_func = pg.sprite.collide_circle_ratio(ratio) + # if self.bar_type == c.CHOSSEBAR_BOWLING: + # ratio = 0.6 + # else: + # ratio = 0.5 + # collided_func = pg.sprite.collide_circle_ratio(ratio) for i in range(self.map_y_len): hypo_zombies = [] for zombie in self.zombie_groups[i]: + if zombie.name in {c.POLE_VAULTING_ZOMBIE} and (not zombie.jumped): + collided_func = pg.sprite.collide_rect_ratio(0.6) + else: + collided_func = pg.sprite.collide_mask if zombie.state != c.WALK: if zombie.state != c.ATTACK: continue @@ -1050,7 +1055,7 @@ class Level(tool.State): targetPlant = max(attackableCommonPlants, key=lambda i: i.rect.x) elif attackableBackupPlant: targetPlant = max(attackableBackupPlant, key=lambda i: i.rect.x) - map_x, map_y = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.bottom) + map_x, map_y = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.centery) if len(self.map.map[map_y][map_x][c.MAP_PLANT]) >= 2: for actualTargetPlant in self.plant_groups[i]: # 检测同一格的其他植物 @@ -1069,12 +1074,19 @@ class Level(tool.State): if targetPlant: # 撑杆跳的特殊情况 if zombie.name in {c.POLE_VAULTING_ZOMBIE} and (not zombie.jumped): - map_x, map_y = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.bottom) - jumpX = targetPlant.rect.x - c.GRID_X_SIZE * 0.7 - if c.TALLNUT in self.map.map[map_y][map_x][c.MAP_PLANT]: - zombie.setJump(False, jumpX) + if not zombie.jumping: + zombie.jumpMap_x, zombie.jumpMap_y = self.map.getMapIndex(targetPlant.rect.centerx, targetPlant.rect.centery) + zombie.jumpMap_x, zombie.jumpMap_y = min(c.GRID_X_LEN, zombie.jumpMap_x), min(self.map_y_len, zombie.jumpMap_y) + jumpX = targetPlant.rect.x - c.GRID_X_SIZE * 0.6 + if c.TALLNUT in self.map.map[zombie.jumpMap_y][zombie.jumpMap_x][c.MAP_PLANT]: + zombie.setJump(False, jumpX) + else: + zombie.setJump(True, jumpX) else: - zombie.setJump(True, jumpX) + if c.TALLNUT in self.map.map[zombie.jumpMap_y][zombie.jumpMap_x][c.MAP_PLANT]: + zombie.setJump(False, zombie.jumpX) + else: + zombie.setJump(True, zombie.jumpX) continue if targetPlant.name == c.WALLNUTBOWLING: @@ -1175,7 +1187,7 @@ class Level(tool.State): elif (targetPlant.name == c.POTATOMINE and not targetPlant.is_init): # 土豆雷不是灰烬植物,不能用Boom for zombie in self.zombie_groups[map_y]: # 双判断:发生碰撞或在攻击范围内 - if ((pg.sprite.collide_circle_ratio(0.6)(zombie, targetPlant)) or + if ((pg.sprite.collide_mask(zombie, targetPlant)) or (abs(zombie.rect.centerx - x) <= targetPlant.explode_x_range)): zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE) # 对于墓碑:移除存储在墓碑集合中的坐标 @@ -1202,7 +1214,14 @@ class Level(tool.State): def checkPlant(self, plant, i): zombie_len = len(self.zombie_groups[i]) - if plant.name == c.THREEPEASHOOTER: + # 没有攻击状态的植物 + if plant.name in { c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, + c.WALLNUT, c.TALLNUT, + c.TORCHWOOD, c.SUNFLOWER, + c.SUNSHROOM, c.COFFEEBEAN, + c.GRAVEBUSTER, c.LILYPAD}: + pass + elif plant.name == c.THREEPEASHOOTER: if plant.state == c.IDLE: if zombie_len > 0: plant.setAttack() @@ -1277,8 +1296,6 @@ class Level(tool.State): if plant.canAttack(zombie): plant.setAttack(zombie, self.zombie_groups[i]) break - elif plant.name in {c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, c.WALLNUT, c.TALLNUT}: - pass else: can_attack = False if (zombie_len > 0):