AI编码助手实战:开维引擎FlappyBird从零生成全流程
最近一周我抽空做了一个挺有意思的实战练习拿开维游戏引擎搭一个 2D 横版小游戏让 AI 编码助手自动生成代码目标是把经典玩法“飞翔的小鸟 FlappyBird”从零到一完整跑起来包括重力、点击跳跃、随机管道、碰撞、计分、重新开始这些全套逻辑。文章标题里带着“AI 自动生成游戏代码”但我得先说清楚一个现实AI 不是闭着眼睛把整个项目丢给你而是更像一个速度极快、但缺乏常识的结对实习生。它能帮你把 70% 的模式化代码瞬间写出来剩下 30% 的架构梳理、数值调优、边界修复仍然需要你亲手把关。这篇博文会把整个流程、提示词写法、踩到的坑一次讲透适合想尝试“AI游戏开发”的初学者也适合正在研究怎么把大模型工具引入日常开发流程的从业者。1. 为什么拿“飞翔的小鸟”当 AI 生成游戏的第一站1.1 麻雀虽小五脏俱全的玩法闭环很多人觉得 FlappyBird 玩法简单代码量应该很小不值得认真对待。这其实是个误区。表面上它只有一个“点击就让小鸟跳一下”的交互但背后包含了游戏开发中最核心的五块拼图游戏循环持续更新、渲染、输入响应物理模拟重力加速度、瞬时速度、位置积分场景生成管道障碍按节奏随机生成并持续向左移动碰撞检测小鸟与上下管道、地面、天花板的相交判断状态管理待开始、游戏中、游戏结束三种状态的切换以及计分和重置逻辑。这五块内容几乎覆盖了大多数 2D 休闲游戏的全部骨架。把这一套跑通之后做跑酷、打砖块、甚至简单的纵版射击都会非常顺手。所以我拿它当“AI 生成游戏代码”的试金石是有意的选择。1.2 判断 AI 适不适合生成某个项目的两个标准我看过很多失败案例一上来就让 AI 生成一个“大型开放世界游戏”结果自然是灾难。AI 编码助手擅长的是把描述清晰的规则转成代码而不是凭空架构一个复杂系统。用两个标准可以快速判断一个项目适不适合规则是否可以被书面化如果玩法能用几条数学规则描述清楚比如“重力 320 像素每平方秒”“管道间距 1.5 秒”AI 就很容易理解。反之那些依赖灵感、审美、手感模糊的功能AI 只能给个雏形。反馈回路是否短改完代码能不能立刻看到效果如果每次调试都要等编译、部署、热更新半天“人机协作”的迭代速度就会大打折扣。“飞翔的小鸟”恰好两个标准都满足。它不需要复杂动画资源不需要服务端联调改一个数值立刻能玩非常适合做 AI 生成的试点项目。1.3 开维引擎给我的初印象这次用的是开维引擎。它是一个典型的“组件化”轻量级 2D 游戏引擎场景里有各种实体实体上挂脚本组件组件里写生命周期回调比如start()、update(dt)、on_input()。渲染这块我直接用引擎内置的矩形、图片和文本绘制接口没有引入额外的渲染框架。选择这个引擎做 AI 实验还有一个原因它的 API 命名足够规范结构简单AI 编码助手对这类常见模式的生成质量普遍比较高。相反如果你拿一个非常小众、资料极少的自研引擎去让 AI 生成代码它没有足够语料可参考生成出来的代码大概率是自嗨式 API 调用根本跑不起来。提示如果你想复刻这次实验建议选主流语法风格、资料完整的引擎或框架。AI 生成的可用率会高很多。2. 工程初始化与场景搭建先让小鸟“出现”在屏幕上2.1 项目目录结构在动手让 AI 写逻辑之前我先把工程目录搭好。这一步看似没技术含量却决定了后面 AI 生成代码时的上下文清晰度。我按下述结构组织assets/存放图标、音效、字体等静态资源scripts/游戏逻辑脚本scenes/场景文件描述实体和层级关系data/数值配置比如重力、速度、管道间距等。为什么要把数值单独放一个目录因为 AI 生成的代码往往喜欢把魔法数字写死在脚本里后期调手感很不方便。我会在提示词里主动要求 AI 读取一个data/game_config.json文件把重力、管道速度、生成间隔这些常量集中管理。改一个 JSON 字段就能试一版新手感这个体验比每次翻代码找数字强太多。2.2 画布尺寸、相机设置与地平面高度我设计的竖屏画布是 480×720 像素这种比例和经典玩法接近也方便在手机上预览。正交相机放在原点世界坐标直接对应像素坐标省去做坐标转换的麻烦。地平面高度设在地图 y600 的位置。也就是说小鸟在竖轴上从 0 开始往下掉掉到 y600 就会撞地。天空区域留白很大让管道的随机位置有充足的上下空间。这些看似不起眼的坐标约定在 AI 生成代码时必须写清楚。否则 AI 很可能会默认“地面就是屏幕底部”然后用screen_height动态计算结果画布尺寸一改碰撞判定就乱套。固定坐标虽然不够灵活但在原型阶段能大幅减少变量。2.3 第一次和 AI 协作生成初步场景接着我给出了第一份提示词让它生成一个带背景和地面层级的场景请用开维引擎生成一个 FlappyBird 风格场景 1. 创建主场景画布 480x720正交相机 2. 背景色为浅蓝色渐变用 2-3 个层叠矩形从下往上渐变 3. 在 y600 创建地面实体渲染为绿色横条宽 480高 60 4. 创建一个空实体 “BirdAnchor”作为小鸟的挂载点。AI 很快生成了场景结构但它的背景渐变是用三个固定色块硬拼的拼接处能看到明显色差。这个我不会去手工调整颜色——对于原型阶段来说有背景颜色分层就够了等手感调好再换美术资源也不迟。生成场景骨架之后我检查了一下层级关系。BirdAnchor被正确创建地面实体没有透视关系相机参数也对。这个阶段的重点是确保实体树清楚AI 写逻辑时知道该往哪个节点上挂组件而不是把代码写错对象。3. AI 生成核心玩法把“游戏规则”翻译成人话再翻译成代码3.1 像写验收标准一样写提示词在真正写代码之前有一个步骤决定成败把玩法规则整理成一段可以被验收的“需求说明”。AI 不懂“手感好”这种主观描述它需要数字、边界条件和行为顺序。我给 AI 的核心提示词是这样写的请生成 scripts/bird.py - 组件挂在 BirdAnchor 实体上 - 包含重力加速度 320px/s²、初始速度为 0 - 每次点击/按空格立刻把垂直速度设为 -100px/s - 只在 GameController.state PLAYING 时更新位置 - 旋转角度限制在 -25 到 80 度之间 - 所有数值从 data 配置读取不要写死。这比直接说“实现一只鸟的飞行动作”要可靠得多。原因很简单AI 生成代码本质上是概率预测描述越不精确它越可能用“常见飞行动作”的思路去套而不是你的思路。把数字写清楚AI 的搜索空间就被锁定了。3.2 小鸟的运动组件重力与跳动AI 生成的鸟组件核心逻辑如下我稍微整理过# scripts/bird.py class Bird(Component): def start(self): self.velocity 0.0 self.gravity cfg.gravity self.flap_speed cfg.flap_speed self.entity.y cfg.bird_start_y def update(self, dt): if Game.state ! GameState.PLAYING: return # 速度随时间增加模拟重力 self.velocity self.gravity * dt self.entity.y self.velocity * dt # 角度反馈向上时抬头下落时低头 angle clamp(self.velocity * 0.2, -25, 80) self.entity.rotation angle def flap(self): self.velocity self.flap_speed这段代码有几个关键点我需要仔细核对。首先是self.velocity self.gravity * dt这用的是“速度积分”而不是直接改坐标。如果 AI 直接写entity.y gravity * dt * dt那会造成二次方位移整体下落会慢得离谱。其次是dt的使用。所有跟时间相关的更新都必须乘dt否则游戏在不同帧率下速度不一样。后面排错篇章我会专门讲这个问题。3.3 管道生成器随机性与节奏控制管道生成器的逻辑比小鸟运动复杂一些。它需要在固定间隔生成一对上下管道管道之间留一个可以让鸟穿过的洞同时整个管道组以恒定速度向左移动。我让 AI 生成的逻辑是这样的# scripts/pipe_spawner.py class PipeSpawner(Component): def start(self): self.timer 0.0 self.spawn_interval 1.5 self.pipe_speed 120.0 self.hole_height 150.0 self.min_hole_center_y 180.0 self.max_hole_center_y 420.0 def update(self, dt): self.timer - dt if self.timer 0: self.timer self.spawn_interval center_y random.uniform(self.min_hole_center_y, self.max_hole_center_y) self.spawn_pipe_pair(center_y) def spawn_pipe_pair(self, center_y): top_pipe self.create_pipe( ycenter_y - self.hole_height / 2, anchorbottom) bottom_pipe self.create_pipe( ycenter_y self.hole_height / 2, anchortop) group self.entity.scene.create_entity(PipeGroup) group.add(top_pipe) group.add(bottom_pipe)这里最值得留意的是锚点处理。上管道应该从洞口顶部向上延伸下管道从洞口底部向下延伸。如果用中心点坐标去放管道边缘很难对齐。我给提示词里特意加了“锚点”两个字AI 才给出正确的实现。下面这张表列出了我在配置文件中使用的核心数值也是后续调手感的起点配置项数值含义调整方向gravity320 px/s²下落加速度数值越大下落越快flap_speed-100 px/s跳跃瞬间速度绝对值越大跳得越高pipe_speed120 px/s管道左移速度越大难度越高spawn_interval1.5 s管道生成间隔越小节奏越紧hole_height150 px管道洞口高度越小难度越高这套数值并不是凭空定的。我心里有个基准整个游戏过程中鸟的正常下落速度大约 200~400 px/s管道左移速度决定反应时间1.5 秒一根管的节奏对新手来说比较友好。4. 碰撞检测、计分与状态管理AI 最容易写崩的三块硬骨头4.1 碰撞检测视觉矩形不等同于碰撞矩形AI 生成的碰撞检测通常是标准的 AABB轴对齐包围盒相交判断这个几乎不会错。但它最容易错的地方在于什么时候判断碰撞碰撞范围到底取多大。我让 AI 生成了如下检测逻辑def is_colliding(rect_a, rect_b): return not ( rect_a.right rect_b.left or rect_b.right rect_a.left or rect_a.bottom rect_b.top or rect_b.bottom rect_a.top )这个函数本身完全正确。但真正的问题出在碰撞矩形上。如果直接用小鸟图片的整个矩形去做碰撞玩家会明显感觉“明明没碰着管道却死了”因为图片透明部分也被算了进去。正确的做法是给小鸟的碰撞盒做内缩通常缩到图片尺寸的 70% 左右给玩家留一点容错空间。我给 AI 的后续提示是- 小鸟的碰撞盒尺寸为 40x32而不是图片尺寸 - 管道碰撞盒宽度为 70高度用实际管道高度 - 地面碰撞盒从 y600 开始向上 - 碰撞到地面或管道时切换到 OVER 状态。有了这些边界设定碰撞的“手感”才开始靠谱。4.2 状态机避免多个布尔变量互相打架AI 很常见的一个问题是用is_ready、is_playing、is_over三个布尔变量分别表达状态结果逻辑一旦复杂就会出现“又 ready 又 over”的荒谬情况。我在提示词里直接要求它用一个枚举class GameState: READY 0 PLAYING 1 OVER 2然后所有的状态判断都围绕着Game.state。这一招立竿见影。AI 生成的代码里所有跳跃、重力、管道生成、计数的逻辑都先检查Game.state逻辑链路清晰很多。下面是我实际使用的状态转换规则初始进入 READY鸟悬浮在空中不落体不动第一次点击进入 PLAYING鸟开始受重力影响碰撞或落地进入 OVER鸟停止操作播放撞击效果点击重开按钮清空管道分数归零回到 READY。这套状态机在群里被大家称为“最不 AI 的 AI 代码”因为每个转换都显式、可追踪没有任何模糊的布尔组合。4.3 得分逻辑什么时候算“通过了一个管道”这是整段代码里 AI 第一次给我挖坑的地方。它第一次生成的计分逻辑是当鸟的碰撞盒和管道碰撞盒重叠的那一帧分数加一。这显然不对因为鸟碰到管道就直接死了它永远不可能靠“碰撞”来得分。正确的得分时机应该是鸟的 x 坐标已经越过了某个管道的右边缘并且这个管道还没有被计过份。我给出的实现是# scripts/pipe.py class Pipe(Component): def start(self): self.scored False def update(self, dt): if self.scored: return bird_x Game.bird.entity.x if bird_x self.entity.x self.width: self.scored True Game.score 1 Sound.play(score)这里关键点在于给每个管道挂了一个scored标签。这个标签的作用是防止重复计分——鸟在两根管道之间停留时如果每帧都判断为“已经越过”分数就会不停往上跳。AI 第一次没考虑到这一点我后来在排错时补上了。5. 资源、音效与手感打磨AI 生成的玩法还得靠人补细节5.1 用程序化图形代替美术资源做原型的时候我没有去找任何外部美术素材直接用引擎的绘图接口生成了所有图形。背景是三层渐变的矩形地面是纹理平铺的绿色长条小鸟就是一个白色矩形加一个橙色三角形嘴巴管道的绿色圆柱体也是用细长矩形拼出来的。用程序化图形的最大好处是零版权风险、零加载耗时饿死哪里都能跑。但缺点也很明显画面平淡、层次感弱。我给自己定的标准是“先能玩再能看”等玩法验证完成了再让 AI 生成资源命名规范和加载流程方便后续替换成正式美术。5.2 手感的数值调优手感是最难量化、也最需要人力介入的部分。我前后调整了三轮数值第一轮重力 320跳跃速度 -100管道间隔 1.5 秒玩起来鸟有点“飘”第二轮重力提高到 380跳跃速度 -120落点更干脆但跳跃高度变化不够明显第三轮把跳跃加速度改为“脉冲式”——每次点击先给一个小幅向上的速度再叠加轻微向上加速度视觉上鸟会有一个微微抬头再下落的过程。其实整个调参过程完全可以交给 AI 去做比如让它生成十几个参数组合但前提是你得明确“手感”的数学模型。现阶段我还没有那么精细的量化指标所以这块仍然是人肉测试。5.3 音频反馈短促而有辨识度音效我用了两个办法生成一个是用引擎内置的合成器接口播放短促的方波音调另一个是直接导入几个公开版权的短音频文件。在 AI 提示词里我要求它把音效调用封装成独立接口例如Sound.play(wing)、Sound.play(score)、Sound.play(hit)然后由音效管理脚本统一加载。这样做的好处是后续替换音频文件不需要改动逻辑代码。我实际用的三个音效都很短跳跃是一声清脆的“咻”得分是一声上扬的“叮”撞击是一声低频的“砰”。这三个反馈清晰地告知玩家当前事件而且不干扰操作注意力。6. 排错实录AI 生成的代码里我实际踩过的五个坑6.1 管道自己会动但还是跟场景坐标打架第一版管道的生成逻辑是每根管道自己在 update 里修改世界坐标。看起来没问题因为管道确实在向左移动。但问题出现在相机有轻微位移模拟的时候——当场景里同时存在相机滚动和管道自移动管道组与背景的移动速度对不上产生严重的“漂移感”。修复方法是把管道移动统一放到一个“管道组”的父实体上让父实体统一左移子管道只维护相对坐标。这样视角移动和管道移动互相独立逻辑也很清晰。6.2 重新开局后上一局的管道残留导致“突然暴毙”AI 在生成 restart 逻辑时只重置了鸟的坐标和分数却忘了清理场景中已存在的管道实体。结果玩家第二次开局时上一局的管道还留在屏幕上直接撞死。我让 AI 在生成所有管道时把管道实体加入一个pipe_collection列表在restart()里遍历并移除。这一步很关键必须在提示词里显式要求- 生成的管道必须加入场景中的 PipeCollection 列表 - restart 时先清除 PipeCollection 中所有实体再重置分数和鸟坐标。6.3 帧率不稳导致难度漂移AI 第一次生成的移动逻辑里管道每帧固定移动 7 像素。这在一台稳定 60 帧的机器上没问题但一旦掉到 30 帧游戏速度立刻下降一半玩家会明显感觉“节奏变慢了”。我把它改为每帧移动120 * dt像素即先乘以每帧间隔时间再累加到位移量。这一点在多个游戏框架里都是老生常谈但 AI 生成代码时经常会“忘记”乘dt生成完必须逐行检查。6.4 高速下落时“穿过”管道把帧率调到 30 帧测试时鸟下落速度最快能到 500 px/s每帧移动约 17 像素。而管道的碰撞盒厚度只有 70 像素理论上不会穿模。但 AI 生成的小鸟碰撞盒比较小管道和鸟的厚度加总后在极端情况下仍可能出现检测不到碰撞的一帧。这里我没有走连续碰撞检测的复杂路线而是采用了一个更务实的方案把碰撞检测从“每帧检测一次”改成“按固定时间步长做两次子级检测”同时适当扩大碰撞盒宽度到和管道一致。对原型来说这个方案已经完全够用。6.5 AI 把“像素”和“逻辑单位”混为一谈我在 480×720 画布上开发AI 生成的某些随机范围用的是“0~1000”这种和画布无关的值导致管道经常生成在画面外或者洞口偏离可玩区域。反复修正太耗费时间后我改变了策略在提示词里把所有数字单位统一写成“画布像素”并给出画布尺寸作为前提。这个提示词上的小细节让后续生成的代码正确率肉眼可见地上升。7. 和 AI 协作生成游戏代码的一点心得这次项目做下来我对“ AI 自动生成游戏代码”这件事有了更具体的认知。AI 很适合承担那些“模式化表达”的工作把核心算法转成代码、生成重复的碰撞组件、把 JSON 配置读取逻辑补全。但它的输出质量高度依赖“需求输入的清晰度”。你给它的提示词越接近一份验收标准它给你的代码就越接近可运行的产品。我通常的做法是先写出一段 30 行左右的需求说明再让它生成代码跑通之后再让 AI 自己补充注释和重构。人工审查环节不能省。我见过很多人把 AI 生成的代码直接丢进项目结果逻辑混乱、资源泄漏、甚至安全漏洞。正确对待 AI 代码的方式是把它当成刚入职的初级开发者写的代码来 review。每一行你都要理解它的意图对不上的地方改掉而不是因为“这代码是 AI 写的”就默认它是对的。数值配置独立出来是这次最值的一步。重力、管道速度、洞口高度全部放进配置文件之后调手感只需要改 JSON再配合 AI 生成的“参数读取组件”整个项目变成了一个可以被快速试错的原型工具。后续我可以在这个基础上扩展更多玩法比如加不同颜色的管道皮肤、全球排行榜、甚至把这一套流程复用到其他小游戏上。这些扩展现在不是没头绪的事而是有了一条清晰的、经过验证的路径。