Merge branch 'master' into opengl
This commit is contained in:
commit
f3a47a9a1e
BIN
resources/graphics/Cards/card_giantwallnut.png
Normal file
BIN
resources/graphics/Cards/card_giantwallnut.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
resources/sound/helpScreen.ogg
Executable file
BIN
resources/sound/helpScreen.ogg
Executable file
Binary file not shown.
@ -179,6 +179,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第0关:测试模式地图
|
# 第0关:测试模式地图
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "隐藏测试关卡",
|
||||||
c.INIT_SUN_NAME: 5000,
|
c.INIT_SUN_NAME: 5000,
|
||||||
c.SHOVEL: 1,
|
c.SHOVEL: 1,
|
||||||
c.SPAWN_ZOMBIES: c.SPAWN_ZOMBIES_LIST,
|
c.SPAWN_ZOMBIES: c.SPAWN_ZOMBIES_LIST,
|
||||||
@ -203,6 +204,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第1关:单行草皮
|
# 第1关:单行草皮
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 7,
|
c.BACKGROUND_TYPE: 7,
|
||||||
|
c.GAME_TITLE: "白天 1-1",
|
||||||
c.INIT_SUN_NAME: 150,
|
c.INIT_SUN_NAME: 150,
|
||||||
c.SHOVEL: 1,
|
c.SHOVEL: 1,
|
||||||
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
@ -212,6 +214,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第2关:三行草皮
|
# 第2关:三行草皮
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 8,
|
c.BACKGROUND_TYPE: 8,
|
||||||
|
c.GAME_TITLE: "白天 1-2",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -221,6 +224,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第3关
|
# 第3关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 0,
|
c.BACKGROUND_TYPE: 0,
|
||||||
|
c.GAME_TITLE: "白天 1-3",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -230,6 +234,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第4关
|
# 第4关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 0,
|
c.BACKGROUND_TYPE: 0,
|
||||||
|
c.GAME_TITLE: "白天 1-4",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -239,6 +244,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第5关 目前白天最后一关
|
# 第5关 目前白天最后一关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 0,
|
c.BACKGROUND_TYPE: 0,
|
||||||
|
c.GAME_TITLE: "白天 1-5",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -248,6 +254,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第6关 目前夜晚第一关
|
# 第6关 目前夜晚第一关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 1,
|
c.BACKGROUND_TYPE: 1,
|
||||||
|
c.GAME_TITLE: "黑夜 2-1",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -258,6 +265,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第7关
|
# 第7关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 1,
|
c.BACKGROUND_TYPE: 1,
|
||||||
|
c.GAME_TITLE: "黑夜 2-2",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -269,6 +277,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第8关 目前为夜晚最后一关
|
# 第8关 目前为夜晚最后一关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 1,
|
c.BACKGROUND_TYPE: 1,
|
||||||
|
c.GAME_TITLE: "黑夜 2-3",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -287,6 +296,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第9关 目前为泳池模式第一关
|
# 第9关 目前为泳池模式第一关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "泳池 3-1",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -297,6 +307,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第10关
|
# 第10关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "泳池 3-2",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -308,6 +319,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第11关
|
# 第11关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "泳池 3-3",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -318,6 +330,7 @@ LEVEL_MAP_DATA = (
|
|||||||
# 第12关 目前为泳池最后一关
|
# 第12关 目前为泳池最后一关
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "泳池 3-4",
|
||||||
c.INIT_SUN_NAME: 50,
|
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,
|
||||||
@ -329,13 +342,14 @@ LEVEL_MAP_DATA = (
|
|||||||
},
|
},
|
||||||
# 第13关 目前为浓雾第一关 尚未完善
|
# 第13关 目前为浓雾第一关 尚未完善
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 3,
|
||||||
|
c.GAME_TITLE: "浓雾 4-1",
|
||||||
c.INIT_SUN_NAME: 50,
|
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.NEWSPAPER_ZOMBIE,
|
c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.NEWSPAPER_ZOMBIE,
|
||||||
c.ZOMBONI, c.FOOTBALL_ZOMBIE,
|
c.ZOMBONI, c.FOOTBALL_ZOMBIE,
|
||||||
c.CONEHEAD_ZOMBIE, c.BUCKETHEAD_HEALTH),
|
c.CONEHEAD_ZOMBIE, c.BUCKETHEAD_ZOMBIE),
|
||||||
c.NUM_FLAGS:4
|
c.NUM_FLAGS:4
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -344,24 +358,36 @@ LEVEL_MAP_DATA = (
|
|||||||
|
|
||||||
# 玩玩小游戏地图
|
# 玩玩小游戏地图
|
||||||
LITTLE_GAME_MAP_DATA = (
|
LITTLE_GAME_MAP_DATA = (
|
||||||
# 第0关 测试 目前空缺
|
# 第0关 测试
|
||||||
{},
|
{
|
||||||
|
c.BACKGROUND_TYPE: 6,
|
||||||
|
c.GAME_TITLE: "隐藏测试关卡",
|
||||||
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_BOWLING,
|
||||||
|
c.SHOVEL: 0,
|
||||||
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
|
c.INCLUDED_ZOMBIES: ( c.POLE_VAULTING_ZOMBIE,),
|
||||||
|
c.NUM_FLAGS:1,
|
||||||
|
c.CARD_POOL: { c.WALLNUTBOWLING: 0,
|
||||||
|
c.REDWALLNUTBOWLING: 0,
|
||||||
|
c.GIANTWALLNUT:100,}
|
||||||
|
},
|
||||||
# 第1关 坚果保龄球
|
# 第1关 坚果保龄球
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 6,
|
c.BACKGROUND_TYPE: 6,
|
||||||
|
c.GAME_TITLE: "坚果保龄球",
|
||||||
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_BOWLING,
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_BOWLING,
|
||||||
c.SHOVEL: 0,
|
c.SHOVEL: 0,
|
||||||
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.CONEHEAD_ZOMBIE,
|
c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.CONEHEAD_ZOMBIE,
|
||||||
c.POLE_VAULTING_ZOMBIE, c.BUCKETHEAD_ZOMBIE,
|
c.POLE_VAULTING_ZOMBIE, c.BUCKETHEAD_ZOMBIE,),
|
||||||
c.NEWSPAPER_ZOMBIE),
|
c.NUM_FLAGS:2,
|
||||||
c.NUM_FLAGS:3,
|
|
||||||
c.CARD_POOL: { c.WALLNUTBOWLING: 300,
|
c.CARD_POOL: { c.WALLNUTBOWLING: 300,
|
||||||
c.REDWALLNUTBOWLING: 100,}
|
c.REDWALLNUTBOWLING: 100,}
|
||||||
},
|
},
|
||||||
# 第2关 白天 大决战
|
# 第2关 白天 大决战
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 0,
|
c.BACKGROUND_TYPE: 0,
|
||||||
|
c.GAME_TITLE: "大决战(白天)",
|
||||||
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
||||||
c.SHOVEL: 1,
|
c.SHOVEL: 1,
|
||||||
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
@ -379,6 +405,7 @@ LITTLE_GAME_MAP_DATA = (
|
|||||||
# 第3关 夜晚 大决战
|
# 第3关 夜晚 大决战
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 1,
|
c.BACKGROUND_TYPE: 1,
|
||||||
|
c.GAME_TITLE: "大决战(黑夜)",
|
||||||
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
||||||
c.SHOVEL: 1,
|
c.SHOVEL: 1,
|
||||||
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
@ -398,6 +425,7 @@ LITTLE_GAME_MAP_DATA = (
|
|||||||
# 第4关 泳池 大决战
|
# 第4关 泳池 大决战
|
||||||
{
|
{
|
||||||
c.BACKGROUND_TYPE: 2,
|
c.BACKGROUND_TYPE: 2,
|
||||||
|
c.GAME_TITLE: "大决战(泳池)",
|
||||||
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE,
|
||||||
c.SHOVEL: 1,
|
c.SHOVEL: 1,
|
||||||
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
@ -414,6 +442,21 @@ LITTLE_GAME_MAP_DATA = (
|
|||||||
c.JALAPENO: 50,
|
c.JALAPENO: 50,
|
||||||
c.THREEPEASHOOTER: 300,}
|
c.THREEPEASHOOTER: 300,}
|
||||||
},
|
},
|
||||||
|
# 第5关 坚果保龄球2
|
||||||
|
{
|
||||||
|
c.BACKGROUND_TYPE: 6,
|
||||||
|
c.GAME_TITLE: "坚果保龄球(II)",
|
||||||
|
c.CHOOSEBAR_TYPE: c.CHOOSEBAR_BOWLING,
|
||||||
|
c.SHOVEL: 0,
|
||||||
|
c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO,
|
||||||
|
c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.CONEHEAD_ZOMBIE,
|
||||||
|
c.POLE_VAULTING_ZOMBIE, c.BUCKETHEAD_ZOMBIE,
|
||||||
|
c.NEWSPAPER_ZOMBIE, c.SCREEN_DOOR_ZOMBIE),
|
||||||
|
c.NUM_FLAGS:3,
|
||||||
|
c.CARD_POOL: { c.WALLNUTBOWLING: 500,
|
||||||
|
c.REDWALLNUTBOWLING: 100,
|
||||||
|
c.GIANTWALLNUT:100,}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# 总关卡数
|
# 总关卡数
|
||||||
|
|||||||
@ -86,6 +86,9 @@ class Card():
|
|||||||
time = current_time - self.frozen_timer
|
time = current_time - self.frozen_timer
|
||||||
if time < self.frozen_time: #cool down status
|
if time < self.frozen_time: #cool down status
|
||||||
image = pg.Surface([self.rect.w, self.rect.h])
|
image = pg.Surface([self.rect.w, self.rect.h])
|
||||||
|
# 在冷却时间不足且阳光也不足时,叠加两者效果显示,即同时改变透明度与图像覆盖
|
||||||
|
if self.sun_cost > sun_value:
|
||||||
|
image.set_alpha(192)
|
||||||
frozen_image = self.orig_image.copy()
|
frozen_image = self.orig_image.copy()
|
||||||
frozen_image.set_alpha(128)
|
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
|
||||||
|
|||||||
@ -22,8 +22,8 @@ class Car(pg.sprite.Sprite):
|
|||||||
def update(self, game_info):
|
def update(self, game_info):
|
||||||
self.current_time = game_info[c.CURRENT_TIME]
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
if self.state == c.WALK:
|
if self.state == c.WALK:
|
||||||
self.rect.x += 4
|
self.rect.x += 5
|
||||||
if self.rect.x > c.SCREEN_WIDTH + 60:
|
if self.rect.x > c.SCREEN_WIDTH + 25:
|
||||||
self.dead = True
|
self.dead = True
|
||||||
|
|
||||||
def setWalk(self):
|
def setWalk(self):
|
||||||
@ -39,7 +39,7 @@ 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,
|
def __init__( self, x, start_y, dest_y, name, damage,
|
||||||
effect=None, passed_torchwood_x=None,
|
effect=None, passed_torchwood_x=None,
|
||||||
damageType=c.ZOMBIE_DEAFULT_DAMAGE):
|
damage_type=c.ZOMBIE_DEAFULT_DAMAGE):
|
||||||
pg.sprite.Sprite.__init__(self)
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -56,7 +56,7 @@ class Bullet(pg.sprite.Sprite):
|
|||||||
self.y_vel = 15 if (dest_y > start_y) else -15
|
self.y_vel = 15 if (dest_y > start_y) else -15
|
||||||
self.x_vel = 10
|
self.x_vel = 10
|
||||||
self.damage = damage
|
self.damage = damage
|
||||||
self.damageType = damageType
|
self.damage_type = damage_type
|
||||||
self.effect = effect
|
self.effect = effect
|
||||||
self.state = c.FLY
|
self.state = c.FLY
|
||||||
self.current_time = 0
|
self.current_time = 0
|
||||||
@ -82,14 +82,8 @@ class Bullet(pg.sprite.Sprite):
|
|||||||
self.explode_frames = []
|
self.explode_frames = []
|
||||||
|
|
||||||
fly_name = self.name
|
fly_name = self.name
|
||||||
if self.name == c.BULLET_MUSHROOM:
|
if self.name in c.BULLET_INDEPENDENT_BOOM_IMG:
|
||||||
explode_name = "BulletMushRoomExplode"
|
explode_name = f"{self.name}Explode"
|
||||||
elif self.name == c.BULLET_PEA_ICE:
|
|
||||||
explode_name = "PeaIceExplode"
|
|
||||||
elif self.name == c.BULLET_SEASHROOM:
|
|
||||||
explode_name = "BulletSeaShroomExplode"
|
|
||||||
elif self.name == c.BULLET_STAR:
|
|
||||||
explode_name = "StarBulletExplode"
|
|
||||||
else:
|
else:
|
||||||
explode_name = "PeaNormalExplode"
|
explode_name = "PeaNormalExplode"
|
||||||
|
|
||||||
@ -184,8 +178,8 @@ class Fume(pg.sprite.Sprite):
|
|||||||
|
|
||||||
# 杨桃的子弹
|
# 杨桃的子弹
|
||||||
class StarBullet(Bullet):
|
class StarBullet(Bullet):
|
||||||
def __init__(self, x, start_y, damage, direction, level, damageType = c.ZOMBIE_DEAFULT_DAMAGE): # direction指星星飞行方向
|
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, damageType = damageType)
|
Bullet.__init__(self, x, start_y, start_y, c.BULLET_STAR, damage, damage_type = damage_type)
|
||||||
|
|
||||||
self.level = level
|
self.level = level
|
||||||
self.map_y = self.level.map.getMapIndex(self.rect.x, self.rect.centery)[1]
|
self.map_y = self.level.map.getMapIndex(self.rect.x, self.rect.centery)[1]
|
||||||
@ -647,9 +641,12 @@ class Chomper(Plant):
|
|||||||
|
|
||||||
def attacking(self):
|
def attacking(self):
|
||||||
if self.frame_index == (self.frame_num - 3):
|
if self.frame_index == (self.frame_num - 3):
|
||||||
# 播放吞的音效
|
# 对活着的僵尸才需要吞下去消化
|
||||||
c.SOUND_BIGCHOMP.play()
|
|
||||||
if self.attack_zombie.alive():
|
if self.attack_zombie.alive():
|
||||||
|
if not self.should_diggest:
|
||||||
|
# 播放吞的音效 由于一帧在这个循环中执行了若干次,可能被设置播放若干次导致声音重叠,所以用if保护
|
||||||
|
# 在尚未检测到需要消化时播放音效
|
||||||
|
c.SOUND_BIGCHOMP.play()
|
||||||
self.should_diggest = 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:
|
||||||
@ -816,7 +813,7 @@ class Squash(Plant):
|
|||||||
if (self.frame_index + 1) == self.frame_num:
|
if (self.frame_index + 1) == self.frame_num:
|
||||||
for zombie in self.zombie_group:
|
for zombie in self.zombie_group:
|
||||||
if self.canAttack(zombie):
|
if self.canAttack(zombie):
|
||||||
zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE)
|
zombie.setDamage(1800, damage_type=c.ZOMBIE_RANGE_DAMAGE)
|
||||||
self.health = 0 # 避免僵尸在原位啃食
|
self.health = 0 # 避免僵尸在原位啃食
|
||||||
self.map_plant_set.remove(c.SQUASH)
|
self.map_plant_set.remove(c.SQUASH)
|
||||||
self.kill()
|
self.kill()
|
||||||
@ -875,7 +872,7 @@ class Spikeweed(Plant):
|
|||||||
zombie.health = zombie.losthead_health
|
zombie.health = zombie.losthead_health
|
||||||
killSelf = True
|
killSelf = True
|
||||||
else:
|
else:
|
||||||
zombie.setDamage(20, damageType=c.ZOMBIE_COMMON_DAMAGE)
|
zombie.setDamage(20, damage_type=c.ZOMBIE_COMMON_DAMAGE)
|
||||||
if killSelf:
|
if killSelf:
|
||||||
self.health = 0
|
self.health = 0
|
||||||
# 播放攻击音效,同子弹打击
|
# 播放攻击音效,同子弹打击
|
||||||
@ -1158,7 +1155,7 @@ class WallNutBowling(Plant):
|
|||||||
self.handleMapYPosition()
|
self.handleMapYPosition()
|
||||||
if self.shouldChangeDirection():
|
if self.shouldChangeDirection():
|
||||||
self.changeDirection(-1)
|
self.changeDirection(-1)
|
||||||
if self.init_rect.x > c.SCREEN_WIDTH + 60:
|
if self.init_rect.x > c.SCREEN_WIDTH + 25:
|
||||||
self.health = 0
|
self.health = 0
|
||||||
self.move_timer += self.move_interval
|
self.move_timer += self.move_interval
|
||||||
|
|
||||||
@ -1200,12 +1197,6 @@ class WallNutBowling(Plant):
|
|||||||
self.disable_hit_y = map_y
|
self.disable_hit_y = map_y
|
||||||
|
|
||||||
def animation(self):
|
def animation(self):
|
||||||
if (self.current_time - self.animate_timer) > self.animate_interval:
|
|
||||||
self.frame_index += 1
|
|
||||||
if self.frame_index >= self.frame_num:
|
|
||||||
self.frame_index = 0
|
|
||||||
self.animate_timer = self.current_time
|
|
||||||
|
|
||||||
image = self.frames[self.frame_index]
|
image = self.frames[self.frame_index]
|
||||||
self.image = pg.transform.rotate(image, self.rotate_degree)
|
self.image = pg.transform.rotate(image, self.rotate_degree)
|
||||||
self.mask = pg.mask.from_surface(self.image)
|
self.mask = pg.mask.from_surface(self.image)
|
||||||
@ -1246,7 +1237,7 @@ class RedWallNutBowling(Plant):
|
|||||||
elif (self.current_time - self.move_timer) >= self.move_interval:
|
elif (self.current_time - self.move_timer) >= self.move_interval:
|
||||||
self.rotate_degree = (self.rotate_degree - 30) % 360
|
self.rotate_degree = (self.rotate_degree - 30) % 360
|
||||||
self.init_rect.x += self.vel_x
|
self.init_rect.x += self.vel_x
|
||||||
if self.init_rect.x > c.SCREEN_WIDTH + 60:
|
if self.init_rect.x > c.SCREEN_WIDTH + 25:
|
||||||
self.health = 0
|
self.health = 0
|
||||||
self.move_timer += self.move_interval
|
self.move_timer += self.move_interval
|
||||||
|
|
||||||
@ -1333,7 +1324,7 @@ class StarFruit(Plant):
|
|||||||
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.bullet_group.add(StarBullet(self.rect.left - 10, self.rect.y + 15, c.BULLET_DAMAGE_NORMAL, c.STAR_BACKWARD, self.level, damageType = c.ZOMBIE_COMMON_DAMAGE))
|
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 - 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.centerx - 20, self.rect.bottom - 5, c.BULLET_DAMAGE_NORMAL, c.STAR_DOWNWARD, self.level))
|
||||||
@ -1737,7 +1728,7 @@ class FumeShroom(Plant):
|
|||||||
# 烟雾只是个动画,实际伤害由本身完成
|
# 烟雾只是个动画,实际伤害由本身完成
|
||||||
for target_zombie in self.zombie_group:
|
for target_zombie in self.zombie_group:
|
||||||
if self.canAttack(target_zombie):
|
if self.canAttack(target_zombie):
|
||||||
target_zombie.setDamage(c.BULLET_DAMAGE_NORMAL, damageType=c.ZOMBIE_RANGE_DAMAGE)
|
target_zombie.setDamage(c.BULLET_DAMAGE_NORMAL, damage_type=c.ZOMBIE_RANGE_DAMAGE)
|
||||||
self.shoot_timer = self.current_time
|
self.shoot_timer = self.current_time
|
||||||
self.show_attack_frames = True
|
self.show_attack_frames = True
|
||||||
# 播放发射音效
|
# 播放发射音效
|
||||||
@ -1826,3 +1817,31 @@ class PumpkinHead(Plant):
|
|||||||
elif not self.cracked2 and self.health <= c.WALLNUT_CRACKED2_HEALTH:
|
elif not self.cracked2 and self.health <= c.WALLNUT_CRACKED2_HEALTH:
|
||||||
self.changeFrames(self.cracked2_frames)
|
self.changeFrames(self.cracked2_frames)
|
||||||
self.cracked2 = True
|
self.cracked2 = True
|
||||||
|
|
||||||
|
|
||||||
|
class GiantWallNut(Plant):
|
||||||
|
def __init__(self, x, y):
|
||||||
|
Plant.__init__(self, x, y, c.GIANTWALLNUT, 1, None)
|
||||||
|
self.init_rect = self.rect.copy()
|
||||||
|
self.rotate_degree = 0
|
||||||
|
self.animate_interval = 200
|
||||||
|
self.move_timer = 0
|
||||||
|
self.move_interval = 70
|
||||||
|
self.vel_x = random.randint(15, 18)
|
||||||
|
|
||||||
|
def idling(self):
|
||||||
|
if self.move_timer == 0:
|
||||||
|
self.move_timer = self.current_time
|
||||||
|
elif (self.current_time - self.move_timer) >= self.move_interval:
|
||||||
|
self.rotate_degree = (self.rotate_degree - 30) % 360
|
||||||
|
self.init_rect.x += self.vel_x
|
||||||
|
if self.init_rect.x > c.SCREEN_WIDTH:
|
||||||
|
self.health = 0
|
||||||
|
self.move_timer += self.move_interval
|
||||||
|
|
||||||
|
def animation(self):
|
||||||
|
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)
|
||||||
|
|||||||
@ -346,23 +346,23 @@ class Zombie(pg.sprite.Sprite):
|
|||||||
if (self.current_time - self.ice_slow_timer) > c.ICE_SLOW_TIME:
|
if (self.current_time - self.ice_slow_timer) > c.ICE_SLOW_TIME:
|
||||||
self.ice_slow_ratio = 1
|
self.ice_slow_ratio = 1
|
||||||
|
|
||||||
def setDamage(self, damage, effect=None, damageType=c.ZOMBIE_COMMON_DAMAGE):
|
def setDamage(self, damage, effect=None, damage_type=c.ZOMBIE_COMMON_DAMAGE):
|
||||||
# 冰冻减速效果
|
# 冰冻减速效果
|
||||||
if effect == c.BULLET_EFFECT_ICE:
|
if effect == c.BULLET_EFFECT_ICE:
|
||||||
if damageType == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速
|
if damage_type == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速
|
||||||
if not self.helmet_type2:
|
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 damage_type == c.ZOMBIE_DEAFULT_DAMAGE: # 寒冰射手不能穿透二类防具进行减速
|
||||||
if not self.helmet_type2:
|
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 damage_type == c.ZOMBIE_DEAFULT_DAMAGE: # 不穿透二类防具的攻击
|
||||||
# 从第二类防具开始逐级传递
|
# 从第二类防具开始逐级传递
|
||||||
if self.helmet_type2:
|
if self.helmet_type2:
|
||||||
self.helmet_type2_health -= damage
|
self.helmet_type2_health -= damage
|
||||||
@ -383,7 +383,7 @@ class Zombie(pg.sprite.Sprite):
|
|||||||
self.helmet_health = 0 # 注意合并后清零
|
self.helmet_health = 0 # 注意合并后清零
|
||||||
else: # 没有防具
|
else: # 没有防具
|
||||||
self.health -= damage
|
self.health -= damage
|
||||||
elif damageType == c.ZOMBIE_COMMON_DAMAGE: # 无视二类防具,将攻击一类防具与本体视为整体的攻击
|
elif damage_type == c.ZOMBIE_COMMON_DAMAGE: # 无视二类防具,将攻击一类防具与本体视为整体的攻击
|
||||||
if self.helmet: # 存在一类防具
|
if self.helmet: # 存在一类防具
|
||||||
self.helmet_health -= damage
|
self.helmet_health -= damage
|
||||||
if self.helmet_health <= 0:
|
if self.helmet_health <= 0:
|
||||||
@ -391,7 +391,7 @@ class Zombie(pg.sprite.Sprite):
|
|||||||
self.helmet_health = 0 # 注意合并后清零
|
self.helmet_health = 0 # 注意合并后清零
|
||||||
else: # 没有一类防具
|
else: # 没有一类防具
|
||||||
self.health -= damage
|
self.health -= damage
|
||||||
elif damageType == c.ZOMBIE_RANGE_DAMAGE:
|
elif damage_type == c.ZOMBIE_RANGE_DAMAGE:
|
||||||
# 从第二类防具开始逐级传递
|
# 从第二类防具开始逐级传递
|
||||||
if self.helmet_type2:
|
if self.helmet_type2:
|
||||||
self.helmet_type2_health -= damage
|
self.helmet_type2_health -= damage
|
||||||
@ -422,9 +422,9 @@ class Zombie(pg.sprite.Sprite):
|
|||||||
self.helmet_health = 0 # 注意合并后清零
|
self.helmet_health = 0 # 注意合并后清零
|
||||||
else: # 没有防具
|
else: # 没有防具
|
||||||
self.health -= damage
|
self.health -= damage
|
||||||
elif damageType == c.ZOMBIE_ASH_DAMAGE:
|
elif damage_type == c.ZOMBIE_ASH_DAMAGE:
|
||||||
self.health -= damage # 无视任何防具
|
self.health -= damage # 无视任何防具
|
||||||
elif damageType == c.ZOMBIE_WALLNUT_BOWLING_DANMAGE:
|
elif damage_type == c.ZOMBIE_WALLNUT_BOWLING_DANMAGE:
|
||||||
# 逻辑:对防具的多余伤害不传递
|
# 逻辑:对防具的多余伤害不传递
|
||||||
if self.helmet_type2:
|
if self.helmet_type2:
|
||||||
# 对二类防具伤害较一般情况低,拟合铁门需要砸3次的设定
|
# 对二类防具伤害较一般情况低,拟合铁门需要砸3次的设定
|
||||||
@ -435,7 +435,7 @@ class Zombie(pg.sprite.Sprite):
|
|||||||
self.health -= damage
|
self.health -= damage
|
||||||
else:
|
else:
|
||||||
print("警告:植物攻击类型错误,现在默认进行类豌豆射手型攻击")
|
print("警告:植物攻击类型错误,现在默认进行类豌豆射手型攻击")
|
||||||
self.setDamage(damage, effect=effect, damageType=c.ZOMBIE_DEAFULT_DAMAGE)
|
self.setDamage(damage, effect=effect, damage_type=c.ZOMBIE_DEAFULT_DAMAGE)
|
||||||
|
|
||||||
# 记录攻击时间
|
# 记录攻击时间
|
||||||
self.hit_timer = self.current_time
|
self.hit_timer = self.current_time
|
||||||
|
|||||||
@ -126,6 +126,7 @@ BACKGROUND_NAME = "Background"
|
|||||||
BACKGROUND_TYPE = "background_type"
|
BACKGROUND_TYPE = "background_type"
|
||||||
INIT_SUN_NAME = "init_sun_value"
|
INIT_SUN_NAME = "init_sun_value"
|
||||||
ZOMBIE_LIST = "zombie_list"
|
ZOMBIE_LIST = "zombie_list"
|
||||||
|
GAME_TITLE = "title"
|
||||||
|
|
||||||
# 地图类型
|
# 地图类型
|
||||||
BACKGROUND_DAY = 0
|
BACKGROUND_DAY = 0
|
||||||
@ -359,7 +360,7 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
|
|||||||
CARD_GARLIC := "card_garlic",
|
CARD_GARLIC := "card_garlic",
|
||||||
50,
|
50,
|
||||||
7500),
|
7500),
|
||||||
# 应当保证这两个在一般模式下不可选的特殊植物恒在最后
|
# 应当保证这3个在一般模式下不可选的特殊植物恒在最后
|
||||||
(WALLNUTBOWLING := "WallNutBowling",
|
(WALLNUTBOWLING := "WallNutBowling",
|
||||||
CARD_WALLNUT := "card_wallnut",
|
CARD_WALLNUT := "card_wallnut",
|
||||||
0,
|
0,
|
||||||
@ -368,6 +369,10 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
|
|||||||
CARD_REDWALLNUT := "card_redwallnut",
|
CARD_REDWALLNUT := "card_redwallnut",
|
||||||
0,
|
0,
|
||||||
0),
|
0),
|
||||||
|
(GIANTWALLNUT := "GiantWallNut",
|
||||||
|
CARD_GIANTWALLNUT := "card_giantwallnut",
|
||||||
|
0,
|
||||||
|
0),
|
||||||
)
|
)
|
||||||
|
|
||||||
# 卡片中的植物名称与索引序号的对应关系,指定名称以得到索引值
|
# 卡片中的植物名称与索引序号的对应关系,指定名称以得到索引值
|
||||||
@ -376,7 +381,7 @@ for i, item in enumerate(PLANT_CARD_INFO):
|
|||||||
PLANT_CARD_INDEX[item[PLANT_NAME_INDEX]] = i
|
PLANT_CARD_INDEX[item[PLANT_NAME_INDEX]] = i
|
||||||
|
|
||||||
# 指定了哪些卡可选(排除坚果保龄球特殊植物)
|
# 指定了哪些卡可选(排除坚果保龄球特殊植物)
|
||||||
CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 2)
|
CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 3)
|
||||||
|
|
||||||
|
|
||||||
# 植物集体属性集合
|
# 植物集体属性集合
|
||||||
@ -408,6 +413,7 @@ PLANT_DIE_SOUND_EXCEPTIONS = {
|
|||||||
ICEFROZENPLOT, HOLE,
|
ICEFROZENPLOT, HOLE,
|
||||||
GRAVE, JALAPENO,
|
GRAVE, JALAPENO,
|
||||||
REDWALLNUTBOWLING, CHERRYBOMB,
|
REDWALLNUTBOWLING, CHERRYBOMB,
|
||||||
|
GIANTWALLNUT,
|
||||||
}
|
}
|
||||||
|
|
||||||
# 直接水生植物
|
# 直接水生植物
|
||||||
@ -426,7 +432,7 @@ PLANT_NON_CHECK_ATTACK_STATE = ( # 这里运用了集合运算
|
|||||||
SUNSHROOM, COFFEEBEAN,
|
SUNSHROOM, COFFEEBEAN,
|
||||||
GRAVEBUSTER, LILYPAD,
|
GRAVEBUSTER, LILYPAD,
|
||||||
HYPNOSHROOM, GARLIC,
|
HYPNOSHROOM, GARLIC,
|
||||||
PUMPKINHEAD,
|
PUMPKINHEAD, GIANTWALLNUT,
|
||||||
} |
|
} |
|
||||||
# 非植物类
|
# 非植物类
|
||||||
NON_PLANT_OBJECTS
|
NON_PLANT_OBJECTS
|
||||||
@ -492,6 +498,11 @@ STAR_BACKWARD = "backward" #向后
|
|||||||
STAR_UPWARD = "upward" # 向上
|
STAR_UPWARD = "upward" # 向上
|
||||||
STAR_DOWNWARD = "downward" # 向下
|
STAR_DOWNWARD = "downward" # 向下
|
||||||
|
|
||||||
|
# 有爆炸图片的子弹
|
||||||
|
BULLET_INDEPENDENT_BOOM_IMG = { BULLET_PEA, BULLET_PEA_ICE,
|
||||||
|
BULLET_MUSHROOM, BULLET_SEASHROOM,
|
||||||
|
BULLET_STAR, }
|
||||||
|
|
||||||
# 僵尸信息
|
# 僵尸信息
|
||||||
ZOMBIE_IMAGE_RECT = "zombie_image_rect"
|
ZOMBIE_IMAGE_RECT = "zombie_image_rect"
|
||||||
ZOMBIE_HEAD = "ZombieHead"
|
ZOMBIE_HEAD = "ZombieHead"
|
||||||
@ -649,6 +660,7 @@ def _getSound(filename):
|
|||||||
# 所有音效的元组,用一波海象算子表达(>= python 3.8),免得要维护两个
|
# 所有音效的元组,用一波海象算子表达(>= python 3.8),免得要维护两个
|
||||||
SOUNDS = ( # 程序交互等
|
SOUNDS = ( # 程序交互等
|
||||||
SOUND_TAPPING_CARD := _getSound("tap.ogg"),
|
SOUND_TAPPING_CARD := _getSound("tap.ogg"),
|
||||||
|
SOUND_HELP_SCREEN := _getSound("helpScreen.ogg"),
|
||||||
# 植物
|
# 植物
|
||||||
SOUND_FIREPEA_EXPLODE := _getSound("firepea.ogg"),
|
SOUND_FIREPEA_EXPLODE := _getSound("firepea.ogg"),
|
||||||
SOUND_BULLET_EXPLODE := _getSound("bulletExplode.ogg"),
|
SOUND_BULLET_EXPLODE := _getSound("bulletExplode.ogg"),
|
||||||
|
|||||||
@ -35,22 +35,24 @@ class Level(tool.State):
|
|||||||
if self.game_info[c.GAME_MODE] == c.MODE_ADVENTURE:
|
if self.game_info[c.GAME_MODE] == c.MODE_ADVENTURE:
|
||||||
if 0 <= self.game_info[c.LEVEL_NUM] < map.TOTAL_LEVEL:
|
if 0 <= self.game_info[c.LEVEL_NUM] < map.TOTAL_LEVEL:
|
||||||
self.map_data = map.LEVEL_MAP_DATA[self.game_info[c.LEVEL_NUM]]
|
self.map_data = map.LEVEL_MAP_DATA[self.game_info[c.LEVEL_NUM]]
|
||||||
pg.display.set_caption(f"pypvz: 冒险模式 第{self.game_info[c.LEVEL_NUM]}关")
|
pg.display.set_caption(f"pypvz: 冒险模式 {self.map_data[c.GAME_TITLE]}")
|
||||||
else:
|
else:
|
||||||
self.game_info[c.LEVEL_NUM] = 1
|
self.game_info[c.LEVEL_NUM] = 1
|
||||||
self.saveUserData()
|
self.saveUserData()
|
||||||
self.map_data = map.LEVEL_MAP_DATA[self.game_info[c.LEVEL_NUM]]
|
self.map_data = map.LEVEL_MAP_DATA[self.game_info[c.LEVEL_NUM]]
|
||||||
logger.warning("关卡数设定错误!进入默认的第一关!")
|
pg.display.set_caption(f"pypvz: 冒险模式 {self.map_data[c.GAME_TITLE]}")
|
||||||
|
logger.warning("关卡数设定错误!进入默认的第一关!\n")
|
||||||
# 小游戏模式
|
# 小游戏模式
|
||||||
elif self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME:
|
elif self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME:
|
||||||
if 0 <= self.game_info[c.LITTLEGAME_NUM] < map.TOTAL_LITTLE_GAME:
|
if 0 <= self.game_info[c.LITTLEGAME_NUM] < map.TOTAL_LITTLE_GAME:
|
||||||
self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]]
|
self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]]
|
||||||
pg.display.set_caption(f"pypvz: 玩玩小游戏 第{self.game_info[c.LITTLEGAME_NUM]}关")
|
pg.display.set_caption(f"pypvz: 玩玩小游戏 {self.map_data[c.GAME_TITLE]}")
|
||||||
else:
|
else:
|
||||||
self.game_info[c.LITTLEGAME_NUM] = 1
|
self.game_info[c.LITTLEGAME_NUM] = 1
|
||||||
self.saveUserData()
|
self.saveUserData()
|
||||||
self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]]
|
self.map_data = map.LITTLE_GAME_MAP_DATA[self.game_info[c.LITTLEGAME_NUM]]
|
||||||
logger.warning("关卡数设定错误!进入默认的第一关!")
|
pg.display.set_caption(f"pypvz: 冒险模式 {self.map_data[c.GAME_TITLE]}")
|
||||||
|
logger.warning("关卡数设定错误!进入默认的第一关!\n")
|
||||||
# 是否有铲子的信息:无铲子时为0,有铲子时为1,故直接赋值即可
|
# 是否有铲子的信息:无铲子时为0,有铲子时为1,故直接赋值即可
|
||||||
self.has_shovel = self.map_data[c.SHOVEL]
|
self.has_shovel = self.map_data[c.SHOVEL]
|
||||||
|
|
||||||
@ -94,7 +96,7 @@ class Level(tool.State):
|
|||||||
# 改用列表生成器直接生成内容,不再在这里使用for循环
|
# 改用列表生成器直接生成内容,不再在这里使用for循环
|
||||||
self.plant_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
self.plant_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
||||||
self.zombie_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
self.zombie_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
||||||
self.hypno_zombie_groups = [pg.sprite.Group() for i in range(self.map_y_len)] #zombies who are hypno after eating hypnoshroom
|
self.hypno_zombie_groups = [pg.sprite.Group() for i in range(self.map_y_len)] # 被魅惑的僵尸
|
||||||
self.bullet_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
self.bullet_groups = [pg.sprite.Group() for i in range(self.map_y_len)]
|
||||||
|
|
||||||
|
|
||||||
@ -102,76 +104,73 @@ class Level(tool.State):
|
|||||||
# 可以考虑将波刷新和一波中的僵尸生成分开
|
# 可以考虑将波刷新和一波中的僵尸生成分开
|
||||||
# useableZombie是指可用的僵尸种类的元组
|
# useableZombie是指可用的僵尸种类的元组
|
||||||
# inevitableZombie指在本轮必然出现的僵尸,输入形式为字典: {波数1:(僵尸1, 僵尸2……), 波数2:(僵尸1, 僵尸2……)……}
|
# inevitableZombie指在本轮必然出现的僵尸,输入形式为字典: {波数1:(僵尸1, 僵尸2……), 波数2:(僵尸1, 僵尸2……)……}
|
||||||
def createWaves(self, useableZombies, numFlags, survivalRounds=0, inevitableZombieDict=None):
|
def createWaves(self, useable_zombies, num_flags, survival_rounds=0, inevitable_zombie_dict=None):
|
||||||
|
|
||||||
waves = []
|
waves = []
|
||||||
|
|
||||||
self.numFlags = numFlags
|
self.num_flags = num_flags
|
||||||
|
|
||||||
# 权重值
|
# 权重值,c.CREATE_ZOMBIE_DICT[zombie][1]即为对应的权重
|
||||||
weights = []
|
weights = [c.CREATE_ZOMBIE_DICT[zombie][1] for zombie in useable_zombies]
|
||||||
for zombie in useableZombies:
|
|
||||||
weights.append(c.CREATE_ZOMBIE_DICT[zombie][1])
|
|
||||||
|
|
||||||
# 按照原版pvz设计的僵尸容量函数,是从无尽解析的,但是普通关卡也可以遵循
|
# 按照原版pvz设计的僵尸容量函数,是从无尽解析的,但是普通关卡也可以遵循
|
||||||
for wave in range(1, 10 * numFlags + 1):
|
for wave in range(1, 10 * num_flags + 1):
|
||||||
volume = int(int((wave + survivalRounds*20)*0.8)/2) + 1
|
zombie_volume = int(int((wave + survival_rounds*20)*0.8)/2) + 1
|
||||||
zombieList = []
|
zombie_list = []
|
||||||
|
|
||||||
# 大波僵尸情况
|
# 大波僵尸情况
|
||||||
if wave % 10 == 0:
|
if wave % 10 == 0:
|
||||||
# 容量增大至2.5倍
|
# 容量增大至2.5倍
|
||||||
volume = int(volume*2.5)
|
zombie_volume = int(zombie_volume*2.5)
|
||||||
# 先生成旗帜僵尸
|
# 先生成旗帜僵尸
|
||||||
zombieList.append(c.FLAG_ZOMBIE)
|
zombie_list.append(c.FLAG_ZOMBIE)
|
||||||
volume -= c.CREATE_ZOMBIE_DICT[c.FLAG_ZOMBIE][0]
|
zombie_volume -= c.CREATE_ZOMBIE_DICT[c.FLAG_ZOMBIE][0]
|
||||||
|
|
||||||
# 传送带模式应当增大僵尸容量
|
# 传送带模式应当增大僵尸容量
|
||||||
if (self.bar_type != c.CHOOSEBAR_STATIC):
|
if (self.bar_type != c.CHOOSEBAR_STATIC):
|
||||||
volume += 2
|
zombie_volume += 2
|
||||||
|
|
||||||
if inevitableZombieDict and (wave in inevitableZombieDict):
|
if inevitable_zombie_dict and (wave in inevitable_zombie_dict):
|
||||||
for newZombie in inevitableZombieDict[str(wave)]:
|
for new_zombie in inevitable_zombie_dict[wave]:
|
||||||
zombieList.append(newZombie)
|
zombie_list.append(new_zombie)
|
||||||
volume -= c.CREATE_ZOMBIE_DICT[newZombie][0]
|
zombie_volume -= c.CREATE_ZOMBIE_DICT[new_zombie][0]
|
||||||
if volume < 0:
|
if zombie_volume < 0:
|
||||||
logger.warning(f"第{wave}波中手动设置的僵尸级别总数超过上限!")
|
logger.warning(f"第{wave}波中手动设置的僵尸级别总数超过上限!")
|
||||||
|
|
||||||
# 防止因为僵尸最小等级过大,使得总容量无法完全利用,造成死循环的检查机制
|
# 防止因为僵尸最小等级过大,使得总容量无法完全利用,造成死循环的检查机制
|
||||||
minCost = c.CREATE_ZOMBIE_DICT[min(useableZombies, key=lambda x:c.CREATE_ZOMBIE_DICT[x][0])][0]
|
min_cost = c.CREATE_ZOMBIE_DICT[min(useable_zombies, key=lambda x:c.CREATE_ZOMBIE_DICT[x][0])][0]
|
||||||
|
|
||||||
while (volume >= minCost) and (len(zombieList) < 50):
|
while (zombie_volume >= min_cost) and (len(zombie_list) < 50):
|
||||||
newZombie = random.choices(useableZombies, weights)[0]
|
new_zombie = random.choices(useable_zombies, weights)[0]
|
||||||
# 普通僵尸、路障僵尸、铁桶僵尸有概率生成水中变种
|
# 普通僵尸、路障僵尸、铁桶僵尸有概率生成水中变种
|
||||||
if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS:
|
if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS:
|
||||||
# 有泳池第一轮的第四波设定上生成水生僵尸
|
# 有泳池第一轮的第四波设定上生成水生僵尸
|
||||||
if survivalRounds == 0 and wave == 4:
|
if survival_rounds == 0 and wave == 4:
|
||||||
if newZombie in c.CONVERT_ZOMBIE_IN_POOL:
|
if new_zombie in c.CONVERT_ZOMBIE_IN_POOL:
|
||||||
newZombie = c.CONVERT_ZOMBIE_IN_POOL[newZombie]
|
new_zombie = c.CONVERT_ZOMBIE_IN_POOL[new_zombie]
|
||||||
elif survivalRounds > 0 or wave > 4:
|
elif survival_rounds > 0 or wave > 4:
|
||||||
if random.randint(1, 3) == 1: # 1/3概率水上,暂时人为设定
|
if random.randint(1, 3) == 1: # 1/3概率水上,暂时人为设定
|
||||||
if newZombie in c.CONVERT_ZOMBIE_IN_POOL:
|
if new_zombie in c.CONVERT_ZOMBIE_IN_POOL:
|
||||||
newZombie = c.CONVERT_ZOMBIE_IN_POOL[newZombie]
|
new_zombie = c.CONVERT_ZOMBIE_IN_POOL[new_zombie]
|
||||||
# 首先几轮不出水生僵尸
|
# 首先几轮不出水生僵尸
|
||||||
elif newZombie in c.WATER_ZOMBIE:
|
elif new_zombie in c.WATER_ZOMBIE:
|
||||||
continue
|
continue
|
||||||
if c.CREATE_ZOMBIE_DICT[newZombie][0] <= volume:
|
if c.CREATE_ZOMBIE_DICT[new_zombie][0] <= zombie_volume:
|
||||||
zombieList.append(newZombie)
|
zombie_list.append(new_zombie)
|
||||||
volume -= c.CREATE_ZOMBIE_DICT[newZombie][0]
|
zombie_volume -= c.CREATE_ZOMBIE_DICT[new_zombie][0]
|
||||||
waves.append(zombieList)
|
waves.append(zombie_list)
|
||||||
# print(wave, zombieList, len(zombieList))
|
|
||||||
|
|
||||||
self.waves = waves
|
self.waves = waves
|
||||||
|
|
||||||
# 针对有泳池的关卡
|
# 针对有泳池的关卡
|
||||||
# 表示尚未生成最后一波中从水里冒出来的僵尸
|
# 表示尚未生成最后一波中从水里冒出来的僵尸
|
||||||
self.createdZombieFromPool = False
|
self.created_zombie_from_pool = False
|
||||||
|
|
||||||
|
|
||||||
# 僵尸的刷新机制
|
# 僵尸的刷新机制
|
||||||
def refreshWaves(self, current_time, survivalRounds=0):
|
def refreshWaves(self, current_time, survival_rounds=0):
|
||||||
# 最后一波或者大于最后一波
|
# 最后一波或者大于最后一波
|
||||||
# 如果在夜晚按需从墓碑生成僵尸
|
# 如果在夜晚按需从墓碑生成僵尸 有泳池时从水中生成僵尸
|
||||||
# 否则直接return
|
# 否则直接return
|
||||||
if self.wave_num >= self.map_data[c.NUM_FLAGS] * 10:
|
if self.wave_num >= self.map_data[c.NUM_FLAGS] * 10:
|
||||||
if self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_NIGHT:
|
if self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_NIGHT:
|
||||||
@ -183,13 +182,13 @@ class Level(tool.State):
|
|||||||
unoccupied = []
|
unoccupied = []
|
||||||
occupied = []
|
occupied = []
|
||||||
# 毁灭菇坑与冰道应当特殊化
|
# 毁灭菇坑与冰道应当特殊化
|
||||||
exceptionObjects = {c.HOLE, c.ICEFROZENPLOT}
|
exception_objects = {c.HOLE, c.ICEFROZENPLOT}
|
||||||
# 遍历能生成墓碑的区域
|
# 遍历能生成墓碑的区域
|
||||||
for map_y in range(0, 4):
|
for map_y in range(0, 4):
|
||||||
for map_x in range(4, 8):
|
for map_x in range(4, 8):
|
||||||
# 为空、为毁灭菇坑、为冰道时看作未被植物占据
|
# 为空、为毁灭菇坑、为冰道时看作未被植物占据
|
||||||
if ((not self.map.map[map_y][map_x][c.MAP_PLANT]) or
|
if ((not self.map.map[map_y][map_x][c.MAP_PLANT]) or
|
||||||
(all((i in exceptionObjects) for i in self.map.map[map_y][map_x][c.MAP_PLANT]))):
|
(all((i in exception_objects) for i in self.map.map[map_y][map_x][c.MAP_PLANT]))):
|
||||||
unoccupied.append((map_x, map_y))
|
unoccupied.append((map_x, map_y))
|
||||||
# 已有墓碑的格子不应该放到任何列表中
|
# 已有墓碑的格子不应该放到任何列表中
|
||||||
elif c.GRAVE not in self.map.map[map_y][map_x][c.MAP_PLANT]:
|
elif c.GRAVE not in self.map.map[map_y][map_x][c.MAP_PLANT]:
|
||||||
@ -209,7 +208,7 @@ class Level(tool.State):
|
|||||||
checkMapX, _ = self.map.getMapIndex(i.rect.centerx, i.rect.bottom)
|
checkMapX, _ = self.map.getMapIndex(i.rect.centerx, i.rect.bottom)
|
||||||
if map_x == checkMapX:
|
if map_x == checkMapX:
|
||||||
# 不杀死毁灭菇坑和冰道
|
# 不杀死毁灭菇坑和冰道
|
||||||
if i.name not in exceptionObjects:
|
if i.name not in exception_objects:
|
||||||
i.health = 0
|
i.health = 0
|
||||||
self.plant_groups[map_y].add(plant.Grave(posX, posY))
|
self.plant_groups[map_y].add(plant.Grave(posX, posY))
|
||||||
self.map.map[map_y][map_x][c.MAP_PLANT].add(c.GRAVE)
|
self.map.map[map_y][map_x][c.MAP_PLANT].add(c.GRAVE)
|
||||||
@ -227,7 +226,7 @@ class Level(tool.State):
|
|||||||
self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(item_x, item_y, self.head_group))
|
self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(item_x, item_y, self.head_group))
|
||||||
self.grave_zombie_created = True
|
self.grave_zombie_created = True
|
||||||
elif self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS:
|
elif self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS:
|
||||||
if not self.createdZombieFromPool:
|
if not self.created_zombie_from_pool:
|
||||||
if current_time - self.wave_time > 1500:
|
if current_time - self.wave_time > 1500:
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
# 水中倒数四列内可以在此时产生僵尸。共产生3个
|
# 水中倒数四列内可以在此时产生僵尸。共产生3个
|
||||||
@ -235,14 +234,14 @@ class Level(tool.State):
|
|||||||
item_x, item_y = self.map.getMapGridPos(map_x, map_y)
|
item_x, item_y = self.map.getMapGridPos(map_x, map_y)
|
||||||
# 用随机数指定产生的僵尸类型
|
# 用随机数指定产生的僵尸类型
|
||||||
# 暂时设定为生成概率相同
|
# 暂时设定为生成概率相同
|
||||||
zombieType = random.randint(1, 3)
|
zombie_type = random.randint(1, 3)
|
||||||
if zombieType == 1:
|
if zombie_type == 1:
|
||||||
self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(item_x, item_y, self.head_group))
|
self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(item_x, item_y, self.head_group))
|
||||||
elif zombieType == 2:
|
elif zombie_type == 2:
|
||||||
self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(item_x, item_y, self.head_group))
|
self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(item_x, item_y, self.head_group))
|
||||||
else:
|
else:
|
||||||
self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(item_x, item_y, self.head_group))
|
self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(item_x, item_y, self.head_group))
|
||||||
self.createdZombieFromPool = True
|
self.created_zombie_from_pool = True
|
||||||
return
|
return
|
||||||
|
|
||||||
# 还未开始出现僵尸
|
# 还未开始出现僵尸
|
||||||
@ -250,7 +249,7 @@ class Level(tool.State):
|
|||||||
if (self.wave_time == 0): # 表明刚刚开始游戏
|
if (self.wave_time == 0): # 表明刚刚开始游戏
|
||||||
self.wave_time = current_time
|
self.wave_time = current_time
|
||||||
else:
|
else:
|
||||||
if (survivalRounds == 0) and (self.bar_type == c.CHOOSEBAR_STATIC): # 首次选卡等待时间较长
|
if (survival_rounds == 0) and (self.bar_type == c.CHOOSEBAR_STATIC): # 首次选卡等待时间较长
|
||||||
if current_time - self.wave_time >= 18000:
|
if current_time - self.wave_time >= 18000:
|
||||||
self.wave_num += 1
|
self.wave_num += 1
|
||||||
self.wave_time = current_time
|
self.wave_time = current_time
|
||||||
@ -287,7 +286,7 @@ class Level(tool.State):
|
|||||||
zombie_nums = 0
|
zombie_nums = 0
|
||||||
for i in range(self.map_y_len):
|
for i in range(self.map_y_len):
|
||||||
zombie_nums += len(self.zombie_groups[i])
|
zombie_nums += len(self.zombie_groups[i])
|
||||||
if (zombie_nums / self.zombie_num < random.uniform(0.15, 0.25)) and (current_time - self.wave_time > 4000):
|
if self.zombie_num and (zombie_nums / self.zombie_num < random.uniform(0.15, 0.25)) and (current_time - self.wave_time > 4000):
|
||||||
# 当僵尸所剩无几并且时间过了4000 ms以上时,改变时间记录,使得2000 ms后刷新僵尸(所以需要判断剩余时间是否大于2000 ms)
|
# 当僵尸所剩无几并且时间过了4000 ms以上时,改变时间记录,使得2000 ms后刷新僵尸(所以需要判断剩余时间是否大于2000 ms)
|
||||||
if self.bar_type == c.CHOOSEBAR_STATIC:
|
if self.bar_type == c.CHOOSEBAR_STATIC:
|
||||||
if current_time - 43000 < self.wave_time: # 判断剩余时间是否有2000 ms
|
if current_time - 43000 < self.wave_time: # 判断剩余时间是否有2000 ms
|
||||||
@ -312,7 +311,7 @@ class Level(tool.State):
|
|||||||
self.cars = []
|
self.cars = []
|
||||||
for i in range(self.map_y_len):
|
for i in range(self.map_y_len):
|
||||||
y = self.map.getMapGridPos(0, i)[1]
|
y = self.map.getMapGridPos(0, i)[1]
|
||||||
self.cars.append(plant.Car(-40, y+20, i))
|
self.cars.append(plant.Car(-45, y+20, i))
|
||||||
|
|
||||||
# 更新函数每帧被调用,将鼠标事件传入给状态处理函数
|
# 更新函数每帧被调用,将鼠标事件传入给状态处理函数
|
||||||
def update(self, surface, current_time, mouse_pos, mouse_click):
|
def update(self, surface, current_time, mouse_pos, mouse_click):
|
||||||
@ -366,7 +365,7 @@ class Level(tool.State):
|
|||||||
def choose(self, mouse_pos, mouse_click):
|
def choose(self, mouse_pos, mouse_click):
|
||||||
# 如果暂停
|
# 如果暂停
|
||||||
if self.show_game_menu:
|
if self.show_game_menu:
|
||||||
self.pauseAndCheckLittleMenuOptions(mouse_pos, mouse_click)
|
self.pauseAndCheckMenuOptions(mouse_pos, mouse_click)
|
||||||
return
|
return
|
||||||
|
|
||||||
elif mouse_pos and mouse_click[0]:
|
elif mouse_pos and mouse_click[0]:
|
||||||
@ -404,6 +403,7 @@ class Level(tool.State):
|
|||||||
|
|
||||||
if self.background_type in c.DAYTIME_BACKGROUNDS and self.bar_type == c.CHOOSEBAR_STATIC:
|
if self.background_type in c.DAYTIME_BACKGROUNDS and self.bar_type == c.CHOOSEBAR_STATIC:
|
||||||
self.produce_sun = True
|
self.produce_sun = True
|
||||||
|
self.fallen_sun = 0 # 已掉落的阳光
|
||||||
else:
|
else:
|
||||||
self.produce_sun = False
|
self.produce_sun = False
|
||||||
self.sun_timer = self.current_time
|
self.sun_timer = self.current_time
|
||||||
@ -419,16 +419,16 @@ class Level(tool.State):
|
|||||||
self.wave_zombies = []
|
self.wave_zombies = []
|
||||||
self.zombie_num = 0
|
self.zombie_num = 0
|
||||||
|
|
||||||
# 暂时没有生存模式,所以 survivalRounds = 0
|
# 暂时没有生存模式,所以 survival_rounds = 0
|
||||||
if c.INEVITABLE_ZOMBIE_DICT in self.map_data:
|
if c.INEVITABLE_ZOMBIE_DICT in self.map_data:
|
||||||
self.createWaves( useableZombies=self.map_data[c.INCLUDED_ZOMBIES],
|
self.createWaves( useable_zombies=self.map_data[c.INCLUDED_ZOMBIES],
|
||||||
numFlags=self.map_data[c.NUM_FLAGS],
|
num_flags=self.map_data[c.NUM_FLAGS],
|
||||||
survivalRounds=0,
|
survival_rounds=0,
|
||||||
inevitableZombieDict=self.map_data[c.INEVITABLE_ZOMBIE_DICT])
|
inevitable_zombie_dict=self.map_data[c.INEVITABLE_ZOMBIE_DICT])
|
||||||
else:
|
else:
|
||||||
self.createWaves( useableZombies=self.map_data[c.INCLUDED_ZOMBIES],
|
self.createWaves( useable_zombies=self.map_data[c.INCLUDED_ZOMBIES],
|
||||||
numFlags=self.map_data[c.NUM_FLAGS],
|
num_flags=self.map_data[c.NUM_FLAGS],
|
||||||
survivalRounds=0)
|
survival_rounds=0)
|
||||||
self.setupCars()
|
self.setupCars()
|
||||||
|
|
||||||
# 地图有铲子才添加铲子
|
# 地图有铲子才添加铲子
|
||||||
@ -458,9 +458,9 @@ class Level(tool.State):
|
|||||||
else:
|
else:
|
||||||
grade_graves = 1
|
grade_graves = 1
|
||||||
|
|
||||||
graveVolume = c.GRAVES_GRADE_INFO[grade_graves]
|
grave_volume = c.GRAVES_GRADE_INFO[grade_graves]
|
||||||
self.grave_set = set()
|
self.grave_set = set()
|
||||||
while len(self.grave_set) < graveVolume:
|
while len(self.grave_set) < grave_volume:
|
||||||
map_x = random.randint(4, 8) # 注意是从0开始编号
|
map_x = random.randint(4, 8) # 注意是从0开始编号
|
||||||
map_y = random.randint(0, 4)
|
map_y = random.randint(0, 4)
|
||||||
self.grave_set.add((map_x, map_y))
|
self.grave_set.add((map_x, map_y))
|
||||||
@ -544,7 +544,7 @@ class Level(tool.State):
|
|||||||
# 音量+、-应当处于同一高度
|
# 音量+、-应当处于同一高度
|
||||||
self.sound_volume_minus_button_rect.y = self.sound_volume_plus_button_rect.y = 250
|
self.sound_volume_minus_button_rect.y = self.sound_volume_plus_button_rect.y = 250
|
||||||
|
|
||||||
def pauseAndCheckLittleMenuOptions(self, mouse_pos, mouse_click):
|
def pauseAndCheckMenuOptions(self, mouse_pos, mouse_click):
|
||||||
# 设置暂停状态
|
# 设置暂停状态
|
||||||
self.pause = True
|
self.pause = True
|
||||||
# 暂停播放音乐
|
# 暂停播放音乐
|
||||||
@ -654,13 +654,9 @@ class Level(tool.State):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def play(self, mouse_pos, mouse_click):
|
def play(self, mouse_pos, mouse_click):
|
||||||
# 原版阳光掉落机制需要
|
|
||||||
# 已掉落的阳光
|
|
||||||
self.fallen_sun = 0
|
|
||||||
|
|
||||||
# 如果暂停
|
# 如果暂停
|
||||||
if self.show_game_menu:
|
if self.show_game_menu:
|
||||||
self.pauseAndCheckLittleMenuOptions(mouse_pos, mouse_click)
|
self.pauseAndCheckMenuOptions(mouse_pos, mouse_click)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||||
@ -704,13 +700,12 @@ class Level(tool.State):
|
|||||||
self.sun_group.add(plant.Sun(x, 0, x, y))
|
self.sun_group.add(plant.Sun(x, 0, x, y))
|
||||||
self.fallen_sun += 1
|
self.fallen_sun += 1
|
||||||
|
|
||||||
# wcb 添加
|
|
||||||
# 检查有没有捡到阳光
|
# 检查有没有捡到阳光
|
||||||
clicked_sun = False
|
clicked_sun = False
|
||||||
clicked_cards_or_map = False
|
clicked_cards_or_map = False
|
||||||
if not self.drag_plant and not self.drag_shovel and mouse_pos and mouse_click[0]:
|
if not self.drag_plant and not self.drag_shovel and mouse_pos and mouse_click[0]:
|
||||||
for sun in self.sun_group:
|
for sun in self.sun_group:
|
||||||
if sun.checkCollision(mouse_pos[0], mouse_pos[1]):
|
if sun.checkCollision(*mouse_pos):
|
||||||
self.menubar.increaseSunValue(sun.sun_value)
|
self.menubar.increaseSunValue(sun.sun_value)
|
||||||
clicked_sun = True
|
clicked_sun = True
|
||||||
# 播放收集阳光的音效
|
# 播放收集阳光的音效
|
||||||
@ -767,7 +762,7 @@ class Level(tool.State):
|
|||||||
self.menubar.update(self.current_time)
|
self.menubar.update(self.current_time)
|
||||||
|
|
||||||
|
|
||||||
# 检查碰撞啥的
|
# 检查碰撞
|
||||||
self.checkBulletCollisions()
|
self.checkBulletCollisions()
|
||||||
self.checkZombieCollisions()
|
self.checkZombieCollisions()
|
||||||
self.checkPlants()
|
self.checkPlants()
|
||||||
@ -925,6 +920,8 @@ class Level(tool.State):
|
|||||||
new_plant = plant.Garlic(x, y)
|
new_plant = plant.Garlic(x, y)
|
||||||
elif self.plant_name == c.PUMPKINHEAD:
|
elif self.plant_name == c.PUMPKINHEAD:
|
||||||
new_plant = plant.PumpkinHead(x, y)
|
new_plant = plant.PumpkinHead(x, y)
|
||||||
|
elif self.plant_name == c.GIANTWALLNUT:
|
||||||
|
new_plant = plant.GiantWallNut(x, y)
|
||||||
|
|
||||||
|
|
||||||
if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS:
|
if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS:
|
||||||
@ -1016,13 +1013,13 @@ class Level(tool.State):
|
|||||||
continue
|
continue
|
||||||
if collided_func(zombie, bullet):
|
if collided_func(zombie, bullet):
|
||||||
if zombie.state != c.DIE:
|
if zombie.state != c.DIE:
|
||||||
zombie.setDamage(bullet.damage, effect=bullet.effect, damageType=bullet.damageType)
|
zombie.setDamage(bullet.damage, effect=bullet.effect, damage_type=bullet.damage_type)
|
||||||
bullet.setExplode()
|
bullet.setExplode()
|
||||||
# 火球有溅射伤害
|
# 火球有溅射伤害
|
||||||
if bullet.name == c.BULLET_FIREBALL:
|
if bullet.name == c.BULLET_FIREBALL:
|
||||||
for rangeZombie in self.zombie_groups[i]:
|
for rangeZombie in self.zombie_groups[i]:
|
||||||
if abs(rangeZombie.rect.x - bullet.rect.x) <= (c.GRID_X_SIZE // 2):
|
if abs(rangeZombie.rect.x - bullet.rect.x) <= (c.GRID_X_SIZE // 2):
|
||||||
rangeZombie.setDamage(c.BULLET_DAMAGE_FIREBALL_RANGE, effect=None, damageType=c.ZOMBIE_DEAFULT_DAMAGE)
|
rangeZombie.setDamage(c.BULLET_DAMAGE_FIREBALL_RANGE, effect=None, damage_type=c.ZOMBIE_DEAFULT_DAMAGE)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@ -1083,6 +1080,15 @@ class Level(tool.State):
|
|||||||
if attackable_common_plants:
|
if attackable_common_plants:
|
||||||
# 默认为最右侧的一个植物
|
# 默认为最右侧的一个植物
|
||||||
target_plant = max(attackable_common_plants, key=lambda i: i.rect.x)
|
target_plant = max(attackable_common_plants, key=lambda i: i.rect.x)
|
||||||
|
map_x, map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery)
|
||||||
|
if not (map_x >= self.map.width or map_y >= self.map.height):
|
||||||
|
if c.PUMPKINHEAD in self.map.map[map_y][map_x][c.MAP_PLANT]:
|
||||||
|
for actual_target_plant in self.plant_groups[i]:
|
||||||
|
# 检测同一格的其他植物
|
||||||
|
if self.map.getMapIndex(actual_target_plant.rect.centerx, actual_target_plant.rect.bottom) == (map_x, map_y):
|
||||||
|
if actual_target_plant.name == c.PUMPKINHEAD:
|
||||||
|
target_plant = actual_target_plant
|
||||||
|
break
|
||||||
elif attackable_backup_plants:
|
elif attackable_backup_plants:
|
||||||
target_plant = max(attackable_backup_plants, key=lambda i: i.rect.x)
|
target_plant = max(attackable_backup_plants, key=lambda i: i.rect.x)
|
||||||
map_x, map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery)
|
map_x, map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery)
|
||||||
@ -1105,7 +1111,10 @@ class Level(tool.State):
|
|||||||
zombie.prey_map_x, zombie.prey_map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery)
|
zombie.prey_map_x, zombie.prey_map_y = self.map.getMapIndex(target_plant.rect.centerx, target_plant.rect.centery)
|
||||||
# 撑杆跳的特殊情况
|
# 撑杆跳的特殊情况
|
||||||
if zombie.name in {c.POLE_VAULTING_ZOMBIE} and (not zombie.jumped):
|
if zombie.name in {c.POLE_VAULTING_ZOMBIE} and (not zombie.jumped):
|
||||||
if not zombie.jumping:
|
if target_plant.name == c.GIANTWALLNUT:
|
||||||
|
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, zombie.jump_map_y = min(c.GRID_X_LEN - 1, zombie.prey_map_x), min(self.map_y_len - 1, zombie.prey_map_y)
|
||||||
jump_x = target_plant.rect.x - c.GRID_X_SIZE * 0.6
|
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]:
|
if c.TALLNUT in self.map.map[zombie.jump_map_y][zombie.jump_map_x][c.MAP_PLANT]:
|
||||||
@ -1123,15 +1132,18 @@ class Level(tool.State):
|
|||||||
if target_plant.canHit(i):
|
if target_plant.canHit(i):
|
||||||
# target_plant.vel_y不为0,有纵向速度,表明已经发生过碰撞,对铁门秒杀(这里实现为忽略二类防具攻击)
|
# target_plant.vel_y不为0,有纵向速度,表明已经发生过碰撞,对铁门秒杀(这里实现为忽略二类防具攻击)
|
||||||
if target_plant.vel_y and zombie.name == c.SCREEN_DOOR_ZOMBIE:
|
if target_plant.vel_y and zombie.name == c.SCREEN_DOOR_ZOMBIE:
|
||||||
zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damageType=c.ZOMBIE_COMMON_DAMAGE)
|
zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damage_type=c.ZOMBIE_COMMON_DAMAGE)
|
||||||
else:
|
else:
|
||||||
zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damageType=c.ZOMBIE_WALLNUT_BOWLING_DANMAGE)
|
zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE, damage_type=c.ZOMBIE_WALLNUT_BOWLING_DANMAGE)
|
||||||
target_plant.changeDirection(i)
|
target_plant.changeDirection(i)
|
||||||
# 播放撞击音效
|
# 播放撞击音效
|
||||||
c.SOUND_BOWLING_IMPACT.play()
|
c.SOUND_BOWLING_IMPACT.play()
|
||||||
elif target_plant.name == c.REDWALLNUTBOWLING:
|
elif target_plant.name == c.REDWALLNUTBOWLING:
|
||||||
if target_plant.state == c.IDLE:
|
if target_plant.state == c.IDLE:
|
||||||
target_plant.setAttack()
|
target_plant.setAttack()
|
||||||
|
elif target_plant.name == c.GIANTWALLNUT:
|
||||||
|
zombie.health = 0
|
||||||
|
c.SOUND_BOWLING_IMPACT.play()
|
||||||
elif zombie.target_y_change:
|
elif zombie.target_y_change:
|
||||||
# 大蒜作用正在生效的僵尸不进行传递
|
# 大蒜作用正在生效的僵尸不进行传递
|
||||||
continue
|
continue
|
||||||
@ -1177,9 +1189,11 @@ class Level(tool.State):
|
|||||||
for i in range(len(self.cars)):
|
for i in range(len(self.cars)):
|
||||||
if self.cars[i]:
|
if self.cars[i]:
|
||||||
for zombie in self.zombie_groups[i]:
|
for zombie in self.zombie_groups[i]:
|
||||||
if zombie and zombie.state != c.DIE and (not zombie.losthead) and (zombie.rect.centerx <= 0):
|
if (zombie and zombie.state != c.DIE and (not zombie.losthead)
|
||||||
|
and (pg.sprite.collide_mask(zombie, self.cars[i]))):
|
||||||
self.cars[i].setWalk()
|
self.cars[i].setWalk()
|
||||||
if zombie.rect.centerx <= self.cars[i].rect.x:
|
if (pg.sprite.collide_mask(zombie, self.cars[i]) or
|
||||||
|
self.cars[i].rect.x <= zombie.rect.right <= self.cars[i].rect.right):
|
||||||
zombie.health = 0
|
zombie.health = 0
|
||||||
if self.cars[i].dead:
|
if self.cars[i].dead:
|
||||||
self.cars[i] = None
|
self.cars[i] = None
|
||||||
@ -1193,7 +1207,7 @@ class Level(tool.State):
|
|||||||
((zombie.rect.right - (x-x_range) > 20) or (zombie.rect.right - (x-x_range))/zombie.rect.width > 0.2, ((x+x_range) - zombie.rect.left > 20) or ((x+x_range) - zombie.rect.left)/zombie.rect.width > 0.2)[zombie.rect.x > x]): # 这代码不太好懂,后面是一个判断僵尸在左还是在右,前面是一个元组,[0]是在左边的情况,[1]是在右边的情况
|
((zombie.rect.right - (x-x_range) > 20) or (zombie.rect.right - (x-x_range))/zombie.rect.width > 0.2, ((x+x_range) - zombie.rect.left > 20) or ((x+x_range) - zombie.rect.left)/zombie.rect.width > 0.2)[zombie.rect.x > x]): # 这代码不太好懂,后面是一个判断僵尸在左还是在右,前面是一个元组,[0]是在左边的情况,[1]是在右边的情况
|
||||||
if effect == c.BULLET_EFFECT_UNICE:
|
if effect == c.BULLET_EFFECT_UNICE:
|
||||||
zombie.ice_slow_ratio = 1
|
zombie.ice_slow_ratio = 1
|
||||||
zombie.setDamage(1800, damageType=c.ZOMBIE_ASH_DAMAGE)
|
zombie.setDamage(1800, damage_type=c.ZOMBIE_ASH_DAMAGE)
|
||||||
if zombie.health <= 0:
|
if zombie.health <= 0:
|
||||||
zombie.setBoomDie()
|
zombie.setBoomDie()
|
||||||
|
|
||||||
@ -1204,7 +1218,7 @@ class Level(tool.State):
|
|||||||
for i in range(self.map_y_len):
|
for i in range(self.map_y_len):
|
||||||
for zombie in self.zombie_groups[i]:
|
for zombie in self.zombie_groups[i]:
|
||||||
zombie.setFreeze(plant.trap_frames[0])
|
zombie.setFreeze(plant.trap_frames[0])
|
||||||
zombie.setDamage(20, damageType=c.ZOMBIE_RANGE_DAMAGE) # 寒冰菇还有全场20的伤害
|
zombie.setDamage(20, damage_type=c.ZOMBIE_RANGE_DAMAGE) # 寒冰菇还有全场20的伤害
|
||||||
|
|
||||||
def killPlant(self, target_plant, shovel=False):
|
def killPlant(self, target_plant, shovel=False):
|
||||||
x, y = target_plant.getPosition()
|
x, y = target_plant.getPosition()
|
||||||
@ -1283,7 +1297,7 @@ class Level(tool.State):
|
|||||||
# 双判断:发生碰撞或在攻击范围内
|
# 双判断:发生碰撞或在攻击范围内
|
||||||
if ((pg.sprite.collide_mask(zombie, target_plant)) or
|
if ((pg.sprite.collide_mask(zombie, target_plant)) or
|
||||||
(abs(zombie.rect.centerx - target_plant.rect.centerx) <= target_plant.explode_x_range)):
|
(abs(zombie.rect.centerx - target_plant.rect.centerx) <= target_plant.explode_x_range)):
|
||||||
zombie.setDamage(1800, damageType=c.ZOMBIE_RANGE_DAMAGE)
|
zombie.setDamage(1800, damage_type=c.ZOMBIE_RANGE_DAMAGE)
|
||||||
target_plant.boomed = True
|
target_plant.boomed = True
|
||||||
elif target_plant.name == c.SQUASH:
|
elif target_plant.name == c.SQUASH:
|
||||||
for zombie in self.zombie_groups[i]:
|
for zombie in self.zombie_groups[i]:
|
||||||
@ -1400,7 +1414,6 @@ class Level(tool.State):
|
|||||||
for i in range(self.map_y_len):
|
for i in range(self.map_y_len):
|
||||||
for zombie in self.zombie_groups[i]:
|
for zombie in self.zombie_groups[i]:
|
||||||
if zombie.rect.right < -20 and (not zombie.losthead) and (zombie.state != c.DIE):
|
if zombie.rect.right < -20 and (not zombie.losthead) and (zombie.state != c.DIE):
|
||||||
print(zombie.rect.right, zombie.losthead, zombie.state,zombie.name)
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -1488,13 +1501,13 @@ class Level(tool.State):
|
|||||||
|
|
||||||
# 填充的进度条信息
|
# 填充的进度条信息
|
||||||
# 常数为拟合值
|
# 常数为拟合值
|
||||||
filledBarRect = (self.level_progress_zombie_head_image_rect.x + 3, self.level_progress_bar_image_rect.y + 6, int((150 * self.wave_num) / (self.map_data[c.NUM_FLAGS] * 10)) + 5, 9)
|
filled_bar_rect = (self.level_progress_zombie_head_image_rect.x + 3, self.level_progress_bar_image_rect.y + 6, int((150 * self.wave_num) / (self.map_data[c.NUM_FLAGS] * 10)) + 5, 9)
|
||||||
# 画填充的进度条
|
# 画填充的进度条
|
||||||
pg.draw.rect(surface, c.YELLOWGREEN, filledBarRect)
|
pg.draw.rect(surface, c.YELLOWGREEN, filled_bar_rect)
|
||||||
|
|
||||||
# 画旗帜
|
# 画旗帜
|
||||||
for i in range(self.numFlags):
|
for i in range(self.num_flags):
|
||||||
self.level_progress_flag_rect.x = self.level_progress_bar_image_rect.x + int((150*i)/self.numFlags) + 5 # 常数是猜的
|
self.level_progress_flag_rect.x = self.level_progress_bar_image_rect.x + int((150*i)/self.num_flags) + 5 # 常数是猜的
|
||||||
# 当指示进度的僵尸头在旗帜左侧时升高旗帜
|
# 当指示进度的僵尸头在旗帜左侧时升高旗帜
|
||||||
if self.level_progress_flag_rect.x - 7 >= self.level_progress_zombie_head_image_rect.x:
|
if self.level_progress_flag_rect.x - 7 >= self.level_progress_zombie_head_image_rect.x:
|
||||||
self.level_progress_flag_rect.y = self.level_progress_bar_image_rect.y - 15 # 常数是猜的
|
self.level_progress_flag_rect.y = self.level_progress_bar_image_rect.y - 15 # 常数是猜的
|
||||||
@ -1534,14 +1547,6 @@ class Level(tool.State):
|
|||||||
self.showAllContentOfMenu(surface)
|
self.showAllContentOfMenu(surface)
|
||||||
# 以后可能需要插入一个预备的状态(预览显示僵尸、返回战场)
|
# 以后可能需要插入一个预备的状态(预览显示僵尸、返回战场)
|
||||||
elif self.state == c.PLAY:
|
elif self.state == c.PLAY:
|
||||||
if self.has_shovel:
|
|
||||||
# 画铲子
|
|
||||||
surface.blit(self.shovel_box, self.shovel_box_rect)
|
|
||||||
surface.blit(self.shovel, self.shovel_rect)
|
|
||||||
# 画小菜单
|
|
||||||
surface.blit(self.little_menu, self.little_menu_rect)
|
|
||||||
|
|
||||||
self.menubar.draw(surface)
|
|
||||||
for i in range(self.map_y_len):
|
for i in range(self.map_y_len):
|
||||||
self.plant_groups[i].draw(surface)
|
self.plant_groups[i].draw(surface)
|
||||||
self.zombie_groups[i].draw(surface)
|
self.zombie_groups[i].draw(surface)
|
||||||
@ -1551,6 +1556,19 @@ class Level(tool.State):
|
|||||||
if self.cars[i]:
|
if self.cars[i]:
|
||||||
self.cars[i].draw(surface)
|
self.cars[i].draw(surface)
|
||||||
self.head_group.draw(surface)
|
self.head_group.draw(surface)
|
||||||
|
|
||||||
|
# 浓雾模式的雾
|
||||||
|
#if self.background_type == c.BACKGROUND_FOG:
|
||||||
|
# pg.draw.rect(surface, c.LIGHTGRAY, (400, 0, 400, 600))
|
||||||
|
|
||||||
|
if self.has_shovel:
|
||||||
|
# 画铲子
|
||||||
|
surface.blit(self.shovel_box, self.shovel_box_rect)
|
||||||
|
surface.blit(self.shovel, self.shovel_rect)
|
||||||
|
# 画小菜单
|
||||||
|
surface.blit(self.little_menu, self.little_menu_rect)
|
||||||
|
|
||||||
|
self.menubar.draw(surface)
|
||||||
self.sun_group.draw(surface)
|
self.sun_group.draw(surface)
|
||||||
|
|
||||||
if self.drag_plant:
|
if self.drag_plant:
|
||||||
|
|||||||
@ -223,6 +223,7 @@ class HelpScreen(tool.State):
|
|||||||
self.setupImage()
|
self.setupImage()
|
||||||
pg.display.set_caption("pypvz: 帮助")
|
pg.display.set_caption("pypvz: 帮助")
|
||||||
pg.mixer.music.stop()
|
pg.mixer.music.stop()
|
||||||
|
c.SOUND_HELP_SCREEN.play()
|
||||||
|
|
||||||
def setupImage(self):
|
def setupImage(self):
|
||||||
# 主体
|
# 主体
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user