拿 AI 写了个游戏谈谈心得

AI 人工审核 gpt-5.6-sol mediumdeepseek-flash
AI 参与说明

项目整理与数据收集由 gpt-5.6-sol medium 协助完成,正文由人类撰写,格式整理与语句润色由 deepseek-flash 负责。

  • 整理方式 AI 参与写作或编辑,但不代表整篇均为 AI 收集整理
  • 人工审核 已复核
  • gpt-5.6-sol medium 整理项目、数据收集
  • deepseek-flash 格式整理、语句润色

最近伙同我的好友 @Codex(是的没错,他自己取名字叫 @Codex,并不是 OpenAI 的 Codex),我们两个差不多奋战了3周,把一个游戏从零做到了上线。

游戏叫《无限弹球》,已经在 TapTap 上线。截至 2026 年 8 月 5 日,页面显示 8.8 分、64 条评价、1.8 万热度,2026 年 7 月 2 日上线,最近一次更新是 7 月 22 日。

它不是一个只在本地跑起来的 Demo。玩家真的下载了,真的玩了十几个小时、几十个小时,很多玩家的构筑甚至比我们自己在开发时做的还要复杂,大量的机制互相协作,甚至出现了我们自己都没想到的无限循环和高密度连锁。

所以这篇文章不准备讨论“AI 能不能写游戏”。它当然能,至少能把一个游戏写到上线。但“写出来”和“做得好”“长期改得动”,完全是三件事。

本文只复盘 TapTap 上发布的这版《无限弹球》。这是我第一次完整做游戏,很多问题现在看起来很基础,但当时确实是一路踩过去的。

几个月前,我在《我让 AI 重写了一遍博客》里写过 Vibe Coding 最让人上头的阶段:AI 疯狂输出,人只需要 Review,两个周末就能完成过去不想再碰的大重构。那种效率提升是真的。这次做游戏,则让我看到了同一件事的另一面:当项目不只是“重写一个已有答案的东西”,而是需要同时探索玩法、数值、内容和技术边界时,Review 本身也会迅速超过人的处理能力。

为什么选择 Godot

如果从 AI Native 的角度选择技术栈,我心里的第一名、无冕之王永远是 Native JS,第二名就是 Godot。这也是我最初选择 Godot 的重要原因。

Native JS 的优势很直接:模型见过足够多的 JavaScript、HTML 和 CSS,运行环境容易搭建,页面结构和状态也方便直接检查。AI 不仅能写,还能立刻运行、截图、读取 DOM,再根据结果继续修改。整个反馈回路几乎没有中间层。

Godot 虽然是游戏引擎,但在 AI 协作上也有一个非常显著的优势:

它不需要任何专用 MCP,AI 就可以直接修改引擎项目里的绝大多数内容。

脚本、场景和资源大多是纯文本的 .gd.tscn.tres。AI 可以直接创建节点、调整锚点、修改材质参数、绑定资源和重排场景,不需要先学会操作一个只能靠鼠标点击的封闭编辑器。

项目里绝大部分界面都是这样完成的:把设计稿交给 AI,让它自己测量间距、尺寸和位置,修改场景以后运行并截图,再自己核对像素。对不上就继续改,直到结果接近设计稿。很多时候我并不需要亲自打开编辑器拖控件,AI 可以在“读纯文本配置、运行场景、截图比较、继续调整”之间形成完整闭环。

这也是 Godot 相比很多大型商业引擎更适合 AI Native 开发的地方。不是因为 AI 更懂游戏,而是因为项目状态足够透明,绝大部分修改都能被文本化、版本化和自动验证。

但我在引擎选择上也犯了一个很大的错误:

把极重的复杂计算放在 GDScript 里实现。

Godot 在复杂纯计算上并没有优势。GDScript 的性能特征和 Python 有点像:当它调用的是引擎内部已经由 C/C++ 实现的能力,例如物理、渲染和场景操作时,可以快如闪电;但如果让 GDScript 自己跑大量循环、规则聚合、动态容器操作和高密度事件结算,性能很快就会成为问题。

这点和 Lua,尤其是 LuaJIT,不太一样。LuaJIT 再怎么折腾,纯计算场景里通常还有一个接近 C 性能的保底,不太容易在极端运算环境下直接拉开两个数量级。GDScript 没有这样的 JIT 保底。一旦玩法允许分裂、回响、复制、销毁和重发互相放大,原本看起来只是一些普通循环的代码,就会在一帧里被执行成千上万次。

