全面修改碰撞机制

This commit is contained in:
星外之神 2022-05-11 15:19:13 +08:00
parent 46780ee81e
commit 2ce597bd48
5 changed files with 87 additions and 35 deletions

View File

@ -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":[

View File

@ -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):

View File

@ -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:

View File

@ -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

View File

@ -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]:
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:
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):