From c592d204efd9cca2c61074d06531cd2ac60c249a Mon Sep 17 00:00:00 2001 From: lbj-cmd Date: Thu, 6 Nov 2025 10:31:57 +0800 Subject: [PATCH 1/2] Applying my 802 file changes --- source/1.txt | 980 ++++++++++++++++++ source/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 167 bytes source/__pycache__/constants.cpython-39.pyc | Bin 0 -> 4517 bytes source/__pycache__/main.cpython-39.pyc | Bin 0 -> 670 bytes source/__pycache__/tool.cpython-39.pyc | Bin 0 -> 5427 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 177 bytes .../__pycache__/grave.cpython-39.pyc | Bin 0 -> 4229 bytes .../component/__pycache__/map.cpython-39.pyc | Bin 0 -> 2320 bytes .../__pycache__/menubar.cpython-39.pyc | Bin 0 -> 14668 bytes .../__pycache__/plant.cpython-39.pyc | Bin 0 -> 31863 bytes .../__pycache__/zombie.cpython-39.pyc | Bin 0 -> 11691 bytes source/component/grave.py | 134 +++ source/component/menubar.py | 11 +- source/component/plant.py | 30 +- source/constants.py | 10 +- .../state/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 173 bytes source/state/__pycache__/level.cpython-39.pyc | Bin 0 -> 17158 bytes .../state/__pycache__/mainmenu.cpython-39.pyc | Bin 0 -> 2416 bytes .../state/__pycache__/screen.cpython-39.pyc | Bin 0 -> 2781 bytes source/state/level.py | 48 +- test_night_level.py | 64 ++ 21 files changed, 1264 insertions(+), 13 deletions(-) create mode 100644 source/1.txt create mode 100644 source/__pycache__/__init__.cpython-39.pyc create mode 100644 source/__pycache__/constants.cpython-39.pyc create mode 100644 source/__pycache__/main.cpython-39.pyc create mode 100644 source/__pycache__/tool.cpython-39.pyc create mode 100644 source/component/__pycache__/__init__.cpython-39.pyc create mode 100644 source/component/__pycache__/grave.cpython-39.pyc create mode 100644 source/component/__pycache__/map.cpython-39.pyc create mode 100644 source/component/__pycache__/menubar.cpython-39.pyc create mode 100644 source/component/__pycache__/plant.cpython-39.pyc create mode 100644 source/component/__pycache__/zombie.cpython-39.pyc create mode 100644 source/component/grave.py create mode 100644 source/state/__pycache__/__init__.cpython-39.pyc create mode 100644 source/state/__pycache__/level.cpython-39.pyc create mode 100644 source/state/__pycache__/mainmenu.cpython-39.pyc create mode 100644 source/state/__pycache__/screen.cpython-39.pyc create mode 100644 test_night_level.py diff --git a/source/1.txt b/source/1.txt new file mode 100644 index 00000000..4f69b6a4 --- /dev/null +++ b/source/1.txt @@ -0,0 +1,980 @@ + + + + +我需要了解当前的关卡系统实现,以便添加黑夜关卡类型。让我搜索关卡相关的代码。 + + +toolName: search_codebase + +status: success + +query: level state game mode implementation + +我需要查看常量文件,了解当前的背景类型和游戏模式定义,以便添加黑夜关卡相关的常量。 + + +toolName: search_codebase + +status: success + +query: BACKGROUND_DAY BACKGROUND_TYPE game mode constants + +我需要查看植物类的实现,了解阳光蘑菇、喷气蘑菇和墓碑吞噬者的当前状态。 + + +toolName: search_codebase + +status: success + +query: SunShroom PuffShroom GraveBuster implementation + +我需要查看阳光蘑菇的完整实现代码,以了解其当前的行为和需要修改的地方。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\plant.py + +我需要查看地图组件的实现,以了解如何添加墓碑机制。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\map.py + +现在我已经了解了游戏的基本结构,让我开始实现黑夜关卡和新植物。首先,我需要修改level.py文件来添加黑夜环境的支持。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: def setupBackground(self): + img_index = self.map_data[c.BACKGROUND_TYPE] + self.background_type = img_index + self.background = tool.GFX[c.BACKGROUND_NAME][img_index] + self.bg_rect = self.background.get_rect() + + self.level = pg.Surface((self.bg_rect.w, self.bg_rect.h)).convert() + self.viewport = tool.SCREEN.get_rect(bottom=self.bg_rect.bottom) + self.viewport.x += c.BACKGROUND_OFFSET_X + + # Add night blue filter for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.night_filter = pg.Surface((self.bg_rect.w, self.bg_rect.h)) + self.night_filter.fill((0, 0, 100)) # Dark blue color + self.night_filter.set_alpha(80) # Transparency level + +oldStr: def setupBackground(self): + img_index = self.map_data[c.BACKGROUND_TYPE] + self.background_type = img_index + self.background = tool.GFX[c.BACKGROUND_NAME][img_index] + self.bg_rect = self.background.get_rect() + + self.level = pg.Surface((self.bg_rect.w, self.bg_rect.h)).convert() + self.viewport = tool.SCREEN.get_rect(bottom=self.bg_rect.bottom) + self.viewport.x += c.BACKGROUND_OFFSET_X + + +现在我需要修改draw方法来应用黑夜滤镜。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: def draw(self, surface): + self.level.blit(self.background, self.viewport, self.viewport) + + # Apply night filter for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.level.blit(self.night_filter, (0, 0)) + + surface.blit(self.level, (0,0), self.viewport) + +oldStr: def draw(self, surface): + self.level.blit(self.background, self.viewport, self.viewport) + surface.blit(self.level, (0,0), self.viewport) + + +现在我需要修改阳光蘑菇的实现,使其符合需求:小蘑菇每15秒产生15阳光,60秒后长大,之后每15秒产生25阳光。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\plant.py + +changes: + +newStr: class SunShroom(Plant): + def __init__(self, x, y, sun_group): + Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None) + self.can_sleep = True + self.animate_interval = 200 + self.sun_timer = 0 + self.sun_group = sun_group + self.is_big = False + self.change_timer = 0 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.big_frames = [] + self.sleep_frames = [] + + idle_name = name + big_name = name + 'Big' + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.big_frames, self.sleep_frames] + name_list = [idle_name, big_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def idling(self): + if not self.is_big: + if self.change_timer == 0: + self.change_timer = self.current_time + elif (self.current_time - self.change_timer) > 60000: # 60 seconds to grow + self.changeFrames(self.big_frames) + self.is_big = True + + # Produce sun every 15 seconds + if self.sun_timer == 0: + self.sun_timer = self.current_time + elif (self.current_time - self.sun_timer) > 15000: + # Small sunshroom produces 15 sun, big one produces 25 + sun_value = 25 if self.is_big else 15 + # Create sun with appropriate value + sun = Sun(self.rect.centerx, self.rect.bottom, self.rect.right, + self.rect.bottom + self.rect.h // 2, self.is_big) + sun.sun_value = sun_value + self.sun_group.add(sun) + self.sun_timer = self.current_time + +oldStr: class SunShroom(Plant): + def __init__(self, x, y, sun_group): + Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None) + self.can_sleep = True + self.animate_interval = 200 + self.sun_timer = 0 + self.sun_group = sun_group + self.is_big = False + self.change_timer = 0 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.big_frames = [] + self.sleep_frames = [] + + idle_name = name + big_name = name + 'Big' + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.big_frames, self.sleep_frames] + name_list = [idle_name, big_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def idling(self): + if not self.is_big: + if self.change_timer == 0: + self.change_timer = self.current_time + elif (self.current_time - self.change_timer) > 25000: + self.changeFrames(self.big_frames) + self.is_big = True + + if self.sun_timer == 0: + 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, self.is_big)) + self.sun_timer = self.current_time + + +现在我需要修改喷气蘑菇的实现,使其符合需求:近距离(3格)喷射攻击,30秒后自动消失。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\plant.py + +changes: + +newStr: class PuffShroom(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) + self.can_sleep = True + self.shoot_timer = 0 + self.life_timer = 0 # Timer for automatic disappearance + self.life_duration = 30000 # 30 seconds + + def loadImages(self, name, scale): + self.idle_frames = [] + self.sleep_frames = [] + + idle_name = name + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.sleep_frames] + name_list = [idle_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1) + + self.frames = self.idle_frames + + def handleState(self): + # Check if PuffShroom should disappear + if self.life_timer == 0: + self.life_timer = self.current_time + elif (self.current_time - self.life_timer) > self.life_duration: + self.health = 0 # Set health to 0 to trigger removal + else: + super().handleState() + + def attacking(self): + if (self.current_time - self.shoot_timer) > 3000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, + c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) + self.shoot_timer = self.current_time + + def canAttack(self, zombie): + # Close range attack (3 grids) + if (self.rect.x <= zombie.rect.right and + (self.rect.right + c.GRID_X_SIZE * 3 >= zombie.rect.x)): + return True + return False + +oldStr: class PuffShroom(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) + self.can_sleep = True + self.shoot_timer = 0 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.sleep_frames = [] + + idle_name = name + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.sleep_frames] + name_list = [idle_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1) + + self.frames = self.idle_frames + + def attacking(self): + if (self.current_time - self.shoot_timer) > 3000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, + c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) + self.shoot_timer = self.current_time + + def canAttack(self, zombie): + if (self.rect.x <= zombie.rect.right and + (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)): + return True + return False + + +现在我需要实现墓碑和墓碑吞噬者。首先,我需要在constants.py中添加相关常量。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\constants.py + +我需要在constants.py中添加墓碑和墓碑吞噬者的相关常量。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\constants.py + +changes: + +newStr: #BACKGROUND +BACKGROUND_DAY = 0 +BACKGROUND_NIGHT = 1 + +#GRAVE +GRAVE = 'Grave' +GRAVE_BUSTER = 'GraveBuster' +GRAVE_BUSTER_EAT_TIME = 5000 # 5 seconds to eat grave + +#PLANT CARD INFO +CARD_GRAVE_BUSTER = 'card_grave_buster' + +oldStr: #BACKGROUND +BACKGROUND_DAY = 0 +BACKGROUND_NIGHT = 1 + + +现在我需要在menubar.py中添加墓碑吞噬者的卡片信息。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\menubar.py + +changes: + +newStr: card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c.CARD_WALLNUT, + c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, + c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, + c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, + c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT, c.CARD_GRAVE_BUSTER] +plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, + c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, + c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, + c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, + c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, c.GRAVE_BUSTER] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, + 125, 25, 25, 75, 75, 0, 0, 75] +plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, + 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0, 7500] +all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + +oldStr: card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c.CARD_WALLNUT, + c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, + c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, + c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, + c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT] +plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, + c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, + c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, + c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, + c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, + 125, 25, 25, 75, 75, 0, 0] +plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, + 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0] +all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + + +现在我需要实现墓碑类。我将在map.py中添加墓碑相关的功能,或者创建一个新的组件类。 + + +toolName: write_to_file + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\component\grave.py + +content: __author__ = 'marble_xu' + +import pygame as pg +from .. import tool +from .. import constants as c + +class Grave(pg.sprite.Sprite): + def __init__(self, x, y): + pg.sprite.Sprite.__init__(self) + + self.name = c.GRAVE + self.frames = [] + self.frame_index = 0 + self.loadImages() + self.frame_num = len(self.frames) + + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.bottom = y + + self.health = 10 # Grave health + self.dead = False + + self.animate_timer = 0 + self.animate_interval = 150 + + def loadImages(self): + # Load grave images + grave_name = self.name + self.loadFrames(self.frames, grave_name, 1) + + def loadFrames(self, frame_list, name, scale): + # Load frames from sprite sheet + frame_rect = tool.GRAVE_RECT[name] + for i in range(frame_rect['frame_num']): + x = frame_rect['x'] + i * frame_rect['width'] + y = frame_rect['y'] + width = frame_rect['width'] + height = frame_rect['height'] + image = tool.get_image(tool.GFX[name], x, y, width, height, c.BLACK, scale) + frame_list.append(image) + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + self.animation() + + 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 + self.image = self.frames[self.frame_index] + + def setDamage(self, damage): + self.health -= damage + if self.health <= 0: + self.dead = True + self.kill() + +class GraveBuster(pg.sprite.Sprite): + def __init__(self, x, y, grave): + pg.sprite.Sprite.__init__(self) + + self.name = c.GRAVE_BUSTER + self.frames = [] + self.frame_index = 0 + self.loadImages() + self.frame_num = len(self.frames) + + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.bottom = y + + self.grave = grave + self.eat_timer = 0 + self.eat_duration = c.GRAVE_BUSTER_EAT_TIME + self.state = c.IDLE + + self.animate_timer = 0 + self.animate_interval = 150 + + def loadImages(self): + # Load grave buster images + buster_name = self.name + self.loadFrames(self.frames, buster_name, 1) + + def loadFrames(self, frame_list, name, scale): + # Load frames from sprite sheet + frame_rect = tool.PLANT_RECT[name] + for i in range(frame_rect['frame_num']): + x = frame_rect['x'] + i * frame_rect['width'] + y = frame_rect['y'] + width = frame_rect['width'] + height = frame_rect['height'] + image = tool.get_image(tool.GFX[name], x, y, width, height, c.BLACK, scale) + frame_list.append(image) + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + self.handleState() + self.animation() + + def handleState(self): + if self.state == c.IDLE: + self.idling() + elif self.state == c.ATTACK: + self.attacking() + + def idling(self): + # Start eating grave + self.state = c.ATTACK + self.eat_timer = self.current_time + + def attacking(self): + # Check if done eating + if (self.current_time - self.eat_timer) > self.eat_duration: + # Destroy both grave and grave buster + self.grave.setDamage(10) # Enough damage to destroy grave + self.kill() + + 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 = self.frame_num - 1 # Stay on last frame + self.animate_timer = self.current_time + self.image = self.frames[self.frame_index] + + def canAttack(self, zombie): + # Grave buster doesn't attack zombies + return False + +现在我需要在level.py中添加墓碑的生成和管理功能。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: from .. import tool +from .. import constants as c +from ..component import map, plant, zombie, menubar, grave + +oldStr: from .. import tool +from .. import constants as c +from ..component import map, plant, zombie, menubar + + +现在我需要在setupGroups方法中添加墓碑组。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: def setupGroups(self): + self.sun_group = pg.sprite.Group() + self.head_group = pg.sprite.Group() + self.grave_group = pg.sprite.Group() + + self.plant_groups = [] + self.zombie_groups = [] + self.hypno_zombie_groups = [] #zombies who are hypno after eating hypnoshroom + self.bullet_groups = [] + for i in range(self.map_y_len): + self.plant_groups.append(pg.sprite.Group()) + self.zombie_groups.append(pg.sprite.Group()) + self.hypno_zombie_groups.append(pg.sprite.Group()) + self.bullet_groups.append(pg.sprite.Group()) + +oldStr: def setupGroups(self): + self.sun_group = pg.sprite.Group() + self.head_group = pg.sprite.Group() + + self.plant_groups = [] + self.zombie_groups = [] + self.hypno_zombie_groups = [] #zombies who are hypno after eating hypnoshroom + self.bullet_groups = [] + for i in range(self.map_y_len): + self.plant_groups.append(pg.sprite.Group()) + self.zombie_groups.append(pg.sprite.Group()) + self.hypno_zombie_groups.append(pg.sprite.Group()) + self.bullet_groups.append(pg.sprite.Group()) + + +现在我需要在initPlay方法中添加墓碑的生成逻辑。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: self.removeMouseImage() + self.setupGroups() + self.setupZombies() + self.setupCars() + + # Generate graves for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.generateGraves() + +oldStr: self.removeMouseImage() + self.setupGroups() + self.setupZombies() + self.setupCars() + + +现在我需要实现generateGraves方法,在黑夜关卡的2-5列随机生成5-8个墓碑。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: def generateGraves(self): + import random + num_graves = random.randint(5, 8) + + for _ in range(num_graves): + # Random column between 2 and 5 (inclusive) + map_x = random.randint(2, 5) + # Random row between 0 and 4 (inclusive) + map_y = random.randint(0, self.map_y_len - 1) + + # Get the position for the grave + x, y = self.map.getMapGridPos(map_x, map_y) + + # Create and add the grave + new_grave = grave.Grave(x, y) + self.grave_group.add(new_grave) + + def createZombie(self, name, map_y): + x, y = self.map.getMapGridPos(0, map_y) + if name == c.NORMAL_ZOMBIE: + self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.CONEHEAD_ZOMBIE: + self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.BUCKETHEAD_ZOMBIE: + self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.FLAG_ZOMBIE: + 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)) + +oldStr: def createZombie(self, name, map_y): + x, y = self.map.getMapGridPos(0, map_y) + if name == c.NORMAL_ZOMBIE: + self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.CONEHEAD_ZOMBIE: + self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.BUCKETHEAD_ZOMBIE: + self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X, y, self.head_group)) + elif name == c.FLAG_ZOMBIE: + 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)) + + +现在我需要在addPlant方法中添加墓碑吞噬者的支持。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: elif self.plant_name == c.HYPNOSHROOM: + new_plant = plant.HypnoShroom(x, y) + elif self.plant_name == c.WALLNUTBOWLING: + new_plant = plant.WallNutBowling(x, y, map_y, self) + elif self.plant_name == c.REDWALLNUTBOWLING: + new_plant = plant.RedWallNutBowling(x, y) + elif self.plant_name == c.GRAVE_BUSTER: + # Check if there's a grave at this position + for g in self.grave_group: + if g.rect.collidepoint(x, y): + new_plant = grave.GraveBuster(x, y, g) + break + else: + # No grave found, can't plant + return + +oldStr: elif self.plant_name == c.HYPNOSHROOM: + new_plant = plant.HypnoShroom(x, y) + elif self.plant_name == c.WALLNUTBOWLING: + new_plant = plant.WallNutBowling(x, y, map_y, self) + elif self.plant_name == c.REDWALLNUTBOWLING: + new_plant = plant.RedWallNutBowling(x, y) + + +现在我需要在update方法中更新墓碑组,并在draw方法中绘制墓碑。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: self.head_group.update(self.game_info) + self.sun_group.update(self.game_info) + self.grave_group.update(self.game_info) + +oldStr: self.head_group.update(self.game_info) + self.sun_group.update(self.game_info) + + +现在我需要在draw方法中绘制墓碑。 + + +toolName: edit_file_update + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +changes: + +newStr: # Draw graves + self.grave_group.draw(surface) + + for i in range(self.map_y_len): + self.plant_groups[i].draw(surface) + self.zombie_groups[i].draw(surface) + self.hypno_zombie_groups[i].draw(surface) + self.bullet_groups[i].draw(surface) + self.drawZombieFreezeTrap(i, surface) + +oldStr: for i in range(self.map_y_len): + self.plant_groups[i].draw(surface) + self.zombie_groups[i].draw(surface) + self.hypno_zombie_groups[i].draw(surface) + self.bullet_groups[i].draw(surface) + self.drawZombieFreezeTrap(i, surface) + + +现在我需要创建一个测试关卡来验证这些功能是否正常工作。我将创建一个新的level_4.json文件作为黑夜关卡。 + + +toolName: write_to_file + +status: failed + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\data\map\level_4.json + + +文件已存在,我需要先查看其内容,然后再修改。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\data\map\level_4.json + +我需要创建一个新的黑夜关卡文件,让我使用level_5.json。 + + +toolName: write_to_file + +status: failed + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\data\map\level_5.json + + +让我查看现有的关卡文件,然后选择一个合适的编号创建新的黑夜关卡。 + + +toolName: view_folder + +status: success + +e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\data\map + +让我检查level_3.json是否已经是黑夜关卡。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\data\map\level_3.json + +让我检查是否有现有的测试文件结构。 + + +toolName: view_folder + +status: success + +e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1 + +让我查看main.py文件,了解如何启动游戏和特定关卡。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\main.py + +让我查看source/main.py文件,了解游戏的启动流程。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\main.py + +现在我需要运行游戏来测试黑夜关卡的功能。让我执行main.py来启动游戏。 + + +toolName: run_command + +status: running + +command: python main.py + +让我检查游戏的运行状态,看看是否有任何错误或异常信息。 + + +toolName: check_command_status + +status: success + + +现在我需要创建一个测试用例来验证所有功能是否正常工作。让我创建一个测试脚本。 + + +toolName: write_to_file + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\test_night_level.py + +content: import pygame as pg +import sys +import os + +# 添加source目录到路径 +sys.path.append(os.path.join(os.path.dirname(__file__), 'source')) + +from source import tool +from source import constants as c +from source.state import level + +def test_night_level(): + """测试黑夜关卡功能""" + print("=== 测试黑夜关卡功能 ===") + + # 初始化pygame + pg.init() + screen = pg.display.set_mode((c.SCREEN_WIDTH, c.SCREEN_HEIGHT)) + clock = pg.time.Clock() + + # 创建游戏控制 + game = tool.Control() + + # 创建黑夜关卡 + level_state = level.Level() + + # 模拟加载黑夜关卡 + level_state.setupLevel(3) # level_3.json是黑夜关卡 + + print("1. 测试背景类型是否为黑夜:") + print(f" background_type = {level_state.background_type}") + print(f" 预期: {c.BACKGROUND_NIGHT}") + print(f" 结果: {'通过' if level_state.background_type == c.BACKGROUND_NIGHT else '失败'}") + + print("\n2. 测试是否不生成阳光:") + print(f" produce_sun = {level_state.produce_sun}") + print(f" 预期: False") + print(f" 结果: {'通过' if not level_state.produce_sun else '失败'}") + + print("\n3. 测试墓碑生成:") + print(f" 墓碑数量: {len(level_state.grave_group)}") + print(f" 预期: 5-8个墓碑") + print(f" 结果: {'通过' if 5 <= len(level_state.grave_group) <= 8 else '失败'}") + + # 显示墓碑位置 + for i, grave in enumerate(level_state.grave_group): + print(f" 墓碑{i+1}: 位置 ({grave.map_x}, {grave.map_y})") + + print("\n4. 测试黑夜滤镜是否创建:") + print(f" night_filter存在: {hasattr(level_state, 'night_filter')}") + print(f" 结果: {'通过' if hasattr(level_state, 'night_filter') else '失败'}") + + if hasattr(level_state, 'night_filter'): + print(f" night_filter alpha: {level_state.night_filter.get_alpha()}") + print(f" 预期: 80") + print(f" 结果: {'通过' if level_state.night_filter.get_alpha() == 80 else '失败'}") + + print("\n=== 测试完成 ===") + + # 清理 + pg.quit() + +if __name__ == "__main__": + test_night_level() + +现在我需要运行测试脚本,看看是否有任何错误或异常信息。 + + +toolName: run_command + +status: success + +command: python test_night_level.py + +让我检查Level类的方法名。 + + +toolName: search_by_regex + +status: success + +query: def setup + +让我查看Level类的初始化方法,了解如何正确初始化关卡。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.py + +让我查看Level类的__init__方法,了解如何正确初始化关卡。 + + +toolName: view_files + +status: success + + +filePath: e:\my_code\git\shujvbiaozhu\PythonPlantsVsZombies-master1\source\state\level.pyModel thinking limit reached, please enter 'Continue' to get more. \ No newline at end of file diff --git a/source/__pycache__/__init__.cpython-39.pyc b/source/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..669a2f48c4ad75bc1fe68a35b3a749190c7059cc GIT binary patch literal 167 zcmYe~<>g`kg1J|@GC}lX5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HIt5r;HWqfje zN@`4cW=TwOMrl@AQf6X)RYqw{KxIireqKOMVqQscSaDQ-Zc=7yv2Jc+aY<^CVN7v; kX;E@&OniK1US>&ryk0@&Ee@O9{FKt1R6CF@pMjVG08(8mm;e9( literal 0 HcmV?d00001 diff --git a/source/__pycache__/constants.cpython-39.pyc b/source/__pycache__/constants.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96b75526051b24a6eae40acaa7f728c05c1adf5d GIT binary patch literal 4517 zcma)9TXWmi5tcZK35njOy@G8Cpm+&H7#+TtWdIQS9lpar}5G3=oYE^fnp%E1F{gNFzmbfAkn z;Nvdza1TB~7XrKweTp-r*ar9j_9@l_iuob&L-gPfJMgKK!S3lP_zZpc9DDEuega=& z0AFDrzQz!~g9G?3?!))+0KSh8;RiT`AL1c=gP+2Ws184-7=D7E!B6pX_!)iyKgTcO z7x`@Vwq2*cTC+QjyPBDrayO~{#(B~j z&oH7ff}9v?x1r>=XblS z9j7}uEO@?+tNnK1INihCE**Q-^ZSRzh}(DDp&txKGm$Ce8f4ZWE65ADPmTwH19_Gz z+4uVn6d1eCZD77^w;${V{-BFc+CJi~aM*KT(e1jS)gN@NecKz5@ z=p^IwL}0PK$GmUbL1a5-g8`N+5g4R4S#0?GPD(CmcGvMzK*0#@AS@5U(Cr{k)@Qjhh4<#y~{#|oTw2pLivWsCtC5Lxs511Era&9VEme@OhC(e)2VhPe&f z^OQjd^OZd(2!>@k5fsclN^H-unQB3gxk#N3(CHDHE&G0lTn=`2jJ<&KerSh&!|ggS zYkV@Gy=eEI`@lJH9E98*+p~L4*M|jzqH}N<+p!1}R%$yjTc{6vT|X8U;~>laf#-I2 zVOe+ZQD}UQC4PkwHlN+iGerK@B=Jcm{(;)emCsTI=4cBuuzOS=mPxAR4$n@BXLgdJ zB3Gb1Q6hj#2b8QXC5tP!ql|5{jIBh7>|^= z(6X2?n%SsJrU*GjSZ|f(CUM5ymc_WyOj#BxccCD&eOjU{s~eEf#VXafscW(b*_tX> z>Fg{xC^2_dqbZw`CQG6|Dps1hE-I#FN)2(8pBymX5G2KFh)R=ut3uV{Cm7{xLPNA< z)euL;h+UT|rmD9_Gm$Nnj_fR{A=E@zQltD>LUoVssl)OWL9bexs>*OWF^`}%T{P-Z1t}b+!&Z4kmo!PDrobg^PW zhBP2US)-xeRMx0pM4jfpC>V59llVnLQ8!ZZ+=d{_O4Fn_OI_6UR+-WaC9_TqmC`Ec zOd@-tFh@yfXyl8s!Az{Osy5=f&TCD|d|fAmwpA&MYC}>)dez)(QVbN8CfyY`L~7yO z9YGc}QBm1-5~!(Lu^o#%VWkQkKJr$mw=_kKg~d4PqzKDo{uor`xv7hSOgA<$uwwai ztZh|vYDBSm^?xl~OBPNg7V(}|RfulDil(d8W<`uzRZ=KN>w*j?c70BsVbd_fX514jKDZ};5MmJ zuSCm_*Lx{K(?#cQlFG+hPih?llY$p`EWGNxZzrW+h!&6Pf1K+Qoissga?}Z2p0opx zFx?Y8gh?aNM`BZ!X$Y{MU7YY1IiYdG*BZ^ZqgG;oSJhHfy&=e><#_6(ZdfvisFA9$ z!1XMyM%h&rku4;^a=A&}Wu~FRnk>|k^(95zFf_UadVoI!>iDO1r~Fw1)zW(=7|49xPG3t76ZG?6Fck?vQEzCBW}3HAOTW!DF59y=6f4Mgt`1#hW|I3tbW@w@t*i( c&;Qp;vQzR*{7-yxuhY55HMk~2lRx7A1M-a^9smFU literal 0 HcmV?d00001 diff --git a/source/__pycache__/main.cpython-39.pyc b/source/__pycache__/main.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2199dcebb4b2e8becbbbf9c277c5c49473d3a2c0 GIT binary patch literal 670 zcmYjP&1&2*5SG01Z@t?T`Vv00&}#{$VKHgIy9wQPp~7Iiw#YhIR*>Y-Ey*pf5wMT# z`}E>#Pkn_#p(C}FjG6H_8qME_%K1D(AP?W8<{L)nhjAW@1I}AebquCP6xFzPTFf2l zV1s9XXOvh>T9u=Y17324YmxocVRx&H~RP=Y6-g=pa)R-#k7 z?6gW|Q^3on>-BWapYe`Ncu+MR(B}ez%GWzH69z!Aqr?e3dKF%ZlZu!^`V~44|A3s*b=Q9N_5h z_nVLfw$XJGO;J&lJyexNF(J#7oWXTzGAGy0XBo0=*u`wB9rlqiZ*K~Yxv2Y=y)lnM Nnf}Cyag3ike*nXXq^SS^ literal 0 HcmV?d00001 diff --git a/source/__pycache__/tool.cpython-39.pyc b/source/__pycache__/tool.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f3ce0a6b43a1fb615dd8696e8f7429a83cf7dcd GIT binary patch literal 5427 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 Bv)BLt literal 0 HcmV?d00001 diff --git a/source/component/__pycache__/__init__.cpython-39.pyc b/source/component/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c2349fd86015a4897a2f6fd83bebea172432ece GIT binary patch literal 177 zcmYe~<>g`kg1J|@GC}lX5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_mt5r;HWqfje zN@`4cW=TwOMrl@AQf6X)RYqw{KxIireqKOMVqQscSaDQ-Zc=7yv2Jc+aY<^CVN7v; uX;E@&Omcp1L4ICpUP(-Rd}dx|NqoFsLFFwDo80`A(wtN~kbR$lm;nGp4lmIF literal 0 HcmV?d00001 diff --git a/source/component/__pycache__/grave.cpython-39.pyc b/source/component/__pycache__/grave.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c93475a0a9818958b77aafa883e00c1a83183c1 GIT binary patch literal 4229 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 literal 0 HcmV?d00001 diff --git a/source/component/__pycache__/menubar.cpython-39.pyc b/source/component/__pycache__/menubar.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4bd846fcf4263d58f480d00f5dddb84150427a8 GIT binary patch literal 14668 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 aQuy~jw$qz;E%_UAGlgdhmkZYlr~Vi89^hX9 literal 0 HcmV?d00001 diff --git a/source/component/__pycache__/plant.cpython-39.pyc b/source/component/__pycache__/plant.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9d1a1c470bde697054b2d5b5adda77995038964 GIT binary patch literal 31863 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 OjQ!EvJ92w+@BV-BD}CAk literal 0 HcmV?d00001 diff --git a/source/component/__pycache__/zombie.cpython-39.pyc b/source/component/__pycache__/zombie.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d941c1be330dfdc1451f11207dbb626470e45fc GIT binary patch literal 11691 zcmeHNTWlQHd7jywot?dMdC`Tkt*mS%@!GQNq=jvyhAT=UEyXmYO0?B7N~fzmBXU>E zUHa_O64_;fR!(n8(|drnNkF1~5m4kQ4}B=wJoF(b+CCU43d~c17De^YrvfdIhq&MO zpPAX^EtaF^txL>*u5;#`|9t=L9M(&vyoKMl{wd!)`Z>$`R~ANp4hrY+^u7tAtR+j? zD%G}^QYx*Sc6!xWa%>Cv4Dy*J*S6lUl&iAuTPho*TG^I&KfRPgou_iB%LO@<^C;(4 z0p)^}3n&*=3FVTMizt`X7|LT(E}>je<0y|yxs39JnnZb0%3~^Z-KtH6xz)P9)eii7 z>klzmYvExEv}T7+zuRpi%{986UccVy_Zn;;{iRVjho|>_kic59vDB3M3>W#ny_61| zR_3;?GRj2>%TwO_)>2mGR353P3aW@Sr%I}fG_S@~1!+Nzs|lnC`~PN>hSsyc-)O{%BWGpLzTKczmYK82bi>eK33)Erec z^&HY;>Unhr>2dXfI*W8#y{KM7dP3P?$xnywQg`)MGgx?NV_l6bNc>}-tGzAQK85B$6M2AIiWb4CltqcQd*u8 zdQxgWA^EC|bV^xRcV*pSR15|URwWq_>+H&aj)^xKUgzj~ddcNQ6H2c0EI-U9| z>Thc#y|5rD+Ej2a%(uIBb$PYEjD~bO=!7}b+F4%>Gfmcq-g40Qb=I_?qcl>^H zHPB(H-oc0ZK~yZ(`~7+&ZnPVrb7N-y%`gLSV{w(ZbCYv;uig&J%|_t&+TFXpuJ@bW zk+K;+w*nrRY^Jvs1S%}v)*!y}P-xe)H-^f2G^G+NLPJ(=!n5y|7yE zVZNWa+3T+BMsTyyU0v&Tz{i`Lg5k4k8@h<0Jv_aaK`gtRa&7*3b}?19i%7kwM(UGR z)63A!G4s8%@zyso94q=!85Zz}R4gJxsTicDt*y)eaxiUer*^C@ci^_tc$}2AmEH0N z*+KeM>NQNiG57O& ziaGmkXagkmwY8w5!W>a00ITKo^Jv#)5^{YhEA{@p&}($tU419m2=fM(?Pjm9k8rfi z-KHYuR)Xg8N;BP?Ec``WeHg++hy@>{cEv9Yc-_FWJe z7FOyV)ef!;v`g!23J|~C2(AOoVa_1E+3nO)!XU5=@(a1W-QBxR*Sz{!e6L3cSq3lm zW+_^qX>U+b#y{qhwJo6lU1s&6CGVv4(Rgj0b5X5>+B2w?6?UGBYF*TxN3H12&Qw(E zq4pir=3;K>*DyS``57d_6#X=EVU|ju*@5PoSzMgC@FtclqR*=I#mlo{Mr}y*+_l-+ zrPDY(NP$ zWjtfYE!0==#`umkW!-V~_e=|HjMbXZ-vOO;tQPrQdIg*4Pjx0n>t2;Qu@+8bEp!?y zsvQx921^n2FE#^%&$0O{*B39%&Rq0C<`*yNC(si(1)r7!BNO2iba`LYx9Dw=H5d{M zGmi$*@}-3<*WQ|$j|X{@gA_)3i)4qDh1na|ug+YZz2+}ndF%Y;Sxu?ZualhQD^sT0 zr_T2;FD%YpduL`oEJ9fmZeZ~kNI8={XW&dWMkS(8p5%p5s{LMB0 zq6erDC`Y2f49E_G+a+{s;ptJKTJ~l!`hw`MeWOzpWps@UHfJxO&ao~6)FSduk2HfC z>RYsKXHoXJ#T{&}lyZ^&$#YxLij9v!1pU!5Kr*&Tzl6`$#tz-=FxPD>U)(Lx)3W*c z3SQFhkjQq+uF|H41*4tCyy=_la1e(+kA_t|y$O)v9+j~p9z-*7Tw)c!k7;ydglUv? zaf-Q2gfi>4ra7{=Q++tnEd(<{-TNs~wZq>=rvqw~3MwuK%lRidr z&;q#X4Lm&;!~%@+c4AUS^x!V{f#@M3WZvW*0|y^Q7BjRY$VkabqIqvIoN!w17Ry{+ zS{w~-c6Qs7(8H0C!|^i=VOoywN_3dsJY&>#RUD_Pk;^K4i|T4uHE(ZJ>9|+dy1gd! zXGh|Pg<8&dT;rIR=C0^5649%|1>wge>*&7KoDnZ=*uF>aQcrvdkJ)DUsMNIZT;XqV zqc+o5?4Z_X3uiEK90vm! z{jZSc470Ip?w)VWTX^_AtVyCa*@eZqhu=rV!w*4flOqn&Wp*R;MHTw>_S#C_n8{DD zhZsTg`+-^75^r!jeK`5U=!&mV{sYZJQFVi8r-SOPd|}6xVUsV!}MML*&!{IoCv`V2#Ee!}i11#7}Td@JAi} zG;&lSDL4t~mctsO5XIv|{3VA188anO)H1_U7$YoQzA)=wpTBa$=<9GQq^D?^H4M ztcFW3zS_|2vWJ-6nC+Yeq8#$s7|v&y6H%pOWSpo8a~k50y2fIe#K2x-zk@b~hV{F6 zdSws`3w5DfDToll*n!1@=_4&3zAX~wi4CG1@ohR8NOAN;H3n6=qi}>t8^k`8C6hS>}Wrvcpvt_wZ#Z;>&L5Q8*)B#|^v_ z1A?P3@!Uq7#XYDHg*hXEg@FWS~3Fc<-I5X7mV(1?=z4EPYclAe4 zQIy$vbi-Ue*fZ1kCQchS6WdpayPYJOybr)R_}On7}o2-egXrO3)|1RMI!v;{iq|E_$6q zo=wP$9F3vLoE#wjGm42k3b^F7VN?N`j{6wl;LQtsy9z=^Bp!~-u(mpRNqcO4sk2=`4a3|AJSHDS~0&JQAt*-F^06{@ZX00D63K8MoGAJ7&+-?8Vv>A&#?ojE&>$ zyzj%UUB_jJ9~OQ8-Sv9gw8#;vKp@PVpT~)k{uz8jlhblIq=`FCrLP&WX$B=GoS}T` z84_`-XnpiK5}Ftj)vPfmv2mZdyCj<=zf3X&iR6eB?Sjx0_s)QLcK%d3=eb_qoAi!& zX|L#Iypnemxr~>|yIvt*X3oobj=V{2vg=3gpTpBT4U$~r;KmA9B5AqIv6kSN;u^(F6XE4)~;dA`Uc4r67jc0YI-b|NKS!-+4EPfyv2k0T!8z*0QYTy z(Xia{FjfiIW-lyC1p1&5-CKySD|e8Ey1Cqw!bEbOIP5SyX&&jRe}&^0WB)`1_7zs; znDu!n6xvNQ(LHdWVEh12k4DM3f##}={xgq-`RC#ks`#P9E42@ubj3cI+B~)kHbY@w zc#t_<0Egcm%HFTyv;WNrh*a2KTC?VG<^BkgSH6I&Lu!SOlD((#r9)+pu6{-&P|Wr| z4L^3_%EGMN3m6#;hZWI90jH|pCmAk0k-;hG@JP!aw>OXNp7OzRNT4Npszy^J%9l!vC*esSn0=o1E;DJfb}6`|SK% zBwr;F^G2BIuaT5N9+Zp-Rz{;vBYeB#Es?3O^R?e0`CXFVBcbT&-zTBO=|3R(LlRL7 zdp4fZcAOjkGBUfQ4F=Rm+^E#yYTGXU&`I-H$^D_@h~!Q0fy#*N=|AF!hu@T(AnqGz zn2Zre3#VE0SW;Fwzuve5SM?_?XXEGJzVPO(xq*u$ZM5o9WbM^><(3Uuo8CL||ChGC z(x(5IK>Cy2Xc8b1!LL0gf}hy80gr^?Z{gFg#5*Y%X3b+^I6v2}FMpJk_%S`S!rc7K z8__K;E`eBxuzHwDxXH!Q#e{D=Ih@(S@cfB6Wpu?7r!4m|owEEsr>u}TWkp;W9ORUh z6D5yJxBolUu74Yh98rb|e0{R{W4b#>Mz-UTz`Bi(e_;fyY0a9)0_)g9aJRQsUkmg{ zA@*_n8hst}9Q{9pM^UgF@k&L(9^W(3g8^K|cM@*~|3~`R-VA&OFNrX`B*KWmEUg)O zG?H^8k0$>Z9!(+gXkJGILXW0MUkUeSA0RDml{)mDN?Y self.animate_interval: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.frame_index = 0 + self.animate_timer = self.current_time + self.image = self.frames[self.frame_index] + + def setDamage(self, damage): + self.health -= damage + if self.health <= 0: + self.dead = True + self.kill() + +class GraveBuster(pg.sprite.Sprite): + def __init__(self, x, y, grave): + pg.sprite.Sprite.__init__(self) + + self.name = c.GRAVE_BUSTER + self.frames = [] + self.frame_index = 0 + self.loadImages() + self.frame_num = len(self.frames) + + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.bottom = y + + self.grave = grave + self.eat_timer = 0 + self.eat_duration = c.GRAVE_BUSTER_EAT_TIME + self.state = c.IDLE + + self.animate_timer = 0 + self.animate_interval = 150 + + def loadImages(self): + # Load grave buster images + buster_name = self.name + self.loadFrames(self.frames, buster_name, 1) + + def loadFrames(self, frame_list, name, scale): + # Load frames from sprite sheet + frame_rect = tool.PLANT_RECT[name] + for i in range(frame_rect['frame_num']): + x = frame_rect['x'] + i * frame_rect['width'] + y = frame_rect['y'] + width = frame_rect['width'] + height = frame_rect['height'] + image = tool.get_image(tool.GFX[name], x, y, width, height, c.BLACK, scale) + frame_list.append(image) + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + self.handleState() + self.animation() + + def handleState(self): + if self.state == c.IDLE: + self.idling() + elif self.state == c.ATTACK: + self.attacking() + + def idling(self): + # Start eating grave + self.state = c.ATTACK + self.eat_timer = self.current_time + + def attacking(self): + # Check if done eating + if (self.current_time - self.eat_timer) > self.eat_duration: + # Destroy both grave and grave buster + self.grave.setDamage(10) # Enough damage to destroy grave + self.kill() + + 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 = self.frame_num - 1 # Stay on last frame + self.animate_timer = self.current_time + self.image = self.frames[self.frame_index] + + def canAttack(self, zombie): + # Grave buster doesn't attack zombies + return False \ No newline at end of file diff --git a/source/component/menubar.py b/source/component/menubar.py index 56054a52..a9dd245c 100644 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -15,16 +15,17 @@ c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, - c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT] + c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT, c.CARD_GRAVE_BUSTER] plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, - c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING] -plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75, 75, 0, 0] + c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, c.GRAVE_BUSTER] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, + 125, 25, 25, 75, 75, 0, 0, 75] plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, - 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0] -all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0, 7500] +all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] def getSunValueImage(sun_value): font = pg.font.SysFont(None, 22) diff --git a/source/component/plant.py b/source/component/plant.py index 684065b1..c9d9a7ac 100644 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -453,6 +453,8 @@ def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) self.can_sleep = True self.shoot_timer = 0 + self.life_timer = 0 # Timer for automatic disappearance + self.life_duration = 30000 # 30 seconds def loadImages(self, name, scale): self.idle_frames = [] @@ -469,6 +471,15 @@ def loadImages(self, name, scale): self.frames = self.idle_frames + def handleState(self): + # Check if PuffShroom should disappear + if self.life_timer == 0: + self.life_timer = self.current_time + elif (self.current_time - self.life_timer) > self.life_duration: + self.health = 0 # Set health to 0 to trigger removal + else: + super().handleState() + def attacking(self): if (self.current_time - self.shoot_timer) > 3000: self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, @@ -476,8 +487,9 @@ def attacking(self): self.shoot_timer = self.current_time def canAttack(self, zombie): + # Close range attack (3 grids) if (self.rect.x <= zombie.rect.right and - (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)): + (self.rect.right + c.GRID_X_SIZE * 3 >= zombie.rect.x)): return True return False @@ -736,15 +748,21 @@ def idling(self): if not self.is_big: if self.change_timer == 0: self.change_timer = self.current_time - elif (self.current_time - self.change_timer) > 25000: + elif (self.current_time - self.change_timer) > 60000: # 60 seconds to grow self.changeFrames(self.big_frames) self.is_big = True + # Produce sun every 15 seconds if self.sun_timer == 0: - 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, self.is_big)) + self.sun_timer = self.current_time + elif (self.current_time - self.sun_timer) > 15000: + # Small sunshroom produces 15 sun, big one produces 25 + sun_value = 25 if self.is_big else 15 + # Create sun with appropriate value + sun = Sun(self.rect.centerx, self.rect.bottom, self.rect.right, + self.rect.bottom + self.rect.h // 2, self.is_big) + sun.sun_value = sun_value + self.sun_group.add(sun) self.sun_timer = self.current_time class IceShroom(Plant): diff --git a/source/constants.py b/source/constants.py index 0c4e2b6e..502df212 100644 --- a/source/constants.py +++ b/source/constants.py @@ -177,4 +177,12 @@ #BACKGROUND BACKGROUND_DAY = 0 -BACKGROUND_NIGHT = 1 \ No newline at end of file +BACKGROUND_NIGHT = 1 + +#GRAVE +GRAVE = 'Grave' +GRAVE_BUSTER = 'GraveBuster' +GRAVE_BUSTER_EAT_TIME = 5000 # 5 seconds to eat grave + +#PLANT CARD INFO +CARD_GRAVE_BUSTER = 'card_grave_buster' \ No newline at end of file diff --git a/source/state/__pycache__/__init__.cpython-39.pyc b/source/state/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6191044b12077a85612a13d0f900e0ec04f930bc GIT binary patch literal 173 zcmYe~<>g`kg1J|@GC}lX5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_et5r;HWqfje zN@`4cW=TwOMrl@AQf6X)RYqw{KxIireqKOMVqQscSaDQ-Zc=7yv2Jc+aY<^CVN7v; qX;E@&OmRtKNoq`dd}dx|NqoFsLFFwDo80`A(wtN~kX@gFm;nHHR4y9; literal 0 HcmV?d00001 diff --git a/source/state/__pycache__/level.cpython-39.pyc b/source/state/__pycache__/level.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68533000e21471215511f431929aff2b3c515b1d GIT binary patch literal 17158 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 literal 0 HcmV?d00001 diff --git a/source/state/__pycache__/mainmenu.cpython-39.pyc b/source/state/__pycache__/mainmenu.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d67b25bb953faf26467e41ef8684514ab113010b GIT binary patch literal 2416 zcmZ8j-ESL35Z}FTeb ze=9Kd7Y)uf2ZOty^fs7eO(watdc0{#TRJ_v?=&6GAiI#=rpMVsCOzptXVQAD%#9s48%~phjb{}Q!EYg7x@gUBGp!26uZ}&A*C9MCwS-;)tABr%MQL7VY zt#ohH{eCBIC*!?QYvVB6O9mS~@^L$DCjFf_N zy)isg2n!29DZ#+_xI!M>I5|N`M?YyKla_Ji8U%7>!h|(}JHj^HnXqH`CF2aeM?JZy zd??p^%|q?3*0<}c+8IO#nf8Z~O5-%sg-*L4!Rg&Z&!L>BiWMW`Bpa#kh{AD${0BHU7wggoFL_pE@A%f`i-!W+RN@5oEz z;e7}lWaKM;#K}{TmDyeA3hVF*W;fZ7@KU%F)^*8O$i4&;U0)z8O_C?nK&t_~41EKvmDLEv+=fTD|dDtgJ0Ptm|N>GgAsk zUqvBM#GDcMf#!!bD~G7Ks|ZtCIERf|fa$kDr?_0@WuP-&%yD@W|2OcVEcHMJpPwLf z$ZMAIE(+#S-dmSg$2#Ib&IWSUgx_c1-8iy=2RpVir|W{eiEU7{UUBU8UvTNXFnCf? zJpD)lQxVV(P;iC5QGir9E*g|e(!;1E%F;J|#pur&J}Ct zFF5yfjSm00Y5#na$K`jF>hxR8Kd4>MmBb{RFes*ZG^*Y3q?~;-CX!=Cc6jC%rbY)ib&)CpP8$ph=h!2A6T;>^rJAftfDulP_`Q3d(a|5^~!TH>?>G zR#XR6C;n-Tkc}d2xUlhz>O_<#{J4zS3TW=7g_}7aQ$@|w*wl*OnErv&PU*Q)6xO^Z z7U9oUt(pUTfu_y9R9=3(xrrJOTPthzJOsCB(S+b*l0GCxZ-j}6c4RV$w6oKTGeuda zt`eij*4+HQ^3##pZHH0*she2Qr96Hn$Qk}bv;5F>||ttyhZi1ZE6 zS8?H2`M6}_mhWiP3iQBIT?nCzLi7_k!jFT{Wg(u9+P!?myo>5044dmxQOzjh<5win zvvP*flcVTjq=zo0QNRN`2m(J?2m-T$&*Ee45guuUk9osGdh@h3>}ZzXACx)vU;=8I%m2Y2!#e@(GUN!LO3mf`w;1wa`7 literal 0 HcmV?d00001 diff --git a/source/state/__pycache__/screen.cpython-39.pyc b/source/state/__pycache__/screen.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07753079a84a1b8ccf64fe1a7b75ff7960a59c0d GIT binary patch literal 2781 zcmb_e-EJF26rS1tb(}P9RZ3eGs)`!}4HS?-RfSqA6Cx#U)Ra)HNGoS&;;d_X&Fn5p zBKL}3^9D#s@A3w`2wco9SA7Mp_|B}II*z4QEfbwHzk7babDY-ve1&2B@mD4J+hyz@ z+Dr}yn|q+F2_{&R2`;QIZ(70@PS@@^O@}kAU98=v$JsIyp75VD;Y+9E|7JG>oCG4o zNhkyCL+mSJ4*NN?uLx^{)v7w|wbXW3Mtj9esA7$m7I=+oCr{HZ<}gnCS>EdBSxonn zgI?YPWp}|OYjPNBk)h97(@$k!0d@oR51HuPE;`mVjgBJXm2A{QubpG zQR6{t8}tB_y$6=F4nMSp?1;m8K4g(C7{0a|$)9sD+EElX?QZ0)T&DORjHb z&9t|j$m~|HmE}_1-pbNK#c~Ug$-#~7OM`tCKrB&4mM~uB2j@!1md4h^0UsAfV$$-e~p>-t7jmK}rluZa{wW1befs1!Wb4 z@H|Q=wc1|({)u+WbwI~T#<_M3=X;v(*KCtqbpjddCC#M;2#&&s2Ia zs`SUTP@RJa6@qDJC+T+8A}!sYepq>2*Uok~$<=jw@u7Jk(!Q*@C3yX;P&=(yDoP?c zUs_}`8l;(?E0=LMiJwk6t-WF(P~(elye{vl`p|Ny7SM7kQPfLC zfxa5)Y83raw7TVu=@9BF#2Cmbf|R1Ts*j0LxlAxBCFOznpo}g99ymc5*!c6!O^m}+ zgMe`llzjyD`mT)r8R+xNFncqJ^HlAZUY)6x6A)7!=IjuS%CzBeX&zg~oYKEp6-u!q zAIBAX^^DF}J#zY2;G`Q+EU0ou{h(%*$-l6Cf2|&Et~_}B@X^oF%G&+qx|(GJb%%v+YplA$z7`O7rIvif^1%e7fH@jy?4WN&A!-*<41JJSagk3o1*vt${MK z4^RP26rKGqAXy-rSJOWv>~x=z5LAO5lH*Qaz(p+eop+ldBYKw!GW7r6M61Wlx#&T4bi zj9LZ$nNes)-eA9tG-_+m*3A4;C~D89j1+a5vWf{biawvEO9yw$=JqYsrD;o!6`(0r KtqV67EB^s?KqV*u literal 0 HcmV?d00001 diff --git a/source/state/level.py b/source/state/level.py index 133cc28a..f218e907 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -5,7 +5,7 @@ import pygame as pg from .. import tool from .. import constants as c -from ..component import map, plant, zombie, menubar +from ..component import map, plant, zombie, menubar, grave class Level(tool.State): def __init__(self): @@ -38,10 +38,17 @@ def setupBackground(self): self.level = pg.Surface((self.bg_rect.w, self.bg_rect.h)).convert() self.viewport = tool.SCREEN.get_rect(bottom=self.bg_rect.bottom) self.viewport.x += c.BACKGROUND_OFFSET_X + + # Add night blue filter for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.night_filter = pg.Surface((self.bg_rect.w, self.bg_rect.h)) + self.night_filter.fill((0, 0, 100)) # Dark blue color + self.night_filter.set_alpha(80) # Transparency level def setupGroups(self): self.sun_group = pg.sprite.Group() self.head_group = pg.sprite.Group() + self.grave_group = pg.sprite.Group() self.plant_groups = [] self.zombie_groups = [] @@ -127,6 +134,10 @@ def initPlay(self, card_list): self.setupGroups() self.setupZombies() self.setupCars() + + # Generate graves for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.generateGraves() def play(self, mouse_pos, mouse_click): if self.zombie_start_time == 0: @@ -148,6 +159,7 @@ def play(self, mouse_pos, mouse_click): self.head_group.update(self.game_info) self.sun_group.update(self.game_info) + self.grave_group.update(self.game_info) if not self.drag_plant and mouse_pos and mouse_click[0]: result = self.menubar.checkCardClick(mouse_pos) @@ -186,6 +198,23 @@ def play(self, mouse_pos, mouse_click): self.checkCarCollisions() self.checkGameState() + def generateGraves(self): + import random + num_graves = random.randint(5, 8) + + for _ in range(num_graves): + # Random column between 2 and 5 (inclusive) + map_x = random.randint(2, 5) + # Random row between 0 and 4 (inclusive) + map_y = random.randint(0, self.map_y_len - 1) + + # Get the position for the grave + x, y = self.map.getMapGridPos(map_x, map_y) + + # Create and add the grave + new_grave = grave.Grave(x, y) + self.grave_group.add(new_grave) + def createZombie(self, name, map_y): x, y = self.map.getMapGridPos(0, map_y) if name == c.NORMAL_ZOMBIE: @@ -250,6 +279,15 @@ def addPlant(self): new_plant = plant.WallNutBowling(x, y, map_y, self) elif self.plant_name == c.REDWALLNUTBOWLING: new_plant = plant.RedWallNutBowling(x, y) + elif self.plant_name == c.GRAVE_BUSTER: + # Check if there's a grave at this position + for g in self.grave_group: + if g.rect.collidepoint(x, y): + new_plant = grave.GraveBuster(x, y, g) + break + else: + # No grave found, can't plant + return if new_plant.can_sleep and self.background_type == c.BACKGROUND_DAY: new_plant.setSleep() @@ -529,11 +567,19 @@ def drawZombieFreezeTrap(self, i, surface): def draw(self, surface): self.level.blit(self.background, self.viewport, self.viewport) + + # Apply night filter for night levels + if self.background_type == c.BACKGROUND_NIGHT: + self.level.blit(self.night_filter, (0, 0)) + surface.blit(self.level, (0,0), self.viewport) if self.state == c.CHOOSE: self.panel.draw(surface) elif self.state == c.PLAY: self.menubar.draw(surface) + # Draw graves + self.grave_group.draw(surface) + for i in range(self.map_y_len): self.plant_groups[i].draw(surface) self.zombie_groups[i].draw(surface) diff --git a/test_night_level.py b/test_night_level.py new file mode 100644 index 00000000..4754f9f2 --- /dev/null +++ b/test_night_level.py @@ -0,0 +1,64 @@ +import pygame as pg +import sys +import os + +# 添加source目录到路径 +sys.path.append(os.path.join(os.path.dirname(__file__), 'source')) + +from source import tool +from source import constants as c +from source.state import level + +def test_night_level(): + """测试黑夜关卡功能""" + print("=== 测试黑夜关卡功能 ===") + + # 初始化pygame + pg.init() + screen = pg.display.set_mode((c.SCREEN_WIDTH, c.SCREEN_HEIGHT)) + clock = pg.time.Clock() + + # 创建游戏控制 + game = tool.Control() + + # 创建黑夜关卡 + level_state = level.Level() + + # 模拟加载黑夜关卡 + level_state.setupLevel(3) # level_3.json是黑夜关卡 + + print("1. 测试背景类型是否为黑夜:") + print(f" background_type = {level_state.background_type}") + print(f" 预期: {c.BACKGROUND_NIGHT}") + print(f" 结果: {'通过' if level_state.background_type == c.BACKGROUND_NIGHT else '失败'}") + + print("\n2. 测试是否不生成阳光:") + print(f" produce_sun = {level_state.produce_sun}") + print(f" 预期: False") + print(f" 结果: {'通过' if not level_state.produce_sun else '失败'}") + + print("\n3. 测试墓碑生成:") + print(f" 墓碑数量: {len(level_state.grave_group)}") + print(f" 预期: 5-8个墓碑") + print(f" 结果: {'通过' if 5 <= len(level_state.grave_group) <= 8 else '失败'}") + + # 显示墓碑位置 + for i, grave in enumerate(level_state.grave_group): + print(f" 墓碑{i+1}: 位置 ({grave.map_x}, {grave.map_y})") + + print("\n4. 测试黑夜滤镜是否创建:") + print(f" night_filter存在: {hasattr(level_state, 'night_filter')}") + print(f" 结果: {'通过' if hasattr(level_state, 'night_filter') else '失败'}") + + if hasattr(level_state, 'night_filter'): + print(f" night_filter alpha: {level_state.night_filter.get_alpha()}") + print(f" 预期: 80") + print(f" 结果: {'通过' if level_state.night_filter.get_alpha() == 80 else '失败'}") + + print("\n=== 测试完成 ===") + + # 清理 + pg.quit() + +if __name__ == "__main__": + test_night_level() \ No newline at end of file From 3f0da5688bcaf38bae3dd417e4b53c91658fe8fd Mon Sep 17 00:00:00 2001 From: lbj-cmd Date: Thu, 6 Nov 2025 10:57:18 +0800 Subject: [PATCH 2/2] update2 --- 1.txt | 0 save_data.json | 8 + source/__pycache__/constants.cpython-39.pyc | Bin 4517 -> 4386 bytes .../__pycache__/menubar.cpython-39.pyc | Bin 14668 -> 14612 bytes .../__pycache__/plant.cpython-39.pyc | Bin 31863 -> 31543 bytes source/component/coin.py | 55 ++++++ source/component/menubar.py | 11 +- source/component/plant.py | 53 ++--- source/component/zombie.py | 9 +- source/constants.py | 12 +- source/main.py | 6 +- source/state/__pycache__/level.cpython-39.pyc | Bin 17158 -> 16330 bytes source/state/encyclopedia.py | 149 ++++++++++++++ source/state/level.py | 95 ++++----- source/state/mainmenu.py | 17 +- source/state/shop.py | 186 ++++++++++++++++++ 16 files changed, 509 insertions(+), 92 deletions(-) create mode 100644 1.txt create mode 100644 save_data.json create mode 100644 source/component/coin.py create mode 100644 source/state/encyclopedia.py create mode 100644 source/state/shop.py diff --git a/1.txt b/1.txt new file mode 100644 index 00000000..e69de29b diff --git a/save_data.json b/save_data.json new file mode 100644 index 00000000..50f1802f --- /dev/null +++ b/save_data.json @@ -0,0 +1,8 @@ +{ + "gold": 0, + "upgrades": { + "gold_shovel": false, + "extra_slot": false, + "zombie_encyclopedia": false + } +} \ No newline at end of file diff --git a/source/__pycache__/constants.cpython-39.pyc b/source/__pycache__/constants.cpython-39.pyc index 96b75526051b24a6eae40acaa7f728c05c1adf5d..986ab56dda6166a599c1eaa925b91c6ff29ccbeb 100644 GIT binary patch delta 57 zcmZ3gyhw>Rk(ZZ?0SM+^<;v8Y$Sccevr*fYi6xjpvvzY0Q#mWMpJvZyC5|2JlO+YR M7{xZX2uLyl0Fx#TDgXcg delta 190 zcmZ3av{aclk(ZZ?0SK7Cac7>N$Scd}vr*fYNhGQ#r8cTJr7o&3r9P@Zr6HI>vvG3{ zQ#q@C6svntVp(bwH<)rNEiOqd%IpwkV2Bb-PAp1^PY21yCxONNG$(9+#=e8y9;hkE zG0ZiJ2Ta8~g$9SX21SV?^Wt3{L*hd`eO;pjogIT*;*sSh&*RTxl-tZHAj!zV!py=5 Ggvi^PBUjnScEmM zM8YCn*f>i!DI!B?aYbk`HB!d13kS==TEof|S*$EpIm;|NAEJ9s*e|r$)<9`L$pKI6}8qJ;5p2u(}C2CqEP#fJ-!9^a?kqulNoId6UbKG#$K-N7Pla upFd~5WC<#yJ9G%tAD*H9(s+((J|#6B|9WB8L$7jM^+wAU%PvckCHNP|IK(Xg delta 706 zcmY+CTS${(7{|Z==VYHdxw)yER*Hvovr*|hchF2FDu}6pqZrX=Vuryg%0r1wF^W9! zEGUDBAjAtHc@v|OFs00jA`HUAMMlxOiiqgKsK@G}o`*mG|L?tdpZ5?7JPTwUFdB6d z*RF5+hQVSV$?NMQ=9GxYALK6!9KdGKZAoJ!H^{55EYq5(L$e1 z=g>~g(LKl)ia8BPC%2^=K{0AE0vBmAW)LCKXgv*Fp|I^ehUi7?M~u*&xN-UJpN)Fs zyD&kq_D)REfPDs!MV$k{bE;2xh}Yyw?7~@bE3pt*piisbU`b4_o(00wO z(}CMG>$#3GI+1%cxdr@5%zXO_6oaB==@o@NBJg14NlJt!?-Z|1C8Ybf%b>HIZigZO)4PyQ3AIX{V{y)M)bj0=whUKmY&$ diff --git a/source/component/__pycache__/plant.cpython-39.pyc b/source/component/__pycache__/plant.cpython-39.pyc index b9d1a1c470bde697054b2d5b5adda77995038964..195862da569348864a14094310ebe0fdff66558e 100644 GIT binary patch delta 3570 zcmai14OG+D70=DbpAZa0AtZc>L5qZdB3i#cP*e~rf-pY|A&~GT5PS)W=vJ#ctLr(n z)QhdHR_n3tR?nQ;xH_%Y`L(L2YTKQideXJxnXSiGt=*h$x32Eq7r@wh9Gv`e-+TAn z`|j`E``*hp-@<`A5bZJ=4J!J3`LBkCRcrS}zn%uy0)I$bq>g%ldc`7!E^N(8!O@R& z#ciTy45(B-EeU$iYsDrN=GEunz;wSNCv3(i^DVe1{b0WrNoD4>3^wo*_Af}r&Y`*R zGJY_~8n=x)6Yn##jm=EKVHv-M7x0f6c4a5evq)nFhS}2VjpBf` zwYjk@u>8@DYIp-(17bHeYH`rm?K-=*SiFWO$2#CJUM{twe%u;(Pp)joxTc)bZ1@a= zk-@`|z~EvyNAQM5B(W?Q&ah=H8Q%ft$%F;xCg||$__ae`|O2=r}3EyyG?)Qe#!T{ES<)pi7%xdC-IjYl8FSON3W07N9eUg6Me*S8JtZ$GRjcW zR$E(EFTCDnoa#u#nZ@zAZBi_Hixo||P-CafjNOys!?wBK$zG;ZV8zLkUyXW?-L7D` zfHx+mCcjT&(BNzGcv_t;u4a#z&SM`k^wJ1tFmK8!Nr8Dz3bisdfE_^9(!UYjgJz;~w()D+tzFl9laQp*#3yxEqEB%WY3 zJqg5&P9H;zT$GG7Ogo}T-ZfY?A|9vZXPOT2%(od1GaSLy`N`_f054U>xM12##oW3>XB#m+?e`l>L4088eEXg!d+$7!wJU(NMSt`k(WxO)- zBb;?QjyD4RGuOi*Jl~!JMjTd9pU_RcS9)2X@FMm7Y4a7)9oSP43t+|*g@<#`l2RzQ z^n!OUXmB+&J8K1PmQQA=xWF0(43go`ao?=ORE}-2o>k?xe!#;Ih%yPkSd@ykqRvox z$c1L%g`#RDR2n#DwgYmpX7<<9FOvzoNqotcWRlCe`G}iRSLXa2ZZ2f_g5e%n*SUEP zH$UcpF?jN^YPcqg@K1GGD8T7+YLc#!LY$iRx*rMhkmyeppwpYgRod?=Oe@|6v+-Q9 zfX^{+ZZec$#oX7S47DZC!$RCrQg4&%d7S-79{P&et`3!OZ}n=S5+|0fljomgmN!_g z^cGJ(gCCWqLk<2=+N8Tl9YyG!XNH?SNjCvMnfLsVYpmGkAZYaYUBd75w6`{S-JVbi z%It%sxW8;&@@K3r&j+25`4_%hW#zfx!(Wv*!G8Q_`53sv#OO+BN(UDH?7I4n3UAaV zy%GMM7@YBju#`{9X zy-u^~A(d3!Q1|c<&&x`hQI&?-X-4=xwpA5Av3NCYj9+PtaBHn9t7^5%scR|WKKkga zDjr!%7b&&$uSEI{^c~gMPohy`beJ6D)+MSeWTR2FPPYSqC9>nxxm9I!?-UCPTh;Je zI+@DFMy5og8Yv6*DQ>9gmQyX?Vg1nFjd0h8gw!DV0+TrFHhQIZ^Rn*xU zoI1sVDUGvZqsY@x4SCX%1|_jhM6r*Zn;SuMEk=b~mcFAN0O%SL50g+dEr+k=fmnn} z^FMM-G}#^_;`_q4uw-V4lM;L7N2o|R=9bws;|VqcrzR%3aeW;n52iJY*+Ffxp7&RZV-(&;D}}K zJLJ;zB8i<_`jmddl9l@s7(z?KERn9WQM)y;KqP}%u0NJFV;H2LOkD5FfG2UEuiTu* zQ+XYN-3gurm`3wNG%V@hfFr$ zElWJSjk7yeKn_)o1&`M0;4F4`v2y;nG$ z!iuX`%~-&{qy+yCqTeM1yBKye9AG%kz>hxB&2W{0uVBGfoZ!P<@Npx!76q4y;O!-E eSlSqm!&Z-uwV85EqfLWMne?4$8fP+_O8*D&5r`-N delta 3807 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 D^X self.animate_interval: + self.frame_index = (self.frame_index + 1) % len(self.frames) + self.image = self.frames[self.frame_index] + self.animate_timer = current_time + + # 向上浮动 + if self.rect.bottom > self.start_y - self.float_distance: + self.rect.y -= self.float_speed + + def draw(self, surface): + """绘制金币""" + surface.blit(self.image, self.rect) \ No newline at end of file diff --git a/source/component/menubar.py b/source/component/menubar.py index a9dd245c..56054a52 100644 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -15,17 +15,16 @@ c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, - c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT, c.CARD_GRAVE_BUSTER] + c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT] plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, - c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING, c.GRAVE_BUSTER] -plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, - 125, 25, 25, 75, 75, 0, 0, 75] + c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75, 75, 0, 0] plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, - 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0, 7500] -all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0] +all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] def getSunValueImage(sun_value): font = pg.font.SysFont(None, 22) diff --git a/source/component/plant.py b/source/component/plant.py index c9d9a7ac..07526b31 100644 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -127,6 +127,8 @@ def __init__(self, x, y, name, health, bullet_group, scale=1): self.animate_timer = 0 self.animate_interval = 100 self.hit_timer = 0 + # 添加sun_cost属性 + self.sun_cost = 0 def loadFrames(self, frames, name, scale, color=c.BLACK): frame_list = tool.GFX[name] @@ -258,6 +260,7 @@ def checkCollision(self, x, y): class SunFlower(Plant): def __init__(self, x, y, sun_group): Plant.__init__(self, x, y, c.SUNFLOWER, c.PLANT_HEALTH, None) + self.sun_cost = 50 self.sun_timer = 0 self.sun_group = sun_group @@ -271,6 +274,7 @@ def idling(self): class PeaShooter(Plant): def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.PEASHOOTER, c.PLANT_HEALTH, bullet_group) + self.sun_cost = 100 self.shoot_timer = 0 def attacking(self): @@ -282,6 +286,7 @@ def attacking(self): class RepeaterPea(Plant): def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.REPEATERPEA, c.PLANT_HEALTH, bullet_group) + self.sun_cost = 200 self.shoot_timer = 0 def attacking(self): @@ -295,6 +300,7 @@ def attacking(self): class ThreePeaShooter(Plant): def __init__(self, x, y, bullet_groups, map_y): Plant.__init__(self, x, y, c.THREEPEASHOOTER, c.PLANT_HEALTH, None) + self.sun_cost = 325 self.shoot_timer = 0 self.map_y = map_y self.bullet_groups = bullet_groups @@ -314,6 +320,7 @@ def attacking(self): class SnowPeaShooter(Plant): def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.SNOWPEASHOOTER, c.PLANT_HEALTH, bullet_group) + self.sun_cost = 175 self.shoot_timer = 0 def attacking(self): @@ -325,6 +332,7 @@ def attacking(self): class WallNut(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.WALLNUT, c.WALLNUT_HEALTH, None) + self.sun_cost = 50 self.load_images() self.cracked1 = False self.cracked2 = False @@ -350,7 +358,8 @@ def idling(self): class CherryBomb(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.CHERRYBOMB, c.WALLNUT_HEALTH, None) - self.state = c.ATTACK + self.sun_cost = 150 + self.boom_timer = 0c.ATTACK self.start_boom = False self.bomb_timer = 0 self.explode_y_range = 1 @@ -388,6 +397,7 @@ def animation(self): class Chomper(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.CHOMPER, c.PLANT_HEALTH, None) + self.sun_cost = 150 self.animate_interval = 250 self.digest_timer = 0 self.digest_interval = 15000 @@ -451,10 +461,9 @@ def digest(self): class PuffShroom(Plant): def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) + self.sun_cost = 0 self.can_sleep = True self.shoot_timer = 0 - self.life_timer = 0 # Timer for automatic disappearance - self.life_duration = 30000 # 30 seconds def loadImages(self, name, scale): self.idle_frames = [] @@ -471,15 +480,6 @@ def loadImages(self, name, scale): self.frames = self.idle_frames - def handleState(self): - # Check if PuffShroom should disappear - if self.life_timer == 0: - self.life_timer = self.current_time - elif (self.current_time - self.life_timer) > self.life_duration: - self.health = 0 # Set health to 0 to trigger removal - else: - super().handleState() - def attacking(self): if (self.current_time - self.shoot_timer) > 3000: self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, @@ -487,16 +487,16 @@ def attacking(self): self.shoot_timer = self.current_time def canAttack(self, zombie): - # Close range attack (3 grids) if (self.rect.x <= zombie.rect.right and - (self.rect.right + c.GRID_X_SIZE * 3 >= zombie.rect.x)): + (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)): return True return False class PotatoMine(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.POTATOMINE, c.PLANT_HEALTH, None) - self.animate_interval = 300 + self.sun_cost = 25 + self.arm_timer = 0 self.is_init = True self.init_timer = 0 self.bomb_timer = 0 @@ -544,6 +544,7 @@ def attacking(self): class Squash(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None) + self.sun_cost = 50 self.orig_pos = (x, y) self.aim_timer = 0 self.squashing = False @@ -598,6 +599,7 @@ def getPosition(self): class Spikeweed(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.SPIKEWEED, c.PLANT_HEALTH, None) + self.sun_cost = 100 self.animate_interval = 200 self.attack_timer = 0 @@ -630,6 +632,7 @@ def attacking(self): class Jalapeno(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.JALAPENO, c.PLANT_HEALTH, None) + self.sun_cost = 125 self.orig_pos = (x, y) self.state = c.ATTACK self.start_explode = False @@ -672,6 +675,7 @@ def getPosition(self): class ScaredyShroom(Plant): def __init__(self, x, y, bullet_group): Plant.__init__(self, x, y, c.SCAREDYSHROOM, c.PLANT_HEALTH, bullet_group) + self.sun_cost = 25 self.can_sleep = True self.shoot_timer = 0 self.cry_x_range = c.GRID_X_SIZE * 2 @@ -720,6 +724,7 @@ def attacking(self): class SunShroom(Plant): def __init__(self, x, y, sun_group): Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None) + self.sun_cost = 25 self.can_sleep = True self.animate_interval = 200 self.sun_timer = 0 @@ -748,26 +753,21 @@ def idling(self): if not self.is_big: if self.change_timer == 0: self.change_timer = self.current_time - elif (self.current_time - self.change_timer) > 60000: # 60 seconds to grow + elif (self.current_time - self.change_timer) > 25000: self.changeFrames(self.big_frames) self.is_big = True - # Produce sun every 15 seconds if self.sun_timer == 0: - self.sun_timer = self.current_time - elif (self.current_time - self.sun_timer) > 15000: - # Small sunshroom produces 15 sun, big one produces 25 - sun_value = 25 if self.is_big else 15 - # Create sun with appropriate value - sun = Sun(self.rect.centerx, self.rect.bottom, self.rect.right, - self.rect.bottom + self.rect.h // 2, self.is_big) - sun.sun_value = sun_value - self.sun_group.add(sun) + 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, self.is_big)) self.sun_timer = self.current_time class IceShroom(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.ICESHROOM, c.PLANT_HEALTH, None) + self.sun_cost = 75 self.can_sleep = True self.orig_pos = (x, y) self.start_freeze = False @@ -825,6 +825,7 @@ def getPosition(self): class HypnoShroom(Plant): def __init__(self, x, y): Plant.__init__(self, x, y, c.HYPNOSHROOM, 1, None) + self.sun_cost = 75 self.can_sleep = True self.animate_interval = 200 diff --git a/source/component/zombie.py b/source/component/zombie.py index 73780f13..06f9dee7 100644 --- a/source/component/zombie.py +++ b/source/component/zombie.py @@ -104,7 +104,14 @@ def attacking(self): self.setWalk() def dying(self): - pass + # 15%的几率掉落金币 + if random.random() < 0.15: + # 创建金币 + from .coin import Coin + coin = Coin(self.rect.centerx, self.rect.bottom) + # 将金币添加到游戏中 + if hasattr(self, 'game') and hasattr(self.game, 'coin_group'): + self.game.coin_group.add(coin) def freezing(self): if self.health <= 0: diff --git a/source/constants.py b/source/constants.py index 502df212..6bdecdf3 100644 --- a/source/constants.py +++ b/source/constants.py @@ -36,6 +36,8 @@ GAME_LOSE = 'game los' GAME_VICTORY = 'game victory' LEVEL = 'level' +SHOP = 'shop' +ENCYCLOPEDIA = 'encyclopedia' MAIN_MENU_IMAGE = 'MainMenu' OPTION_ADVENTURE = 'Adventure' @@ -177,12 +179,4 @@ #BACKGROUND BACKGROUND_DAY = 0 -BACKGROUND_NIGHT = 1 - -#GRAVE -GRAVE = 'Grave' -GRAVE_BUSTER = 'GraveBuster' -GRAVE_BUSTER_EAT_TIME = 5000 # 5 seconds to eat grave - -#PLANT CARD INFO -CARD_GRAVE_BUSTER = 'card_grave_buster' \ No newline at end of file +BACKGROUND_NIGHT = 1 \ No newline at end of file diff --git a/source/main.py b/source/main.py index 92fcdc19..d746731f 100644 --- a/source/main.py +++ b/source/main.py @@ -2,13 +2,15 @@ from . import tool from . import constants as c -from .state import mainmenu, screen, level +from .state import mainmenu, screen, level, shop, encyclopedia def main(): game = tool.Control() state_dict = {c.MAIN_MENU: mainmenu.Menu(), c.GAME_VICTORY: screen.GameVictoryScreen(), c.GAME_LOSE: screen.GameLoseScreen(), - c.LEVEL: level.Level()} + c.LEVEL: level.Level(), + c.SHOP: shop.Shop(), + c.ENCYCLOPEDIA: encyclopedia.Encyclopedia()} game.setup_states(state_dict, c.MAIN_MENU) game.main() \ No newline at end of file diff --git a/source/state/__pycache__/level.cpython-39.pyc b/source/state/__pycache__/level.cpython-39.pyc index 68533000e21471215511f431929aff2b3c515b1d..a9edf274ebd36341a22732c7ca279c07976007f4 100644 GIT binary patch delta 5954 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 Ckvvxb delta 6679 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 self.option_rect.y and y <= self.option_rect.bottom): self.option_clicked = True self.option_timer = self.option_start = self.current_time + return True + # 检查商店按钮点击 + elif(x >= self.shop_button_rect.x and x <= self.shop_button_rect.right and + y >= self.shop_button_rect.y and y <= self.shop_button_rect.bottom): + self.next = c.SHOP + self.done = True + return True return False def update(self, surface, current_time, mouse_pos, mouse_click): @@ -66,4 +80,5 @@ def update(self, surface, current_time, mouse_pos, mouse_click): self.done = True surface.blit(self.bg_image, self.bg_rect) - surface.blit(self.option_image, self.option_rect) \ No newline at end of file + surface.blit(self.option_image, self.option_rect) + surface.blit(self.shop_button_text, self.shop_button_rect) \ No newline at end of file diff --git a/source/state/shop.py b/source/state/shop.py new file mode 100644 index 00000000..6ad1205c --- /dev/null +++ b/source/state/shop.py @@ -0,0 +1,186 @@ +__author__ = 'marble_xu' + +import pygame as pg +import json +import os +from .. import tool +from .. import constants as c + +class Shop(tool.State): + def __init__(self): + tool.State.__init__(self) + self.save_file_path = 'save_data.json' + self.load_save_data() + self.setup_shop_items() + self.setup_background() + self.setup_buttons() + self.setup_text() + + def load_save_data(self): + """加载保存数据""" + if os.path.exists(self.save_file_path): + with open(self.save_file_path, 'r') as f: + self.save_data = json.load(f) + else: + self.save_data = { + "gold": 0, + "upgrades": { + "gold_shovel": False, + "extra_slot": False, + "zombie_encyclopedia": False + } + } + self.save_save_data() + + def save_save_data(self): + """保存数据到文件""" + with open(self.save_file_path, 'w') as f: + json.dump(self.save_data, f, indent=2) + + def setup_shop_items(self): + """设置商店商品""" + self.items = [ + { + "name": "黄金铲子", + "description": "铲除植物时返还25%的阳光消耗", + "price": 1000, + "upgrade_key": "gold_shovel", + "rect": pg.Rect(100, 100, 200, 100) + }, + { + "name": "额外卡槽", + "description": "永久解锁第7个植物卡槽", + "price": 5000, + "upgrade_key": "extra_slot", + "rect": pg.Rect(400, 100, 200, 100) + }, + { + "name": "僵尸图鉴", + "description": "解锁僵尸图鉴功能", + "price": 500, + "upgrade_key": "zombie_encyclopedia", + "rect": pg.Rect(100, 250, 200, 100) + } + ] + + def setup_background(self): + """设置背景""" + self.bg_color = c.NAVYBLUE + + def setup_buttons(self): + """设置按钮""" + self.back_button_rect = pg.Rect(600, 500, 150, 50) + self.encyclopedia_button_rect = pg.Rect(400, 250, 200, 100) + + def setup_text(self): + """设置文本""" + self.font = pg.font.Font(None, 36) + self.small_font = pg.font.Font(None, 24) + + def startup(self, current_time, persist): + """初始化状态""" + self.next = c.MAIN_MENU + self.persist = persist + self.game_info = persist + self.current_time = current_time + self.mouse_pos = None + self.mouse_click = False + + def update(self, surface, current_time, mouse_pos, mouse_click): + """更新状态""" + self.current_time = current_time + self.mouse_pos = mouse_pos + self.mouse_click = mouse_click + + if self.mouse_click and self.mouse_pos: + self.handle_click(self.mouse_pos) + + self.draw(surface) + + def handle_click(self, mouse_pos): + """处理鼠标点击""" + x, y = mouse_pos + + # 处理返回按钮 + if self.back_button_rect.collidepoint(x, y): + self.done = True + return + + # 处理图鉴按钮(如果已购买) + if self.save_data['upgrades']['zombie_encyclopedia'] and \ + self.encyclopedia_button_rect.collidepoint(x, y): + self.next = c.ENCYCLOPEDIA + self.done = True + return + + # 处理商品购买 + for item in self.items: + if item['rect'].collidepoint(x, y): + self.attempt_purchase(item) + break + + def attempt_purchase(self, item): + """尝试购买商品""" + upgrade_key = item['upgrade_key'] + if not self.save_data['upgrades'][upgrade_key]: + if self.save_data['gold'] >= item['price']: + # 购买成功 + self.save_data['gold'] -= item['price'] + self.save_data['upgrades'][upgrade_key] = True + self.save_save_data() + + def draw(self, surface): + """绘制商店界面""" + # 填充背景 + surface.fill(self.bg_color) + + # 绘制标题 + title_text = self.font.render("疯狂戴夫的商店", True, c.GOLD) + title_rect = title_text.get_rect(center=(c.SCREEN_WIDTH // 2, 50)) + surface.blit(title_text, title_rect) + + # 绘制金币数量 + gold_text = self.font.render(f"金币: {self.save_data['gold']}", True, c.YELLOW) + gold_rect = gold_text.get_rect(topleft=(50, 50)) + surface.blit(gold_text, gold_rect) + + # 绘制商品 + for item in self.items: + is_purchased = self.save_data['upgrades'][item['upgrade_key']] + + # 绘制商品框 + if is_purchased: + pg.draw.rect(surface, c.GREEN, item['rect'], 3) + else: + pg.draw.rect(surface, c.WHITE, item['rect'], 3) + + # 绘制商品名称 + name_text = self.font.render(item['name'], True, c.WHITE) + name_rect = name_text.get_rect(center=(item['rect'].centerx, item['rect'].y + 30)) + surface.blit(name_text, name_rect) + + # 绘制商品价格 + if not is_purchased: + price_text = self.small_font.render(f"价格: {item['price']} 金币", True, c.YELLOW) + else: + price_text = self.small_font.render("已购买", True, c.GREEN) + price_rect = price_text.get_rect(center=(item['rect'].centerx, item['rect'].y + 60)) + surface.blit(price_text, price_rect) + + # 绘制商品描述 + desc_text = self.small_font.render(item['description'], True, c.LIGHTYELLOW) + desc_rect = desc_text.get_rect(center=(item['rect'].centerx, item['rect'].y + 90)) + surface.blit(desc_text, desc_rect) + + # 绘制返回按钮 + pg.draw.rect(surface, c.RED, self.back_button_rect) + back_text = self.font.render("返回主菜单", True, c.WHITE) + back_rect = back_text.get_rect(center=self.back_button_rect.center) + surface.blit(back_text, back_rect) + + # 如果已购买图鉴,绘制图鉴按钮 + if self.save_data['upgrades']['zombie_encyclopedia']: + pg.draw.rect(surface, c.BLUE, self.encyclopedia_button_rect) + ency_text = self.font.render("僵尸图鉴", True, c.WHITE) + ency_rect = ency_text.get_rect(center=self.encyclopedia_button_rect.center) + surface.blit(ency_text, ency_rect) \ No newline at end of file