项目的性能记录里,一次 destroy_ball 最慢超过 100 毫秒、一次 spawn_ball 最慢超过 80 毫秒。虽然这不全是语言本身造成的,里面还有同步规则链、对象生命周期和重复计算,但把整套高密度规则解析都压在 GDScript 上,确实放大了问题。

如果一定要说这次最让我后悔的技术选择,并不是用了 Godot,而是:

没有在一开始就把复杂规则和结算层写成 C#。

后来我们针对纯计算做过一个很简单的 benchmark。在相近的计算任务里,C# 大约比 GDScript 快 270-480 倍。这个数字第一次跑出来时其实有点让人绝望,因为它意味着我们后面花大量时间做的缓存、分帧、对象复用和调度优化,有相当一部分是在弥补一个从技术选型阶段就存在的巨大性能差距。

当然,这不代表把项目换成 C#,整款游戏的帧率就会直接提高 270-480 倍。物理、渲染、节点操作、资源加载和移动端提交仍然由引擎及其他环节决定,这个简单 benchmark 测到的主要是纯循环、规则聚合和数据处理。但偏偏《无限弹球》后期最重的部分,就是这类会被高密度触发反复放大的纯计算。

如果当时仍然使用 Godot 管场景、物理、资源和 UI,只把规则引擎、数值结算和高密度队列放在 C#,很多架构问题依然要解决,无限连锁也依然需要预算和收束,但我们的性能余量会完全不同。至少不需要在每一次正确性修复以后,立刻担心多一层 Action、多一次 RuleBinding 分发或多一个 Settlement 对象会不会把移动端帧耗再次推爆。

这也是一种很具体的后悔:方向其实不难想到,却因为 GDScript 开发起来太顺手、AI 写起来也太快,一直没有在项目还容易迁移的时候停下来。等性能问题真正暴露,规则、资源、测试和大量物品已经全部绑定在现有实现上,语言迁移不再只是重写几个热点函数,而是要重新验证整个游戏的结算事实

所以 Godot 的优点和缺点其实来自同一个地方:

它非常容易让 AI 直接把东西做出来,但“容易实现”不代表“适合承载任何计算”。

场景、资源、交互和引擎能力可以放心交给 Godot;会随组合规模成倍增长的纯计算,则应该在设计阶段就控制复杂度,或者尽早移动到更适合的执行层,而不是等玩家打出极端构筑以后再靠分帧队列救火。

实际用了哪些模型

这个项目的主要开发模型是 GPT 5.5,中后期也用过一段 GPT 5.6,但整个游戏基本是在 GPT 5.5 的配合下完成的。少量使用了 Fable 和 Opus,美术图片则大量使用 gpt-image-2

我没有为每个模型建立一套非常严格的分工。整体上 GPT 5.5 承担了绝大部分代码、架构、排错和内容实现,GPT 5.6 主要参与中后期的部分任务,Fable 与 Opus 只在少量任务中参与。图片生成则是另一条独立工作流:先用 gpt-image-2 生成,再通过后文会提到的美术 Skill 固定风格、尺寸、透明背景、原图归档和运行时导入。

回头看,模型之间的差异当然存在,但它们并不是决定项目最终质量的主要变量。

真正影响更大的,还是提供给模型的上下文、规则边界、验证工具,以及我自己有没有先把问题想清楚。

AI 最擅长的,恰好也是第一个坑

AI 最擅长快速把想法变成东西。

我想要一种新球,它可以写规则、补资源、接 UI、加描述;我想要一种新钉子,它可以顺手把碰撞、成长、销毁、特效都接上;我觉得某个流派缺内容,它可以很快再补十个物品。

这带来了一种非常危险的错觉:

产出速度等于开发进度。

项目早期曾经一次性数据化了 40 种 Ball、35 种 Peg、11 种 Relic 和几十种效果。文件很多,卡牌很多,图鉴看起来也越来越丰富。但游戏的胜利条件、流派闭环、数值曲线和运行时边界,其实都还没有稳定。

正常开发里,做一个复杂物品很贵,成本会逼着人先问:

  • 这个机制真的有必要吗?
  • 它在构筑里是什么位置?
  • 玩家能不能理解?
  • 它跟现有规则组合以后会发生什么?

AI 把“实现成本”压低以后,这几个问题不会自动消失,反而更容易被跳过。以前是想清楚再写,现在很容易变成先让 AI 写出来,觉得不好再改。

而游戏设计最怕的就是“什么都先做一点”。

第一个创作问题:什么都想放进去

玩家的一条长评说得很准:

