今晚吃什么
像素风「吃东西进化」类幸存者游戏:一只靠吃进化的史莱姆,边打边吃、三选一养成,还能让 AI 现场为你生成本局专属食物。也是一次方法论实验——当代码几乎全部由 AI 产出,如何让它的产出可被信任。
吃食物攒进化度,攒满三选一,四大流派 × 三层进化树叠加金色组合卡。战死或通关回小屋,用掉落的调味料熬煮、购物、换装,再来一局。向大厨点一道菜,游戏会现场生成它——文案、像素图、数值、专属进化分支,只属于你这一局。
代码不是我写的,是我定义、审查、验收的
一句话:AI 负责把东西做出来,我负责定标准、挑毛病、决定它能不能上线。
稀缺的能力不在产出,在判定——所以工程重心从「怎么做出来」移到了「怎么知道它真的对」。
- 想做的功能
- 先写设计规范 要什么、不要什么 · 45 份
- 再写执行计划 分几步做 · 62 份
- 按风险决定怎么协作 低:直接做 / 中:先讨论 / 高:做完两轮审查
- AI 实现
- 129 项检查全过才算完 有红的:定位 → 先复现 → 再修
- 人工评审
- 写进优化日志 16 批 · 含明确没修的项 · 回头改规范
低风险 技术债 / 重构 / 补测试 直接实现 → 聚焦验证 中风险 玩家可感知的 UI / 手感 / 数值 先讨论再实现 → 单次评审 高风险 跨模块行为 / 发布就绪 实现 → 规范审查 → 质量审查
规范先行。 我先把要做的东西写清楚,AI 再动手。同一个功能,规范写得含糊,AI 给你的就是一个「能跑但不对」的版本;规范写死,基本一次过。这在几十次迭代里是可观察、可复现的因果关系,不是玄学——所以这个项目里 45 份设计规范加 62 份执行计划,是最不像代码、却最决定代码的部分。
踩过的坑要变成清单。 一年下来沉淀的不是「AI 很好用」这种感受,而是一份 AI 在真实引擎项目里会怎么翻车的清单:什么现象、什么原因、以后怎么绕开。下面三条可以展开看。
检查脚本自己打印「全部通过」,判定却是失败
进程假死,一行输出都没有
换台电脑检出代码,几十项检查同时报错
怎么让「检查通过了」这句话可信
「门禁」就是一堆自动跑的检查脚本:任何一条不过,这次改动就不许合并。这一节讲的是——怎么让这些检查真的说真话。
代码能跑不等于代码是对的。中间隔着三种假象:AI 自己说测过了、本机缓存把问题挡住了、失败重试一次就变绿。还有第四种最阴——全程没有任何报错,产出的东西却是废的。
只看数据和规则本身:字段有没有填错、文件有没有缺、算法结果对不对、该接的线有没有接上。快到每次改动都能跑一遍。
起完整引擎跑真实的帧,验系统之间的配合:怪刷得对不对、buff 叠得对不对、技能相位、UI 有没有按时绑上。慢,但能抓到只在跑起来时才暴露的问题。
把以前买过的每张真实原图重新切一遍,跟上次的成绩比:只许更好,不许变差。单独放,是为了不让「素材没准备好」变成整套检查飘红的理由。
机器判不了的东西:构图、颜色、好不好读,只能对着美术规范一张张看。诚实地说,这部分至今没有自动化判据。
| 判定 | 什么情况给这个判定 | 拦不拦合并 | 为什么值得单独分一档 |
|---|---|---|---|
| TIMEOUT | 超时还没退出(默认 180 秒) | 拦 | 断言失败时场景常常忘了退出、就一直挂着。不单独分一档,它看起来就像「还在跑」 |
| FAIL | 输出里出现失败标记(SCRIPT ERROR / FAILED 等) | 拦 | 检查自己报告的失败 |
| ERRLOG | 出现了不在白名单里的引擎报错 | 拦 | 引擎级的运行时错误。加这一档之前,这一整类问题被系统性漏掉 |
| EXITCRASH | 断言全过,只是退出的时候崩了 | 不拦 | 唯一一种已经查清原因的失败,也因此是唯一允许自动重试一次的 |
| PASS | 正常退出,并且打了通过标记 | 不拦 | — |
| WARN | 没报错,但也没打通过标记 | 不拦 | 不允许闷声通过:没打标记,说明这项检查可能压根什么都没验 |
四条写下来的原则
它们都不是通用工程常识,而是这套体系被现实纠正之后留下的形状。
重试只能吸收已经查清原因的抖动
早期是「失败就重试一次」,套件确实变绿了,代价是把真正的偶发 bug 一起洗绿——一个 30% 概率复现的问题,重试一次后有 91% 的概率显示为通过(两次都撞上只有 9%)。所以现在只有「断言全过、仅退出时崩溃」这一种允许重试。
老债冻结,新债零容忍
新规矩遇上历史烂摊子,常见的两个选项都很差:全修完再上规则(阻塞太久),或者只写进文档不做检查(等于没有规则)。用的是棘轮——像只能朝一个方向拧的扳手:把现存的 72 处违规冻成基线,断言总数不许超过它。老的不挡路,新增一处立刻顶破基线报错;顺手清理后把基线调低,数字再也回不去。
CI 不是再跑一遍本地跑过的东西
它只跑最快的 47 项,不是图省事。开发机上堆着各种本地缓存,很多问题被缓存挡着看不见;CI 每次从零检出,相当于换一台没用过的新电脑跑一遍——新类找不到、文件漏提交这类问题只会在这里现形。
要确认门禁真的会报警,每个方向都要
故意把合格线抬高一次,看着评测报出合格率从 1.000 掉到 0.000、并以失败退出。一个从来没红过的门禁,和一个不存在的门禁没有区别。但只红过一次还不够:后来复查发现,另外三种变差它全漏了(见本节末)。有几种变差,就得各让门禁红一次——只红过一种,就只能信一种。
评测体系本身,也要被评测
回头拿本机真实流水账(每次交付、每次评审各记一行)逐行对照代码,把评测体系自己复查了一遍。查出来的问题都是一个形状:每次都「跑了」、一处报错没有,却没在做它声称在做的事。
最刺眼的一处:被当作基线的交付流水账,134 行里曾有 126 行是检查脚本自己写的,真实交付只有 8 行。
| 原以为 | 实际上 | 现在 |
|---|---|---|
| 交付流水账就是真实基线 | 134 行里 126 行是检查脚本写的:跑检查的进程和玩家共用一份账,之前的测试隔离只隔离了存档 | 按启动参数判来源,检查一律写进隔离目录;跑满 129 项,真实行数仍是 8 |
| 真图回归验过会报警 | 只验过「合格率下滑」这一个方向。基线被静默从 1.000 调到 0.893、4 张没登记的新图、不合格格子从 3 涨到 6,都照样通过 | 调低基线必须写理由、留历史;没登记的判失败;不合格格子数也纳入比较 |
| CI 拦得住引擎报错 | 报错刷屏时 20 次漏 20 次——恰恰是最该抓的时候 | 新写法 0 / 20;本地和 CI 的引擎版本、报错白名单是否一致,改由一条检查来判 |
| 带上违规理由重发,模型会在上一稿上改 | 请求是单轮的,模型根本看不到上一稿,等于带着约束重新掷骰。另一个项目(守线)实测过同一根因:只给理由救回 12%,加上上一稿 75% | 改成多轮、带上上一稿。这条路径在这里还没触发过,75% 是另一个项目的数,这里只是预期 |
| 美术交付有检查守着 | 那项检查查的是打包时被排除的副本,像素质量信的是 QA 记录里自报的「ok」——把图换掉照样绿 | 守真正发出去的那份,从像素重算;每条规则都做过变异测试:改坏它,检查必须变红 |
| 漏掉的问题出在哪 | 个数 | 说明 |
|---|---|---|
| 改动内 | 4 | 问题就在评审者眼前的改动里 |
| 改动外 | 5 | 问题在没改的文件里,逐任务评审结构上就看不到。最贵的一条在这里:删了一个字段、另一个文件还在给它赋值,每次生成玩家都报错——还被两份任务报告标成了「早就存在」 |
两条 AI 生产线,难的不是生成,是验收
一条离线画美术,一条在玩家点菜时现场生成整套素材。两条都不是「调个 API 拿结果」——重点全在生成之后:这东西到底能不能用,谁来判、按什么判。
生成 → 校验 → 后处理 → 验收 → 入库,五步一步不少。
先有规范,再有生成。 一份全项目美术规范先定死视觉基调、像素网格、色板与明度、描边与色阶、动画帧率、UI 字体这些硬规矩,最关键的是最后两章:四类资产各自的验收标准,以及具体怎么审。不合格的资产在入库前就被打回,而不是「生成出来了就用」。
外观必须能拆着用。 主角一局之内要进化好几次,所以外观不能是一整张图:把角色拆成固定区域,每块独立生成、独立替换,再用一份主控骨架保证所有部件对得上位。难点不在画得好不好看,在于怎么让模型的一次输出里,同时给出好几块都能直接拿来用的区域。
一次请求,交付一整套素材。 玩家点一道菜:先让 DeepSeek 写出结构化的菜品文案,再让 gpt-image-2 在一张 1024×1024 的大图里按格子画完整套素材——1 个食物图标,加 3 条进化支线 × 3 个品质的部件,本地再切开装配。为什么不一个部件请求一次?因为这个图像 API 按「画了多少像素」收费,跟请求几次无关,一张画完最省。
- 菜品文案 DeepSeek 产出结构化 JSON
- 拼出整页提示词 禁止模型自己写背景
- 一张 1024×1024 大图 1 个图标 + 3 支线 × 3 品质
- 切图:找像素团 不能按格子硬裁——模型会画歪、会溅出碎屑,所以改成挑「连在一起的那团像素」
- 去掉粉边 洋红底会把白蒸汽染粉,得把被染的颜色通道压回去
- 统一尺寸对齐
- 装到角色身上
把「能看」变成数字。 2026 年 8 月的一次事故:供应商正常出图、正常扣费,文案和技能全都成功,玩家拿到的却是默认模板外观,而且全程没有任何一处报错。问题分三层,每层都不是「报错了」,而是「根本没人判」。
- 模型正常出图并扣费,文案与技能全部成功
- 切图按 9 列 × 3 行去找精灵,模型却只在每个「支线 × 品质」块正中画了一个
- 于是有 5 个格子是空的,超过了 3 个的阈值
- 整页判废 因为当时的降级是按「整页」算的
- 已经切好的食物图标被一起丢掉——它是这份付费产出里最值钱的一格
- 玩家拿到模板外观,而全程无一处报错 日志只有一句「流程完成」,NPC 台词还把锅甩给了供应商
| 指标 | 合格范围 | 越界说明什么 | 级别 |
|---|---|---|---|
| coverage · 这格画满了多少 | 0.05 ~ 0.82 | 太低=这格基本是空的或只有碎屑;太高=背景底板没剥干净 | FAIL |
| edge_touch · 贴到格子边的比例 | ≤ 0.20 | 主体在原图上就被旁边的格子切断了 | FAIL |
| chroma_residue · 残留的粉边 | ≤ 0.02 | 洋红底没抠干净,边缘发粉 | FAIL |
| fragments · 碎成了几块 | ≤ 3 | 主体碎了,或者把邻格的碎屑一起并了进来 | WARN |
| center_offset · 偏离中心多远 | ≤ 0.25 | 取景没框准 | WARN |
降级要比付费更细。 那次事故里 5 个空格就让整页作废,连已经切好的食物图标一起丢。现在改成:图标和部件分开算,降级按支线算,只有所有支线都废才允许整页降级。另外整页原图永久存盘,所以切坏了的第一反应不是重新买一张,而是换个参数档位离线重切——那张炸鸡就是这么从「整页降级」救回「零降级」的,花了 0 元。
整条链路是围绕失败设计的。 模型一定会偶尔抽风,所以每一类失败都提前想好了兜法,而不是等它炸了再补。
| 会出什么问题 | 怎么兜 |
|---|---|
| 文案模型写的提示词自带「深色背景」,和整页的洋红底指令打架 | 生成侧禁止写背景,拼装侧再兜底剥一次——旧的缓存内容也一起受益 |
| 返回的 JSON 被代码围栏之类的噪声污染 | 先剥掉噪声再重试,而不是直接判失败 |
| 网络抖一下 | 按错误类型分开处理:连接 / DNS / TLS / 429 / 5xx 重试;超时不重试(推理本来就要几十秒,重发只让玩家多等一倍);400 / 401 / 402 重试也没用,直接失败 |
| 真的失败了 | 降级到「招牌菜」池。关键是招牌菜和正常菜走同一条生产管线——一条平时不跑、配置更弱的降级路径,真触发时只会制造出没人测过的新故障 |
| 玩家怎么感知 | 由大厨 NPC 出面道歉,玩家看到的是角色行为,不是一个错误提示 |
组合空间远大于内容体量
四大流派 × 三层进化树,叠加金色组合卡;四把餐具主题自动武器可购买、可抽卡升级;敌人按类型掉落带品质的调味料,熬煮站三合一,商店按风味点总值加配方计价。精英词缀、主题协同、菜谱墙、Boss 变体四组机制交叉相乘,让每局的组合空间远大于内容本身的体量。
技术实现
用 Godot 4 + GDScript 独立完成,数据驱动贯穿始终。
数据驱动关卡
地图、波次、Boss、天然食物、进化池全部放进 .tres 资源文件,Stage 只是共享骨架——新增一张关卡几乎不用写代码。
组件化战斗
角色由 Health / Hitbox / Hurtbox / Mover / StatBoard 等组件拼装,投射物技能走对象池;四把餐具主题自动武器可购买、抽卡升级。
调味料经济
敌人按类型掉落带品质的调味料,熬煮站三低阶合一高阶,商店按风味点总值加配方计价——一套纯静态函数实现的经济系统。
上面说的每件事,项目里都有对应文档
这些文档是开发过程中真在用的,不是为作品集补写的,也没有为它重写过一行。
| 文档 | 里面有什么 |
|---|---|
| 质量门禁与 AI 协作评测体系 | 分层门禁 · 六级判定细则 · 噪声白名单怎么从实测统计推出来的 · AI 失败模式清单 · 评测体系自己的复查:查出了什么、怎么修、怎么复验 |
| 评审漏判率复盘 | 两个工程、14 个任务 · 漏在改动内与改动外分开算 · 注明哪部分结论是推断的 |
| 全项目美术重制规范 | 视觉基调 · 硬规则 · 四类资产的验收标准与审核方法 |
| 上线就绪评审 | P0/P1/P2 分级 · 发布门禁清单 · 每条结论配一条 30 秒能复现的命令 |
| AIGC 交付页质量标准 | 成本口径 · 五项指标的阈值和理由 · 去粉边的硬约束 · 回归评测怎么用、基线什么情况下才许调低 |
| 优化日志 | 16 个批次,每次都写清怎么复现、怎么验证、以及明确没修的是哪些 |
同一套判断标准,两种生产方式。在 Liberty Engine 的海洋系统里,它是手写 HLSL、Compute Shader 和 GPU 稳定性预算;在这里,它是写给 AI 的验收细则。