Merge branch 'master' into opengl

This commit is contained in:
星外之神 2022-08-11 13:31:28 +08:00
commit af7528944b
5 changed files with 77 additions and 45 deletions

View File

@ -87,10 +87,11 @@ python pypvz.py
* 泳池模式9~11
* 浓雾模式暂时没有雾12
* 小游戏模式:
* 坚果保龄球模式1
* 坚果保龄球1
* 传送带模式白天2
* 传送带模式黑夜3
* 传送带模式泳池4
* 坚果保龄球(II)5
* 目前暂时按照以上设定,未与原版相符
* 可以通过修改存档JSON文件中的`game rate`值来调节游戏速度倍率

View File

@ -56,10 +56,10 @@ class Map():
]
def isValid(self, map_x, map_y):
if (map_x < 0 or map_x >= self.width or
map_y < 0 or map_y >= self.height):
return False
return True
if ((0 <= map_x < self.width)
and (0 <= map_y < self.height)):
return True
return False
# 地图单元格状态
# 注意是可变对象,不能直接引用

View File

@ -22,7 +22,8 @@ def getSunValueImage(sun_value):
return image
def getCardPool(data):
card_pool = {c.PLANT_CARD_INFO[c.PLANT_CARD_INDEX[card_name]]: data[card_name] for card_name in data}
card_pool = {c.PLANT_CARD_INFO[c.PLANT_CARD_INDEX[card_name]]: data[card_name]
for card_name in data}
return card_pool
class Card():
@ -36,7 +37,8 @@ class Card():
self.sun_cost_img = font.render(str(c.PLANT_CARD_INFO[index][c.SUN_INDEX]), True, c.BLACK)
self.sun_cost_img_rect = self.sun_cost_img.get_rect()
sun_cost_img_x = 32 - self.sun_cost_img_rect.w
self.orig_image.blit(self.sun_cost_img, (sun_cost_img_x, 52, self.sun_cost_img_rect.w, self.sun_cost_img_rect.h))
self.orig_image.blit(self.sun_cost_img,
(sun_cost_img_x, 52, self.sun_cost_img_rect.w, self.sun_cost_img_rect.h))
self.index = index
self.sun_cost = c.PLANT_CARD_INFO[index][c.SUN_INDEX]
@ -86,7 +88,7 @@ class Card():
image = pg.Surface((self.rect.w, self.rect.h)) # 黑底
frozen_image = self.orig_image
frozen_image.set_alpha(128)
frozen_height = (self.frozen_time - time)/self.frozen_time * self.rect.h
frozen_height = ((self.frozen_time - time)/self.frozen_time) * self.rect.h
image.blit(frozen_image, (0,0), (0, 0, self.rect.w, frozen_height))
self.orig_image.set_alpha(192)
@ -177,8 +179,8 @@ class MenuBar():
def checkMenuBarClick(self, mouse_pos):
x, y = mouse_pos
if (x >= self.rect.x and x <= self.rect.right and
y >= self.rect.y and y <= self.rect.bottom):
if (self.rect.x <= x <= self.rect.right and
self.rect.y <= y <= self.rect.bottom):
return True
return False
@ -299,8 +301,8 @@ class Panel():
return False
x, y = mouse_pos
if (x >= self.button_rect.x and x <= self.button_rect.right and
y >= self.button_rect.y and y <= self.button_rect.bottom):
if (self.button_rect.x <= x <= self.button_rect.right and
self.button_rect.y <= y <= self.button_rect.bottom):
return True
return False
@ -349,8 +351,8 @@ class MoveCard():
def checkMouseClick(self, mouse_pos):
x, y = mouse_pos
if (x >= self.rect.x and x <= self.rect.right and
y >= self.rect.y and y <= self.rect.bottom):
if (self.rect.x <= x <= self.rect.right and
self.rect.y <= y <= self.rect.bottom):
return True
return False
@ -426,7 +428,7 @@ class MoveBar():
card.update(left_x, self.current_time)
left_x = card.rect.right + 1
if(self.current_time - self.create_timer) > c.MOVEBAR_CARD_FRESH_TIME:
if (self.current_time - self.create_timer) > c.MOVEBAR_CARD_FRESH_TIME:
if self.createCard():
self.create_timer = self.current_time
@ -440,8 +442,8 @@ class MoveBar():
def checkMenuBarClick(self, mouse_pos):
x, y = mouse_pos
if (x >= self.rect.x and x <= self.rect.right and
y >= self.rect.y and y <= self.rect.bottom):
if (self.rect.x <= x <= self.rect.right and
self.rect.y <= y <= self.rect.bottom):
return True
return False