球分类型,又分碰撞分、落桶分、速度分;物品有驻场、离场、奇偶回合效果,还有回响、消耗、不灭、移除;每一件单看都能解释,叠在一起就很难知道到底发生了什么。

我当时的回复也很诚实:第一次做游戏,确实什么都想试试,能想到可以放进弹球里的机制,几乎都放进去了。

这就是第一个创作上的大坑:

把“每件物品都不一样”当成了内容质量。

为了避免重复,我会不断给新物品增加差异。结果不是每件物品都更有特色,而是很多物品同时承担两三个职责:既生产东西,又成长,又销毁,还会转化别的物品或跨回合结算。

后面回头整理时,最该删的已经不是某个数值,而是这种多重职责。比如一个物品同时负责产物、成长、销毁和转化,开发者很难保证时序,玩家也不可能一眼理解。

真正好的差异化不是每件物品都有一套新规则,而是少量清晰规则可以组合出不同结果。

第二个创作问题:有“流派”,但没有构筑闭环

早期设计里,Money、食物、动物、太空、随机倍率、回合成长、永久销毁,甚至某种触发方式,都被我叫作“流派”。

后来才发现,这些东西根本不在同一个分类维度里:

  • 有的是主题,例如太空、食物;
  • 有的是资源,例如临时球、现金、销毁次数;
  • 有的是发动机,例如分裂、回响、复制;
  • 有的是终端,也就是把积累的资源真正换成分数的东西。

名字都叫流派,不代表它们真的能构成一套玩法。

当时甚至出现过 11 个 Peg 都在生产临时球,真正消费临时球的却只有 4 个;Money 物品自己形成封闭循环,和其他体系几乎没有关系;某些强力终端需要高分球,但系统里没有稳定的成长路径把球送到那个位置。

这类问题 AI 很难替我发现。因为每个需求单独看都是合理的:做一个产球 Peg,做一个吃球 Peg,做一个高分终端。只有把整局资源流画出来,才会发现生产、加工和消费根本不平衡。

第三个创作问题:先定目标分,再想怎么让玩家追上

数值是我踩得最重的一坑。

有一版关卡目标从开局到 8-5 增长约 33000 倍,但当时已有物品的成长几乎全是线性加算。内部算下来,最强构筑离最终目标还差约 1000 倍。

为了解决这个缺口,我开始加入翻倍、累乘、平方和额外乘区。结果很快又走到了另一边:玩家在前期就凑出无限回响、无限分裂或极高倍率,闭着眼睛发球也能过关;到了后期,一颗球在场上跳十几分钟,玩家只能看动画。

TapTap 上有玩家总结得很直接:

爽过头了,没有把控好度,反而适得其反。

另一位玩家说,关卡只是不断提高目标分,删掉关卡和分数限制似乎也没有影响。这个反馈指出的不是某个数字填错了,而是关卡没有形成新的决策。玩家已经完成构筑以后,后面的操作只剩下继续点发射,等待某一关数值终于超过自己。

我当时确实处在“水多了加面,面多了加水”的阶段:玩家太弱就补乘区,玩家太强就抬目标或砍单卡。没有稳定的数值模型,也没有先用可重复的局面验证完整成长曲线,所以每次平衡都会改变另一批物品的价值。

玩家反馈的 Bug 到底是什么

上线以后,玩家报出来的问题大致可以分成五类。

1. 无限循环和高密度连锁

最典型的是“落桶触发回响”和“累计落桶触发回响”互相触发。玩家一旦凑出组合,理论分数无穷大,但游戏也永远无法进入下一回合。

类似问题还有太空碎片与回声室无限重发、分裂和不灭让球不再消耗、生成请求持续积压、同一物理帧重复刷新绕过队列额度。玩家看到的是一颗球打几分钟、越来越卡,最后无法操作;开发侧看到的是规则递归、对象持续生成和待处理事件没有上限。

最早的处理是给单个物品加“每球每回合一次”之类的限制。这能立刻止血,但会牺牲玩家好不容易构筑出来的收益,也没有解决其他组合再次形成无限链的问题。

后来的处理思路变成:

不直接禁止收益,而是限制每帧工作量。

命中、落桶、销毁、生成、重发和表现进入队列,按帧预算处理;球池设置硬上限;每次发射共享 90 秒墙钟上限,超时后停止产生新的物理球,但已经结算的分数和状态仍然提交。高频特效改为批量绘制,浮字和 HUD 刷新也要合并。

这个方向比给每张卡打补丁正确,但它来得太晚。等到玩家已经可以制造无限链时,性能问题其实已经变成了整个运行时模型的问题。

2. 对象身份和状态归属错误

