ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

使用Claude Code开发植物大战僵尸游戏(pygame,附源码)

使用Claude Code开发植物大战僵尸游戏(pygame,附源码) 文章目录引言项目速览架构设计状态机驱动的游戏循环模块职责划分技术亮点1. 程序化图形用几何图元画出一个世界2. 程序化音效用数学公式合成声音3. 严格的时间管理统一使用 pygame.time.get_ticks()4. 坐标系统网格与像素的清晰转换5. 实体交互模式通过 game 引用解耦6. 特殊僵尸的差异化行为7. 中文显示与字体回退波次与关卡系统扩展指南添加新植物添加新僵尸总结运行效果人工备注说明开发工具Claude Code 火山方舟glm-5.1这个项目使用Claude Code开发2小时直接生成80%代码2小时让AI微调代码这篇文章也是使用Claude Code编写引言植物大战僵尸Plants vs. Zombies是无数玩家的童年回忆。你是否想过不依赖任何图片、音频等外部资源仅用纯代码能否复刻这款经典塔防游戏本文将带你走进一个完全基于 Pygame 的植物大战僵尸克隆项目——所有图形通过几何图元程序化绘制所有音效通过数学公式程序化生成界面全中文支持整个项目仅约 2000 行 Python 代码。项目速览代码量约 2055 行11 个 Python 模块外部依赖仅需pygame无图片、无音频文件、无其他第三方库运行方式pip install pygame python main.py特性5 种植物、5 种僵尸、10 关关卡、波次系统、割草机、阳光收集、暂停/设置持久化架构设计状态机驱动的游戏循环游戏的核心是经典的游戏循环模式处理事件 → 更新逻辑 → 渲染画面 → 刷新屏幕。在此基础上通过状态机管理不同的游戏阶段menu → level_select → playing ⇄ paused ⇄ settings ↓ level_complete → playing (下一关) ↓ win / lose → menugame.py中的Game类是整个项目的中枢拥有主循环、状态机、所有实体列表和波次系统。每个状态都有独立的draw_*方法和事件处理分支defrun(self):whilerunning:foreventinpygame.event.get():self.handle_event(event)self.update()# 根据状态选择渲染方法ifself.statemenu:self.draw_menu()elifself.stateplaying:self.draw()# ...pygame.display.flip()self.clock.tick(FPS)这种设计将不同阶段的逻辑完全隔离避免了状态间的耦合。例如暂停状态下不会触发游戏更新设置界面的事件处理也不会影响战斗逻辑。模块职责划分项目遵循单一职责原则每个模块都有清晰的边界模块行数职责game.py816游戏主循环、状态机、实体管理、波次系统plants.py299植物基类及 5 个子类向日葵、豌豆射手、双发射手、食人花、坚果墙zombies.py202僵尸基类及 5 个子类普通、路障、铁桶、跨栏、报纸僵尸ui.py207植物卡片栏、铲子、暂停按钮、波次进度条sound.py152程序化音效生成SoundManager 管理 13 种音效map_grid.py96网格数据、坐标转换、草坪/街道渲染、割草机sun.py81阳光下落、收集动画、生命周期settings.py111所有常量定义、中文字体辅助函数projectile.py40豌豆弹丸移动与碰撞检测button.py34通用按钮组件main.py17入口文件settings.py是游戏平衡的唯一数据源——血量、费用、速度、时间间隔等所有常量集中管理调整难度只需修改一个文件。技术亮点1. 程序化图形用几何图元画出一个世界这是项目最有趣的特性。没有加载任何 PNG/SVG所有角色都通过pygame.draw的circle、rect、ellipse、polygon、line、arc组合绘制。以豌豆射手为例它由茎、叶子、头部、嘴巴和眼睛组成defdraw(self,surface,x,y):# 茎pygame.draw.rect(surface,(0,80,0),(x-4,y5,8,30))# 叶子pygame.draw.ellipse(surface,DARK_GREEN,(x-18,y10,16,8))# 头部渐变效果用两个同心圆模拟pygame.draw.circle(surface,(0,120,0),(x,y-5),20)pygame.draw.circle(surface,(0,160,0),(x,y-5),17)# 嘴巴/炮管pygame.draw.rect(surface,(0,80,0),(x5,y-10,22,14))# 眼睛pygame.draw.circle(surface,WHITE,(x-5,y-11),6)pygame.draw.circle(surface,BLACK,(x-4,y-11),3)这种绘制方式不仅避免了版权问题还带来了独特的手绘风格。每个角色都有动画细节——向日葵的花瓣会微微摇摆僵尸走路时身体会上下晃动坚果墙受伤后会出现裂纹# 坚果墙的损伤可视化damage_ratio1-self.hp/self.max_hpifdamage_ratio0.33:pygame.draw.line(surface,DARK_BROWN,...)# 第一道裂纹ifdamage_ratio0.66:pygame.draw.line(surface,BLACK,...)# 更深的裂纹2. 程序化音效用数学公式合成声音sound.py实现了一个完整的程序化音效系统。核心思路是用正弦波合成乐音用随机噪声合成打击音效def_tone(freq,duration,volume0.5,sample_rate22050):生成指定频率的正弦波音调nint(sample_rate*duration)samples[]foriinrange(n):ti/sample_rate envmin(1.0,min(i,n-i)/(sample_rate*0.01))# 包络线samples.append(volume*env*math.sin(2*math.pi*freq*t))returnsamples通过组合不同频率和时长的音调可以模拟出丰富的游戏音效。例如阳光收集音效使用上行音阶880Hz → 1100Hz → 1320Hz给出愉悦的反馈感僵尸死亡音效使用下行音阶300Hz → 200Hz → 100Hz营造低沉的氛围游戏胜利音效则使用 C 大调上行琶音C5 → E5 → G5 → C6带来通关的成就感。SoundManager在初始化时一次性生成 13 种音效并缓存运行时通过play(name)按名称播放self.sounds{place:create_place_sound(),pea:create_pea_sound(),sun_collect:create_sun_collect_sound(),zombie_die:create_zombie_die_sound(),# ...}3. 严格的时间管理统一使用pygame.time.get_ticks()游戏开发中计时器的管理是容易出现 bug 的地方。本项目坚持一个原则所有计时器统一使用pygame.time.get_ticks()禁止使用time.time()或帧计数。这个原则在暂停/恢复机制中尤为重要。当游戏暂停时记录暂停时间戳恢复时计算暂停时长delta_ms然后将所有计时器偏移该时长def_resume(self):deltapygame.time.get_ticks()-self.paused_from self._offset_timers(delta)self.stateplayingdef_offset_timers(self,delta_ms):self.spawn_timerdelta_ms self.sky_sun_timerdelta_ms self.wave_timerdelta_msforplantinself.plants_list:ifhasattr(plant,sun_timer):plant.sun_timerdelta_msifhasattr(plant,fire_timer):plant.fire_timerdelta_msforcardinself.ui.cards:card.last_placeddelta_ms# ...这确保了暂停不会导致时间跳跃——恢复后植物不会突然发射大量豌豆阳光不会突然过期。每一个有计时器的实体都被精心偏移包括植物的射击/产阳光/咀嚼计时器、卡片的冷却计时器、阳光的生命周期计时器等。4. 坐标系统网格与像素的清晰转换游戏场地是一个 5 行 9 列的网格但实际渲染和交互都在像素空间。MapGrid封装了两个关键的转换方法defpixel_to_grid(self,x,y):col(x-GRID_X_OFFSET)//CELL_WIDTH row(y-GRID_Y_OFFSET)//CELL_HEIGHTif0rowGRID_ROWSand0colGRID_COLS:returnrow,colreturnNone,Nonedefgrid_to_pixel(self,row,col):xGRID_X_OFFSETcol*CELL_WIDTHCELL_WIDTH//2yGRID_Y_OFFSETrow*CELL_HEIGHTCELL_HEIGHT//2returnx,y所有涉及坐标的操作——放置植物、碰撞检测、幽灵预览——都通过这两个方法进行转换绝不硬编码像素坐标。这使得调整网格偏移或单元格尺寸时整个游戏自动适配。5. 实体交互模式通过game引用解耦植物和僵尸的update()方法接收game对象引用通过它与其他系统交互classPeashooter(Plant):defupdate(self,game):nowpygame.time.get_ticks()ifnowself.fire_timer:ifgame.has_zombie_in_row(self.row):# 查询同行僵尸self.fire_timernowPEASHOOTER_FIRE_INTERVAL game.spawn_pea(self.row,self.col)# 生成豌豆这种设计让实体逻辑保持内聚——豌豆射手自己决定何时射击但不需要知道豌豆是如何被创建和管理的。碰撞检测同样遵循这个模式在projectile.py中豌豆自行检测与僵尸的碰撞并造成伤害。6. 特殊僵尸的差异化行为5 种僵尸共享基类的移动和啃食逻辑但通过方法重写实现差异化的行为路障僵尸/铁桶僵尸单纯增加血量通过_draw_accessory绘制不同的头部装饰跨栏僵尸重写_check_plant_collision首次遇到植物时跳过而非啃食报纸僵尸重写take_damage报纸被打掉后进入暴怒状态速度提升 3 倍classNewspaperZombie(Zombie):deftake_damage(self,amount):ifself.newspaper_alive:self.newspaper_hp-amount self.hp-amountifself.newspaper_hp0:self.newspaper_aliveFalseself.angryTrueself.base_speedZOMBIE_SPEED*NEWSPAPER_ZOMBIE_ANGRY_SPEED_MULT self.speedself.base_speed7. 中文显示与字体回退所有界面文字均为中文settings.py中的get_chinese_font()实现了多级字体回退defget_chinese_font(size):font_paths[C:/Windows/Fonts/msyh.ttc,# 微软雅黑C:/Windows/Fonts/simhei.ttf,# 黑体C:/Windows/Fonts/simsun.ttc,# 宋体]forpathinfont_paths:ifos.path.exists(path):try:returnpygame.font.Font(path,size)exceptException:continuereturnpygame.font.Font(None,size)# 最终回退所有render()调用都必须使用此函数而非 Pygame 默认字体确保中文字符正确显示。波次与关卡系统游戏包含 10 个关卡每关 5 波僵尸。僵尸数量随关卡和波次递增def_zombie_count_for_wave(self):baseBASE_ZOMBIE_COUNT*self.levelreturnbaseself.wave*self.level不同关卡的僵尸种类逐步解锁第 2 关出现路障僵尸第 3 关出现跨栏僵尸第 4 关出现报纸僵尸第 6 关出现铁桶僵尸。每波开始前有 20 秒准备时间带有倒计时提示和音效。关卡进度通过 JSON 文件持久化解锁的最高关卡会被保存def_save_settings(self):data{volume:self.volume,speed:SPEED_OPTIONS[self.speed_index],level_unlocked:self.level_unlocked,}withopen(SETTINGS_FILE,w)asf:json.dump(data,f)扩展指南添加新植物在settings.py中添加常量费用、血量、计时器间隔在plants.py中创建子类实现update(game)和draw(surface, x, y)将新类追加到PLANT_CLASSES列表在ui.py的PlantCard._draw_plant_icon()中添加卡片图标如果植物有计时器在game.py的_offset_timers()中添加偏移逻辑添加新僵尸在settings.py中添加常量血量、速度倍率在zombies.py中创建子类重写_draw_accessory()绘制装饰必要时重写_check_plant_collision()或take_damage()在game.py的_spawn_zombie()中添加生成逻辑总结这个项目展示了如何用最简洁的技术栈实现一个完整的塔防游戏。程序化图形和音效消除了对外部资源的依赖状态机管理了复杂的游戏流程统一的时间系统避免了暂停后的时间跳跃清晰的模块划分让代码易于理解和扩展。对于想入门游戏开发的 Python 程序员来说这是一个很好的学习案例——你不需要美术素材不需要音频工程知识只需要理解游戏循环、状态管理和碰撞检测这几个核心概念就能创造出有趣的游戏体验。运行效果源码
返回列表