View File

@ -178,9 +178,12 @@ class Fume(pg.sprite.Sprite):
# 杨桃的子弹
class StarBullet(Bullet):
def __init__(self, x, start_y, damage, direction, level, damage_type = c.ZOMBIE_DEAFULT_DAMAGE): # direction指星星飞行方向
Bullet.__init__(self, x, start_y, start_y, c.BULLET_STAR, damage, damage_type = damage_type)
def __init__( self, x, start_y,
damage, direction,
level, damage_type = c.ZOMBIE_DEAFULT_DAMAGE): # direction指星星飞行方向
Bullet.__init__( self, x, start_y,
start_y, c.BULLET_STAR,
damage, damage_type = damage_type)
self.level = level
self.map_y = self.level.map.getMapIndex(self.rect.x, self.rect.centery)[1]
self.direction = direction
@ -394,7 +397,8 @@ class SunFlower(Plant):
self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000)
elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL:
self.sun_group.add(
Sun(self.rect.centerx, self.rect.bottom, self.rect.right, self.rect.bottom + self.rect.h // 2))
Sun( self.rect.centerx, self.rect.bottom,
self.rect.right, self.rect.bottom + self.rect.h // 2))
self.sun_timer = self.current_time
@ -697,8 +701,9 @@ class PuffShroom(Plant):
def canAttack(self, zombie):
if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False
if (self.rect.x <= zombie.rect.right and
(self.rect.x + c.GRID_X_SIZE * 4 >= zombie.rect.x) and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
if (self.rect.x <= zombie.rect.right
and (self.rect.x + c.GRID_X_SIZE * 4 >= zombie.rect.x)
and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
return True
return False
@ -796,7 +801,8 @@ class Squash(Plant):
return True
# 攻击状态
elif (self.state == c.ATTACK):
if pg.sprite.collide_rect_ratio(0.5)(zombie, self) or pg.sprite.collide_mask(zombie, self):
if (pg.sprite.collide_rect_ratio(0.5)(zombie, self)
or pg.sprite.collide_mask(zombie, self)):
return True
return False
@ -844,9 +850,12 @@ class Spikeweed(Plant):
self.state = c.IDLE
def canAttack(self, zombie):
# 地刺能不能扎的判据:僵尸中心与地刺中心的距离或僵尸包括了地刺中心和右端(平衡得到合理的攻击范围,"僵尸包括了地刺中心和右端"是为以后巨人做准备)
# 地刺能不能扎的判据:
# 僵尸中心与地刺中心的距离或僵尸包括了地刺中心和右端(平衡得到合理的攻击范围,"僵尸包括了地刺中心和右端"是为以后巨人做准备)
# 暂时不能用碰撞判断,平衡性不好
if ((-40 <= zombie.rect.centerx - self.rect.centerx <= 40) or (zombie.rect.left <= self.rect.x <= zombie.rect.right and zombie.rect.left <= self.rect.right <= zombie.rect.right)):
if ((-40 <= zombie.rect.centerx - self.rect.centerx <= 40)
or (zombie.rect.left <= self.rect.x <= zombie.rect.right
and zombie.rect.left <= self.rect.right <= zombie.rect.right)):
return True
return False
@ -1050,8 +1059,10 @@ class IceShroom(Plant):
sleep_name = name + "Sleep"
trap_name = name + "Trap"
frame_list = [self.idle_frames, self.snow_frames, self.sleep_frames, self.trap_frames]
name_list = [idle_name, snow_name, sleep_name, trap_name]
frame_list = [ self.idle_frames, self.snow_frames,
self.sleep_frames, self.trap_frames]
name_list = [ idle_name, snow_name,
sleep_name, trap_name]
scale_list = [1, 1.5, 1, 1]
for i, name in enumerate(name_list):
@ -1308,13 +1319,17 @@ class StarFruit(Plant):
zombie_map_y = self.level.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom)[1]
if (self.rect.x >= zombie.rect.x) and (self.map_y == zombie_map_y): # 对于同行且在杨桃后的僵尸
return True
# 斜向上理想直线方程为f(zombie.rect.x) = -0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10
# 斜向上,理想直线方程为:
# f(zombie.rect.x) = -0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10
# 注意实际上为射线
elif -100 <= (zombie.rect.y - (-0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10)) <= 70 and (zombie.rect.left <= c.SCREEN_WIDTH) and (zombie.rect.x >= self.rect.x):
elif (-100 <= (zombie.rect.y - (-0.75*(zombie.rect.x - (self.rect.right - 5)) + self.rect.y - 10)) <= 70
and (zombie.rect.left <= c.SCREEN_WIDTH) and (zombie.rect.x >= self.rect.x)):
return True
# 斜向下理想直线方程为f(zombie.rect.x) = zombie.rect.x + self.rect.y - self.rect.right - 15
# 注意实际上为射线
elif abs(zombie.rect.y - (zombie.rect.x + self.rect.y - self.rect.right - 15)) <= 70 and (zombie.rect.left <= c.SCREEN_WIDTH) and (zombie.rect.x >= self.rect.x):
elif (abs(zombie.rect.y - (zombie.rect.x + self.rect.y - self.rect.right - 15)) <= 70
and (zombie.rect.left <= c.SCREEN_WIDTH)
and (zombie.rect.x >= self.rect.x)):
return True
elif zombie.rect.left <= self.rect.x <= zombie.rect.right:
return True
@ -1324,13 +1339,23 @@ class StarFruit(Plant):
if self.shoot_timer == 0:
self.shoot_timer = self.current_time - 700
elif (self.current_time - self.shoot_timer) >= 1400:
# 向后打的杨桃子弹无视铁门与报纸防具
self.bullet_group.add(StarBullet(self.rect.left - 10, self.rect.y + 15, c.BULLET_DAMAGE_NORMAL, c.STAR_BACKWARD, self.level, damage_type = c.ZOMBIE_COMMON_DAMAGE))
# pypvz特有设定向后打的杨桃子弹无视铁门与报纸防具
self.bullet_group.add(StarBullet( self.rect.left - 10, self.rect.y + 15,
c.BULLET_DAMAGE_NORMAL, c.STAR_BACKWARD,
self.level, damage_type = c.ZOMBIE_COMMON_DAMAGE))
# 其他方向的杨桃子弹伤害效果与豌豆等同
self.bullet_group.add(StarBullet(self.rect.centerx - 20, self.rect.bottom - self.rect.h - 15, c.BULLET_DAMAGE_NORMAL, c.STAR_UPWARD, self.level))
self.bullet_group.add(StarBullet(self.rect.centerx - 20, self.rect.bottom - 5, c.BULLET_DAMAGE_NORMAL, c.STAR_DOWNWARD, self.level))
self.bullet_group.add(StarBullet(self.rect.right - 5, self.rect.bottom - 20, c.BULLET_DAMAGE_NORMAL, c.STAR_FORWARD_DOWN, self.level))
self.bullet_group.add(StarBullet(self.rect.right - 5, self.rect.y - 10, c.BULLET_DAMAGE_NORMAL, c.STAR_FORWARD_UP, self.level))
self.bullet_group.add(StarBullet( self.rect.centerx - 20, self.rect.bottom - self.rect.h - 15,
c.BULLET_DAMAGE_NORMAL, c.STAR_UPWARD,
self.level))
self.bullet_group.add(StarBullet( self.rect.centerx - 20, self.rect.bottom - 5,
c.BULLET_DAMAGE_NORMAL, c.STAR_DOWNWARD,
self.level))
self.bullet_group.add(StarBullet( self.rect.right - 5, self.rect.bottom - 20,
c.BULLET_DAMAGE_NORMAL, c.STAR_FORWARD_DOWN,
self.level))
self.bullet_group.add(StarBullet( self.rect.right - 5, self.rect.y - 10,
c.BULLET_DAMAGE_NORMAL, c.STAR_FORWARD_UP,
self.level))
self.shoot_timer = self.current_time
# 播放发射音效
c.SOUND_SHOOT.play()
@ -1358,8 +1383,8 @@ class CoffeeBean(Plant):
for plant in self.plant_group:
if plant.can_sleep:
if plant.state == c.SLEEP:
plantMapX, _ = self.map.getMapIndex(plant.rect.centerx, plant.rect.bottom)
if plantMapX == self.map_x:
plant_map_x, _ = self.map.getMapIndex(plant.rect.centerx, plant.rect.bottom)
if plant_map_x == self.map_x:
plant.state = c.IDLE
plant.setIdle()
plant.changeFrames(plant.idle_frames)
@ -1415,8 +1440,9 @@ class SeaShroom(Plant):
def canAttack(self, zombie):
if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False
if (self.rect.x <= zombie.rect.right and
(self.rect.x + c.GRID_X_SIZE * 4 >= zombie.rect.x) and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
if (self.rect.x <= zombie.rect.right
and (self.rect.x + c.GRID_X_SIZE * 4 >= zombie.rect.x)
and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
return True
return False
@ -1706,8 +1732,9 @@ class FumeShroom(Plant):
def canAttack(self, zombie):
if (zombie.name == c.SNORKELZOMBIE) and (zombie.frames == zombie.swim_frames):
return False
if (self.rect.x <= zombie.rect.right and
(self.rect.x + c.GRID_X_SIZE * 5 >= zombie.rect.x) and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
if (self.rect.x <= zombie.rect.right
and (self.rect.x + c.GRID_X_SIZE * 5 >= zombie.rect.x)
and (zombie.rect.left <= c.SCREEN_WIDTH + 10)):
return True
return False

View File

@ -26,6 +26,7 @@ class Level(tool.State):
# 导入地图参数
self.loadMap()
self.map = map.Map(self.map_data[c.BACKGROUND_TYPE])
self.map_x_len = self.map.width
self.map_y_len = self.map.height
self.setupBackground()
self.initState()
@ -101,7 +102,7 @@ class Level(tool.State):
# 按照规则生成每一波僵尸
# 可以考虑将波刷新和一波中的僵尸生成分开
# 将波刷新和一波中的僵尸生成分开
# useableZombie是指可用的僵尸种类的元组
# inevitableZombie指在本轮必然出现的僵尸输入形式为字典: {波数1:(僵尸1, 僵尸2……), 波数2:(僵尸1, 僵尸2……)……}
def createWaves(self, useable_zombies, num_flags, survival_rounds=0, inevitable_zombie_dict=None):
@ -1115,7 +1116,8 @@ class Level(tool.State):
zombie.health = 0
c.SOUND_BOWLING_IMPACT.play()
elif not zombie.jumping:
zombie.jump_map_x, zombie.jump_map_y = min(c.GRID_X_LEN - 1, zombie.prey_map_x), min(self.map_y_len - 1, zombie.prey_map_y)
zombie.jump_map_x = min(self.map_x_len - 1, zombie.prey_map_x)
zombie.jump_map_y = min(self.map_y_len - 1, zombie.prey_map_y)
jump_x = target_plant.rect.x - c.GRID_X_SIZE * 0.6
if c.TALLNUT in self.map.map[zombie.jump_map_y][zombie.jump_map_x][c.MAP_PLANT]:
zombie.setJump(False, jump_x)