分裂体、复制体、母球看起来都是“另一颗球”,但规则上并不一样。有的限制应该和母球共享,有的应该独立计算。

这里出现过很多很难靠单物品测试发现的问题:分裂体错误消费母球的回响次数;复制体触发水晶球效果时误删原球;对象池复用后,新球继承上一颗球的传送次数;生成球出现了,但它自己的规则没有注册。

处理这类 Bug 的关键不是再加一个 if,而是明确“身份是谁的、状态存在哪里、复制时哪些状态继承、回收时哪些状态必须清空”。后来分裂体和母球共享每球限制,复制体独立计算;对象回收统一重置运行时状态;规则状态跟随物品实例,而不是散落在场景节点上。

3. 销毁、移除和奖励时点混乱

Chicken 和 Mitosis Peg 曾经在被移除后不产蛋、不复制球。原因是等到奖励结算时,原来的场景节点和部分状态已经不存在了。替补、不灭、永久移除、付费移除叠在一起时,还出现过原目标的移除效果被跳过、替补的不灭没有生效等问题。

最终需要把几个概念拆开:发出销毁请求、判断是否阻止或替换、确认销毁事实、从场景移除、结算销毁收益。奖励只依赖销毁时保存的必要状态,而不是回头访问已经离开场景的对象。

这类 Bug 是“为什么逐渐改不动”的核心例子。玩家只看到某只鸡没有下蛋,背后却牵涉规则时点、节点生命周期、状态快照、对象池和表现层。

4. 玩法结算被动画和场景生命周期影响

中子星的射线曾经因为上一段特效还在播放而不再结算;回收后的球会被尚未完成的传送动画重新显示;高频射线会在回合结束后继续补播;分数浮字可能访问已经离开场景的节点。

这里的原则后来才逐渐清晰:

动画只能展示已经发生的结果,不能决定玩法是否发生。

玩法冷却和结算时点必须独立于特效时长,回合结束时要取消尚未提交的表现请求,表现层过载时可以丢弃动画,但不能改变得分。

5. 编辑器正常,发布包却坏了

有一版移动端出现多个物品显示“没有特殊规则”,回响、不灭、暴击等效果也可能不工作。原因不是规则本身写错,而是依赖只在动态路径里被引用,导出包没有正确带上相关资源。

这件事提醒我,编辑器里跑通不等于发布包可用。移动端还暴露了富文本溢出、英文名漏翻、CSV 分隔符乱码、null 和 HTML 标记直接显示、最高分未保存、折扣买入却按原价退款等问题。

后面的处理包括显式加载规则资源、维护真机复现存档、给高风险组合保存固定测试局面,并让每个移动版本都有对应的变更记录。但发布后才开始补这套流程,代价明显更高。

我是怎么处理玩家反馈的

玩家反馈最有价值的部分,往往不是“这里有 Bug”,而是他们带来的真实构筑

开发者很容易按物品逐个测试:太阳能不能生成太阳耀斑,海洋之星能不能复制宝石,回响能不能重发。玩家不会这么玩。他们会把海洋之星、炼金术、黑洞、中子星、分裂、不灭和回响全部装在一起,然后连续玩十几个小时。

后来比较有效的处理流程是:

  1. 先保留玩家的存档、构筑、回合和触发条件,不急着根据一句描述猜代码。
  2. 按问题类型分类:把问题分成规则错误、时序错误、状态归属、对象生命周期、性能过载、移动端打包差异,而不是按物品名称分工。
  3. 修复后保存成压力存档,避免同一类组合换个物品又回来。
  4. 同时检查“最终结果是否正确”和“这一帧做了多少工作”。只看不卡死,可能已经吞了玩家收益;只看分数正确,也可能一帧卡上百毫秒。
  5. 对玩家无法理解的问题,不只改代码,还要检查描述、得分归因和图鉴。很多所谓 Bug,其实是系统发生了正确但无法解释的事情。

这个过程也让我意识到,玩家反馈不能只被整理成一个 Bug 列表。无限回响、看不懂得分来源、后期只能挂机、随便选也能过关,看起来是四条反馈,实际指向同一个设计问题:触发链太强、信息又不透明,玩家的决策逐渐失去意义。

为什么游戏逐渐改不动了

最直接的答案是:

规则数量增长得比规则模型快。

这里需要先说明,我们并不是完全没有做早期架构设计。恰恰相反,结算体系是整个项目里考虑得最多、也被反复设计过的部分之一。

