diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/PythonPlantsVsZombies.iml b/.idea/PythonPlantsVsZombies.iml new file mode 100644 index 00000000..d0876a78 --- /dev/null +++ b/.idea/PythonPlantsVsZombies.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..105ce2da --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..2a2c1b9b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..35c0ec56 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/__pycache__/__init__.cpython-312.pyc b/source/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 00000000..73ec3c53 Binary files /dev/null and b/source/__pycache__/__init__.cpython-312.pyc differ diff --git a/source/__pycache__/constants.cpython-312.pyc b/source/__pycache__/constants.cpython-312.pyc new file mode 100644 index 00000000..929394fe Binary files /dev/null and b/source/__pycache__/constants.cpython-312.pyc differ diff --git a/source/__pycache__/main.cpython-312.pyc b/source/__pycache__/main.cpython-312.pyc new file mode 100644 index 00000000..b84b6c22 Binary files /dev/null and b/source/__pycache__/main.cpython-312.pyc differ diff --git a/source/__pycache__/tool.cpython-312.pyc b/source/__pycache__/tool.cpython-312.pyc new file mode 100644 index 00000000..69e5afe0 Binary files /dev/null and b/source/__pycache__/tool.cpython-312.pyc differ diff --git a/source/component/__pycache__/__init__.cpython-312.pyc b/source/component/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 00000000..1f9988a3 Binary files /dev/null and b/source/component/__pycache__/__init__.cpython-312.pyc differ diff --git a/source/component/__pycache__/map.cpython-312.pyc b/source/component/__pycache__/map.cpython-312.pyc new file mode 100644 index 00000000..92b1ac8f Binary files /dev/null and b/source/component/__pycache__/map.cpython-312.pyc differ diff --git a/source/component/__pycache__/menubar.cpython-312.pyc b/source/component/__pycache__/menubar.cpython-312.pyc new file mode 100644 index 00000000..51a487c5 Binary files /dev/null and b/source/component/__pycache__/menubar.cpython-312.pyc differ diff --git a/source/component/__pycache__/plant.cpython-312.pyc b/source/component/__pycache__/plant.cpython-312.pyc new file mode 100644 index 00000000..2fae0b33 Binary files /dev/null and b/source/component/__pycache__/plant.cpython-312.pyc differ diff --git a/source/component/__pycache__/zombie.cpython-312.pyc b/source/component/__pycache__/zombie.cpython-312.pyc new file mode 100644 index 00000000..7eaed3fa Binary files /dev/null and b/source/component/__pycache__/zombie.cpython-312.pyc differ diff --git a/source/component/plant.py b/source/component/plant.py index 684065b1..bf261e24 100644 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -54,6 +54,7 @@ def __init__(self, x, start_y, dest_y, name, damage, ice): self.ice = ice self.state = c.FLY self.current_time = 0 + self.knockback = 0 # 击退效果,默认为0表示没有击退 def loadFrames(self, frames, name): frame_list = tool.GFX[name] @@ -825,6 +826,64 @@ def loadImages(self, name, scale): self.frames = self.idle_frames +# Chinese Red Theme Plants +class RedPeony(Plant): + """红牡丹 - 中国红主题植物,能够释放花粉攻击多个僵尸""" + def __init__(self, x, y, zombie_groups, map_y): + Plant.__init__(self, x, y, c.RED_PEONY, c.RED_PEONY_HEALTH, None) + self.shoot_timer = 0 + self.map_y = map_y + self.zombie_groups = zombie_groups + self.attack_range = 3 # 攻击范围为3行 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 3000: + # 释放花粉攻击范围内的所有僵尸 + for i in range(-self.attack_range, self.attack_range + 1): + tmp_y = self.map_y + i + if tmp_y < 0 or tmp_y >= c.GRID_Y_LEN: + continue + for zombie in self.zombie_groups[tmp_y]: + if self.canAttack(zombie): + zombie.setDamage(c.RED_PEONY_POLLEN_DAMAGE) + self.shoot_timer = self.current_time + + def canAttack(self, zombie): + if (self.state != c.SLEEP and zombie.state != c.DIE and + self.rect.x <= zombie.rect.right and + self.rect.right + c.GRID_X_SIZE * 2 >= zombie.rect.x): + return True + return False + +class FirecrackerPlant(Plant): + """鞭炮花 - 中国红主题植物,能够发射鞭炮攻击僵尸""" + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.FIRECRACKER_PLANT, c.FIRECRACKER_PLANT_HEALTH, bullet_group) + self.shoot_timer = 0 + self.bullet_speed = 6 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2500: + # 发射鞭炮子弹 + self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, + c.BULLET_PEA, c.FIRECRACKER_DAMAGE, False)) + self.shoot_timer = self.current_time + +class LionDancePea(Plant): + """舞狮豌豆 - 中国红主题植物,能够发射具有击退效果的豌豆""" + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.LION_DANCE_PEA, c.LION_DANCE_PEA_HEALTH, bullet_group) + self.shoot_timer = 0 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 3000: + # 发射具有击退效果的豌豆 + bullet = Bullet(self.rect.right, self.rect.y, self.rect.y, + c.BULLET_PEA, c.LION_DANCE_PEA_DAMAGE, False) + bullet.knockback = c.LION_DANCE_PEA_KNOCKBACK + self.bullet_group.add(bullet) + self.shoot_timer = self.current_time + class WallNutBowling(Plant): def __init__(self, x, y, map_y, level): Plant.__init__(self, x, y, c.WALLNUTBOWLING, 1, None) diff --git a/source/component/zombie.py b/source/component/zombie.py index 73780f13..133c004f 100644 --- a/source/component/zombie.py +++ b/source/component/zombie.py @@ -411,4 +411,148 @@ def loadImages(self): color = c.WHITE self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'], color) - self.frames = self.helmet_walk_frames \ No newline at end of file + self.frames = self.helmet_walk_frames + +# Chinese Red Theme Zombies +class LanternZombie(Zombie): + """灯笼僵尸 - 中国红主题僵尸,手持灯笼照亮周围区域""" + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.LANTERN_ZOMBIE, c.LANTERN_ZOMBIE_HEALTH, head_group) + self.speed = c.LANTERN_ZOMBIE_SPEED + self.lantern_light_range = c.LANTERN_LIGHT_RANGE + self.lantern_on = True + + def loadImages(self): + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + walk_name = self.name + attack_name = self.name + 'Attack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = c.NORMAL_ZOMBIE + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.walk_frames + +class LionDanceZombie(Zombie): + """舞狮僵尸 - 中国红主题僵尸,穿着舞狮服装,具有较高的生命值和攻击力""" + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.LION_DANCE_ZOMBIE, c.LION_DANCE_ZOMBIE_HEALTH, head_group) + self.speed = c.LION_DANCE_ZOMBIE_SPEED + self.damage = c.LION_DANCE_ATTACK_DAMAGE + self.helmet = True + + def loadImages(self): + self.helmet_walk_frames = [] + self.helmet_attack_frames = [] + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + helmet_walk_name = self.name + helmet_attack_name = self.name + 'Attack' + walk_name = self.name + 'NoCostume' + attack_name = self.name + 'NoCostumeAttack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = self.name + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, + self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [helmet_walk_name, helmet_attack_name, + walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.helmet_walk_frames + +class ChineseNewYearZombie(Zombie): + """春节僵尸 - 中国红主题僵尸,穿着春节服装,死亡时掉落金币""" + def __init__(self, x, y, head_group, gold_group): + Zombie.__init__(self, x, y, c.CHINESE_NEW_YEAR_ZOMBIE, c.CHINESE_NEW_YEAR_ZOMBIE_HEALTH, head_group) + self.speed = c.CHINESE_NEW_YEAR_ZOMBIE_SPEED + self.gold_group = gold_group + self.gold_drop = c.CHINESE_NEW_YEAR_GOLD_DROP + + def loadImages(self): + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + walk_name = self.name + attack_name = self.name + 'Attack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = self.name + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.walk_frames + + def dying(self): + # 死亡时掉落金币 + if not self.dead: + for i in range(self.gold_drop): + gold = Gold(self.rect.centerx, self.rect.y) + self.gold_group.add(gold) + self.dead = True + super().dying() + +class Gold(pg.sprite.Sprite): + """金币类 - 春节僵尸死亡时掉落""" + def __init__(self, x, y): + pg.sprite.Sprite.__init__(self) + self.image = tool.get_image(tool.GFX['Gold'], 0, 0, 30, 30, c.BLACK, 1) + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.y = y + self.y_vel = -2 # 金币向上飘 + self.gravity = 0.1 # 重力效果 + self.live_time = 5000 # 金币存在时间 + self.created_time = pg.time.get_ticks() + + def update(self, game_info): + # 金币向上飘然后下落 + self.y_vel += self.gravity + self.rect.y += self.y_vel + + # 金币存在时间结束后消失 + if pg.time.get_ticks() - self.created_time > self.live_time: + self.kill() + + def checkCollision(self, x, y): + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + self.kill() + return True + return False \ No newline at end of file diff --git a/source/constants.py b/source/constants.py index 0c4e2b6e..b4950f25 100644 --- a/source/constants.py +++ b/source/constants.py @@ -93,6 +93,10 @@ HYPNOSHROOM = 'HypnoShroom' WALLNUTBOWLING = 'WallNutBowling' REDWALLNUTBOWLING = 'RedWallNutBowling' +# Chinese Red Theme Plants +RED_PEONY = 'RedPeony' # 红牡丹 +FIRECRACKER_PLANT = 'FirecrackerPlant' # 鞭炮花 +LION_DANCE_PEA = 'LionDancePea' # 舞狮豌豆 PLANT_HEALTH = 5 WALLNUT_HEALTH = 30 @@ -100,6 +104,15 @@ WALLNUT_CRACKED2_HEALTH = 10 WALLNUT_BOWLING_DAMAGE = 10 +# Chinese Red Theme Plant Properties +RED_PEONY_HEALTH = 15 # 红牡丹生命值 +RED_PEONY_POLLEN_DAMAGE = 3 # 红牡丹花粉伤害 +FIRECRACKER_PLANT_HEALTH = 10 # 鞭炮花生命值 +FIRECRACKER_DAMAGE = 2 # 鞭炮伤害 +LION_DANCE_PEA_HEALTH = 5 # 舞狮豌豆生命值 +LION_DANCE_PEA_DAMAGE = 4 # 舞狮豌豆伤害 +LION_DANCE_PEA_KNOCKBACK = 50 # 舞狮豌豆击退效果 + PRODUCE_SUN_INTERVAL = 7000 FLOWER_SUN_INTERVAL = 22000 SUN_LIVE_TIME = 7000 @@ -129,6 +142,10 @@ CARD_ICESHROOM = 'card_iceshroom' CARD_HYPNOSHROOM = 'card_hypnoshroom' CARD_REDWALLNUT = 'card_redwallnut' +# Chinese Red Theme Plant Cards +CARD_RED_PEONY = 'card_redpeony' +CARD_FIRECRACKER_PLANT = 'card_firecrackerplant' +CARD_LION_DANCE_PEA = 'card_liondancepea' #BULLET INFO BULLET_PEA = 'PeaNormal' @@ -145,6 +162,10 @@ FLAG_ZOMBIE = 'FlagZombie' NEWSPAPER_ZOMBIE = 'NewspaperZombie' BOOMDIE = 'BoomDie' +# Chinese Red Theme Zombies +LANTERN_ZOMBIE = 'LanternZombie' # 灯笼僵尸 +LION_DANCE_ZOMBIE = 'LionDanceZombie' # 舞狮僵尸 +CHINESE_NEW_YEAR_ZOMBIE = 'ChineseNewYearZombie' # 春节僵尸 LOSTHEAD_HEALTH = 5 NORMAL_HEALTH = 10 @@ -153,6 +174,17 @@ BUCKETHEAD_HEALTH = 30 NEWSPAPER_HEALTH = 15 +# Chinese Red Theme Zombie Properties +LANTERN_ZOMBIE_HEALTH = 15 # 灯笼僵尸生命值 +LANTERN_ZOMBIE_SPEED = 1.2 # 灯笼僵尸移动速度 +LANTERN_LIGHT_RANGE = 3 # 灯笼照亮范围 +LION_DANCE_ZOMBIE_HEALTH = 30 # 舞狮僵尸生命值 +LION_DANCE_ZOMBIE_SPEED = 0.8 # 舞狮僵尸移动速度 +LION_DANCE_ATTACK_DAMAGE = 2 # 舞狮僵尸攻击伤害 +CHINESE_NEW_YEAR_ZOMBIE_HEALTH = 25 # 春节僵尸生命值 +CHINESE_NEW_YEAR_ZOMBIE_SPEED = 1.0 # 春节僵尸移动速度 +CHINESE_NEW_YEAR_GOLD_DROP = 5 # 春节僵尸掉落金币数量 + ATTACK_INTERVAL = 1000 ZOMBIE_WALK_INTERVAL = 70 diff --git a/source/state/__pycache__/__init__.cpython-312.pyc b/source/state/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 00000000..58f7eae1 Binary files /dev/null and b/source/state/__pycache__/__init__.cpython-312.pyc differ diff --git a/source/state/__pycache__/level.cpython-312.pyc b/source/state/__pycache__/level.cpython-312.pyc new file mode 100644 index 00000000..a25d4b94 Binary files /dev/null and b/source/state/__pycache__/level.cpython-312.pyc differ diff --git a/source/state/__pycache__/mainmenu.cpython-312.pyc b/source/state/__pycache__/mainmenu.cpython-312.pyc new file mode 100644 index 00000000..a64d3d7a Binary files /dev/null and b/source/state/__pycache__/mainmenu.cpython-312.pyc differ diff --git a/source/state/__pycache__/screen.cpython-312.pyc b/source/state/__pycache__/screen.cpython-312.pyc new file mode 100644 index 00000000..ce3bd80d Binary files /dev/null and b/source/state/__pycache__/screen.cpython-312.pyc differ diff --git a/source/state/level.py b/source/state/level.py index 133cc28a..d7dc76f8 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -42,6 +42,7 @@ def setupBackground(self): def setupGroups(self): self.sun_group = pg.sprite.Group() self.head_group = pg.sprite.Group() + self.gold_group = pg.sprite.Group() # 金币组 self.plant_groups = [] self.zombie_groups = [] @@ -148,6 +149,7 @@ def play(self, mouse_pos, mouse_click): self.head_group.update(self.game_info) self.sun_group.update(self.game_info) + self.gold_group.update(self.game_info) if not self.drag_plant and mouse_pos and mouse_click[0]: result = self.menubar.checkCardClick(mouse_pos) @@ -174,6 +176,11 @@ def play(self, mouse_pos, mouse_click): for sun in self.sun_group: if sun.checkCollision(mouse_pos[0], mouse_pos[1]): self.menubar.increaseSunValue(sun.sun_value) + # 收集金币 + for gold in self.gold_group: + if gold.checkCollision(mouse_pos[0], mouse_pos[1]): + self.menubar.increaseGoldValue(gold.gold_value) + gold.kill() for car in self.cars: car.update(self.game_info) @@ -198,6 +205,13 @@ def createZombie(self, name, map_y): self.zombie_groups[map_y].add(zombie.FlagZombie(c.ZOMBIE_START_X, y, self.head_group)) elif name == c.NEWSPAPER_ZOMBIE: self.zombie_groups[map_y].add(zombie.NewspaperZombie(c.ZOMBIE_START_X, y, self.head_group)) + # Chinese Red Theme Zombies + elif name == c.LANTERN_ZOMBIE: + self.zombie_groups[map_y].add(zombie.LanternZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.LION_DANCE_ZOMBIE: + self.zombie_groups[map_y].add(zombie.LionDanceZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.CHINESE_NEW_YEAR_ZOMBIE: + self.zombie_groups[map_y].add(zombie.ChineseNewYearZombie(c.ZOMBIE_START_X, y, self.head_group, self.gold_group)) def canSeedPlant(self): x, y = pg.mouse.get_pos() @@ -250,6 +264,13 @@ def addPlant(self): new_plant = plant.WallNutBowling(x, y, map_y, self) elif self.plant_name == c.REDWALLNUTBOWLING: new_plant = plant.RedWallNutBowling(x, y) + # Chinese Red Theme Plants + elif self.plant_name == c.RED_PEONY: + new_plant = plant.RedPeony(x, y, self.zombie_groups, map_y) + elif self.plant_name == c.FIRECRACKER_PLANT: + new_plant = plant.FirecrackerPlant(x, y, self.bullet_groups[map_y]) + elif self.plant_name == c.LION_DANCE_PEA: + new_plant = plant.LionDancePea(x, y, self.bullet_groups[map_y]) if new_plant.can_sleep and self.background_type == c.BACKGROUND_DAY: new_plant.setSleep() @@ -544,6 +565,7 @@ def draw(self, surface): car.draw(surface) self.head_group.draw(surface) self.sun_group.draw(surface) + self.gold_group.draw(surface) if self.drag_plant: self.drawMouseShow(surface) \ No newline at end of file