我们很早就在拆分撞钉分和落桶分,设计不同的分数修饰通道,区分 Ball、Peg、Relic 的触发顺序,用 Effect 表达可组合行为,再用统一的事件 Resolver 处理命中、落桶、销毁和奖励。场景层也做过拆分,试图把棋盘、商店、背包、覆盖层和全局状态放进各自的边界里。

这些设计在当时并不是拍脑袋。每一轮都在解决上一轮已经出现的真实问题,也确实让项目继续向前走了一段。问题是:

计划赶不上变化。

最初的结算模型主要处理“命中以后加多少分”“落桶以后乘多少倍率”。后来玩法逐渐要求替换一次销毁、把销毁转移给另一个目标、阻止移除但保留销毁收益、让分裂体和母球共享部分限制、让复制体独立继承另一部分状态、等待动画以后重发、在对象已经回收后继续结算奖励。这些已经不是原来公式上再加一条 modifier,而是在不断扩展“一个动作究竟是什么”。

架构设计只能基于当时已经知道的需求建立边界。玩法机制却在 AI 的帮助下快速增加,每一周,不准确的说,在开发的时候每一个小时都可能出现新的组合和新的语义。于是原本合理的抽象不断被要求承担计划外职责:Effect 从数值修饰长成了世界副作用入口,Context 从事件参数长成了所有系统的临时仓库,Resolver 从统一顺序长成了大量特殊时点的总调度器。

所以这次的教训也不是“前期架构没有意义”。没有这些设计,项目可能更早就会停下来。真正的问题是,我们把架构当成了已经解决的问题,却没有同步控制内容扩张,也没有在需求改变抽象前提时及时停下来重画模型。AI 又让旧架构继续打补丁的成本显得很低,结果每一次都还能往前走一点,直到局部修补的总成本超过了重做。

早期为了快速实现内容,每个 Effect 既可以改分数,也可以直接生成球、销毁球、传送、重发、改状态、播特效。一个上下文对象里同时塞着当前碰撞对象、物品状态、分数累计器、各种 modifier、销毁请求和 VFX 接口。

这在内容少的时候非常方便。要做一个效果,拿到上下文,想改什么就改什么。但内容多起来以后,没有人能稳定回答这些问题:

  • 两个效果都要替换这次销毁,谁先执行?
  • 不灭阻止的是销毁事实,还是只阻止从棋盘移除?
  • 回响是在落桶分结算前还是结算后生成?
  • 一个动画还没结束,下一次玩法触发能不能开始?
  • 分裂体触发限制时,计数算在自己还是母球身上?

当时这些时点主要靠 resolver 里的手写代码顺序表达。每出现一种新需求,就增加一个 hook、一个请求类型或一条特殊分支。局部都说得通,整体顺序却越来越难解释。

同时,基础属性、全局属性修改、单次得分修饰、效果参数和运行时状态分散在多套机制里。最大的棋盘控制器还同时管理对象池、生成、销毁、结算、反馈、队列和回合状态。

到这个阶段,一次看似简单的修改会穿过很多层。例如“球销毁”并不是把节点放回对象池,它还可能同步执行销毁保护、目标替换、销毁后规则、奖励结算、状态刷新和回收。实际性能记录里,一次 destroy_ball 最慢超过 100 毫秒,一次 spawn_ball 最慢超过 80 毫秒。Command 虽然排队了,但每个 Command 内部仍然藏着一整条同步规则链

所以“改不动”不是代码文件太多,而是没有稳定的语义所有权:谁决定时点,谁能修改世界,谁保存状态,谁只负责展示,这些边界直到后期才开始补。

后来的规则引擎更正确,但也更慢

发现这些问题以后,我们并不是继续沿用旧体系,而是重新设计了一套相当完整的规则引擎。

它把一次玩法变化表达成明确的 GameplayAction,例如命中、落桶、销毁请求、销毁事实、生成球和重发;每个 Action 按固定阶段运行,Rule 不能再随意修改世界,只能提交取消、替换、数值修饰或后续命令;分数由独立的 ScoreSettlement 聚合,属性由统一的 Value Resolver 读取,最终只有 Command 的 COMMIT 阶段可以真正修改场景和状态。

这套设计其实非常合理,也精确了很多。

以前“不灭到底阻止销毁还是阻止移除”“替补承受伤害以后原目标还算不算发生过销毁”“动画没播完能不能影响下一次结算”都依赖某段代码碰巧先执行。新体系里,这些问题至少可以被放进明确的 Action、阶段和提交边界中讨论。每次规则参与、数值贡献和后续动作也可以留下 Trace,复杂组合终于有机会解释自己为什么得到这个结果。

但代价同样明显:

它慢。

一次最普通的撞钉,不再只是调用一个函数加分,而是要创建 Action、收集参与者、匹配 RuleBinding、构造 Context、按阶段派发规则、解析 Value、聚合 Settlement、生成 Command,再提交后续 Action。单次看每一步都不离谱,甚至都是为了正确性必须付出的成本;可是一旦分裂、回响和复制把一次发射放大成成千上万次命中,这套完整管线也会被重复运行成千上万次。

它解决的是“每次结算是否精确”,没有自动解决“每秒会发生多少次结算”。而 GDScript 恰好又不擅长大量动态对象、Dictionary、循环、规则分发和短生命周期分配。于是一个在架构上更清晰、更可测试、更容易 Trace 的系统,在极端纯计算压力下反而比原来的直接调用更重。

这里很难简单说规则引擎设计错了。它所保障的顺序、归因、替换和提交边界都是真实需要的。如果为了快重新退回让每个物品直接改场景,Bug 只会更难处理。真正的问题是我们同时选择了三件会互相放大的事情:允许近乎无限的触发密度、为每次触发执行高精度规则管线、再把整条管线放在 GDScript 中运行。

后续做队列预算、分帧调度、对象池、批量表现和 Command 性能实验,本质上都是在想办法保留这套精确语义,同时不要让它在一帧里把无限工作全部做完。但这也意味着,项目不再只是做玩法,而是在为一套高吞吐规则运行时补调度器、预算器、性能基准和收束机制。维护成本就是从这里开始明显失控的。

比语言更根本的问题,是无节制地释放 Rule

C# 的 benchmark 很夸张,但如果只把问题归结为 GDScript 太慢,还是会漏掉最根本的一层:

我们无节制地向游戏里释放了太多 Rule。

这里的“多”不只是文件数量。每个 Rule 还带着自己的触发时点、参与者范围、状态、数值读取、世界命令和后续 Action。有些 Rule 每回合触发一次,有些每颗球触发一次,有些则会在每次撞钉、落桶、销毁、生成和重发时触发。更危险的是,Rule 的结果又可能制造下一次 Rule 的输入。

单看任何一条都不严重:命中时有概率分裂,落桶时获得回响,销毁时再生成一颗球,生成球落桶后复制一次效果。但它们组合起来不是简单相加,而是互相放大。一个新 Rule 不只是增加一个功能,还可能和已有几十条 Rule 分别形成新的交互,甚至把原本有限的触发链闭合成循环。

当时我们对物品有稀有度、价格和数值强度预算,却没有真正建立 Rule 预算。没有人在新增规则时强制回答:

  • 它最多会被触发多少次?
  • 它会不会生成新的物理事件或后续 Action?
  • 它和分裂、回响、复制、不灭组合后的上界是什么?
  • 它是否又引入一种新的状态所有权或特殊时点?
  • 玩家能否从画面和得分归因中理解它?
  • 为了这一条 Rule,运行时、测试和 UI 要多维护多少分支?

AI 又让释放 Rule 变得太容易。过去新增一种机制可能要写几天代码,成本本身会迫使人克制;现在一句话就能把规则、资源、说明和特效都补齐。于是“能不能实现”几乎不再构成限制,而“应不应该进入正式物品池”又没有足够严格的闸门。

这也是为什么换成 C# 只能解决一部分问题。快 270-480 倍可以给系统巨大的性能余量,却不能让无限工作变成有限工作,也不能自动降低组合复杂度。无节制的 Rule 最终仍会吃完任何预算,只是出问题的时间更晚。

如果重新来一次,我会给 Rule 本身设置内容预算和复杂度预算:

优先复用少量通用 Rule;一件物品只保留一个主语义;高频 Rule 不允许无上限地产生新事件;能形成闭环的 Rule 必须有明确的收束证明;每开放一个新物品,都要先进入固定极端构筑做组合验证。

Rule 不应该因为已经写完就默认可以发布。

AI 在“改不动”这件事里扮演了什么角色

这不能简单归结为“AI 写的代码质量差”。很多具体实现其实能跑,局部逻辑也很完整。真正的问题是 AI 会非常忠实地放大当前的开发方式。

如果需求是“给这个物品加一个特殊例外”,AI 很擅长找到调用点、补分支、更新文案和修测试。下一次再来一个例外,它也能继续补。每一步看起来都完成得很快,直到几十个局部正确的补丁叠成一个没人能完整推演的系统。

AI 不会天然替项目维护统一的世界观。这里的世界观不是剧情,而是程序里的规则事实:什么叫销毁,什么叫落桶,什么叫复制,什么叫一次发射,什么是已经发生,什么只是准备发生。

这些概念如果没有先由人定义清楚,AI 会根据当前文件、当前命名和当前需求给出一个看起来最顺手的解释。上下文一换,同一个概念就可能得到另一种实现。

换句话说,AI 大幅提高了写代码和改代码的速度,但没有替我承担架构决策。

因为实现太快,我反而更晚才感受到错误抽象的成本。

这种感觉和我之前写的《AI 时代的开发疲劳:低生产成本与高决策成本》几乎是同一个问题:浅层实现被 AI 快速清空以后,人要连续处理的是方向、架构、验收和取舍。生产成本下降了,待判断的决策数量却在增加。

我在《AI 时代的 idea 贬值与验证基础设施》里也写过,未来缺的可能不是“想到”,而是稳定地验证想法。《无限弹球》算是一次非常具体的反例:我有太多能迅速落地的 idea,却没有一套同样高效的系统,及时证明哪些机制不该进入游戏、哪些数值组合一定会失控。

真正值得保留下来的,是 Skill

虽然前面说了很多问题,但这个项目也让我确认了一种很有效的 AI 工程化方法:

不要只保存一次成功的结果,要把产生这个结果的判断过程固化成 Skill。

最典型的是生图。

一开始让 AI “画一个游戏道具”,每次都像重新抽卡。有时是扁平插画,有时是发亮的 3D 手游图标,有时物体撑满画布,有时 Peg 看起来又像 Relic。即使某一次结果很好,下一次换个对话、换个模型或换个物品,风格还是会面目全非。

后来我把这套过程写成了常驻的物品美术 Skill。它不只是保存一句提示词,而是同时固定:

  • 什么时候应该触发这项能力;
  • 生成前必须查看哪些同类参考图;
  • 每次提示词都必须包含的风格锁定句;
  • 224×224、透明背景、轮廓粗细、主体占比和留白范围;
  • 禁止渐变、柔光、真实材质、镜面高光、3D 深度和精致 App 图标感;
  • Ball、Peg、Relic 各自不同的构图约束;
  • 先用纯色背景生成,再抠图、缩放、检查透明角的处理流程;
  • 原图备份、运行时压缩、Godot 导入和资源引用;
  • 什么结果必须拒绝并重新生成。

这里真正被固化的不是某张图片,而是“我如何判断一张图属于这个游戏”。下一次 AI 不需要重新猜我的审美,它会先看参考图,使用同一段 Style Lock,按相同尺寸和留白生成,再执行同一套验收。

这也是 Skill 和一段超长 Prompt 的区别。Prompt 通常只解决当前对话,Skill 更像一份会被自动触发的、带验收标准的 SOP。一个可复用的 Skill 至少应该写清楚五件事:

  1. 触发条件:用户说什么、任务碰到哪些文件或场景时必须使用。
  2. 事实与边界:项目当前采用什么架构,哪些做法明确禁止。
  3. 固定流程:先读什么、调用什么工具、产物放在哪里、按什么顺序执行。
  4. 验收标准:尺寸、格式、测试、视觉对比、性能指标或发布字段达到什么程度才算完成。
  5. 失败经验:过去出现过什么偏差,遇到类似结果时应该拒绝、回退还是换一种做法。

随着项目推进,我把越来越多流程做成了这种能力:

  • 新 Ball Skill 会强制使用统一规则架构,禁止每个物品创建一套私有继承,禁止规则直接修改场景和状态,并锁定资源、README、开放清单、Manifest 和验证步骤。
  • 性能优化 Skill 会要求先保存真实构筑、建立 P95/P99 基线、保持得分和触发次数不变,每次只改一档,重复基准没有收益就回退。
  • 图片压缩 Skill 会固定原图备份、Manifest、运行时覆盖和验证流程,避免 AI 只替换游戏目录里的图片,导致真正的源文件丢失。
  • 更新日志 Skill 会从移动端版本号推导唯一文件名,强制中英文同步,并保证已经发布的历史版本不被后续任务覆盖。
  • UI 切图 Skill 会明确只能从设计原图切,不能重绘、不能复用项目里已有图片,还规定了透明图输出和遮挡区域修补方式。

每次 AI 犯错以后,如果只在当前对话里说一句“下次别这样”,这条经验基本等于没有留下。把“Peg 总画得太大”“模型喜欢加 3D 高光”“新增物品忘记加入开放清单”“优化后分数对了但归因变了”写进 Skill,错误才会变成下一次任务自动读取的约束。

这样做以后,项目确实会呈现出一种积累效应:任务做得越多,AI 越了解目录、术语、禁区和验收方式,后续需求需要反复解释的内容越少。它不是模型自己突然变聪明了,而是项目把原本只存在于我脑子里的隐性知识,逐渐变成了机器可以重复执行的外部记忆

不过 Skill 也不是越多越好。它只能稳定复制已经明确的判断,也可能把错误架构永久固化。如果项目的事实已经变化,Skill、项目说明和测试必须一起更新;如果某个流程还在探索期,就不应该急着把第一次成功写成不可违背的硬规则。

这正好对应我在《AI 时代的工程护城河》里提到的三件事:鉴赏、编排和上下文。Skill 做的事情,就是把人的鉴赏标准、任务编排和项目私有上下文沉淀下来,让 AI 不必在每次任务里从零猜测。

如果再做一次,我会先做什么

1. 先做十件能组成闭环的物品,不做一百件孤立的物品

先确认资源从哪里来、经过什么加工、最终在哪里转成分数。一个流派至少要有入口、成长和终端,而且每件物品尽量只有一个主语义。

2. 在写内容前先写完整数值模型

不是只看单卡收益,而是模拟从第一关到最后一关,计算线性成长、乘法成长和高频触发的实际次数。x1.2 触发一次很温和,触发 100 次完全是另一回事。

3. 先定义规则边界,再让 AI 批量生产

物理只报告碰撞事实;规则只能提交加分、取消、替换、生成等请求;统一的结算器决定顺序;只有提交阶段能改场景和状态;动画只消费结果。

这些边界如果先立住,AI 才适合批量扩内容。否则它只是在用更高速度复制当前架构的缺陷。

4. 从第一天就保存真实构筑作为回归样本

单元测试适合验证公式,但这种组合游戏还需要完整构筑存档。每次玩家打出一个极端组合,都应该能一键复现,并记录最终得分、触发次数、队列峰值和最长帧耗。

5. 发布包必须独立验收

编辑器、桌面调试版和手机导出包不是同一个环境。规则资源、字体、语言、存档迁移、触摸滚动、长文本和性能,都要在真实发布包里走一遍。

千万千万要记得:性能必须在真机上测试。PC 性能和 mobile 性能完全是两回事。 桌面跑得再流畅,放到手机上可能是另一帧率、另一套热降频和另一套内存预算,只靠编辑器或 PC 调试版验收性能,等于没验收。

6. 更早做减法

复杂不是深度,独特也不等于好玩。

玩家看不懂自己的分数从哪里来时,再多机制都只会变成噪音。删掉一个承担三种职责的物品,可能比再加十条说明更有效。

最后的心得

拿 AI 写游戏最大的收获,不是证明一个人能在多短时间内堆出多少代码和内容。

真正的收获是:

AI 把实现速度提高以后,人的判断会更早成为整个项目的瓶颈。

以前很多坏想法会因为做起来太贵而死在纸上。现在它们可以在半小时内变成一个看起来很完整的功能。于是最重要的能力不再是“能不能做出来”,而是能不能及时判断:这个东西应不应该存在,它属于哪套规则,它会不会破坏已有系统,以及玩家为什么要为它做选择。

《无限弹球》最终确实上线了,也确实有玩家觉得它好玩、上头,愿意研究各种离谱组合。这部分不是假的。但玩家越深入,越容易碰到 Bug、性能问题和无法解释的结算;玩到后期,构筑越强,操作和选择反而越少。这说明游戏最初的爽点成立了,支撑爽点长期发展的结构却没有同时成立。

AI 可以帮我把一个游戏写出来,甚至帮我快速修掉大量 Bug。但它不能替我决定什么才是这个游戏,也不能替我在一开始就拒绝那些虽然能做、却不该做的东西。

这大概就是我从这次开发里学到的最重要的一件事。

之后呢

说了这么多问题,但这个项目我是真的很喜欢。玩家愿意去研究那些离谱组合,本身就是对玩法方向最好的肯定。如果周末还有时间,我会继续维护它,让它慢慢变好。

下一个游戏,会带着这些教训重新开始。如果真的有缘,希望有一天能做一个 Steam 上的游戏,到时候再回来和大家分享。

本文标题: 拿 AI 写了个游戏谈谈心得

永久链接: https://iceprosurface.com/thought/building-a-game-with-ai/

作者授权:本文由 icepro 原创编译并授权刊载发布。

版权声明:本文使用 「署名-非商业性使用-相同方式共享 4.0 国际」 创作共享协议,转载或使用请遵守署名协议。