下载 App
我一个人 + AI,做了个四模式的水滴肉鸽 💧
昨天 12:2916 浏览综合
《重生!我的水滴无限大》开发实录 · 490 次提交 · 4.2 万行 Lua
我是这个游戏的开发者,在 TapTap 上你直接搜「重生!我的水滴无限大」就能玩到,四种模式都是开着的。
先甩点硬数据,免得你们觉得我在吹:
🤖 490 次 Git 提交,全程一个人 + AI 结对写完
📝 4.2 万行 Lua,47 个测试文件
🎮 四种玩法:试炼、无尽、赛季、爬塔
🔄 玩法方向大转向至少 5 次,项目没死,反而越转越稳
很多人聊 AI 编程,关心的都是"AI 到底能不能写出来"。
做完这个项目,我的答案反过来了:AI 什么都敢写,问题是你敢不敢让它写。
AI 编程最大的坑,根本不是产出不了代码,而是——没拴绳的 AI 会用最快的速度,把你的项目写成浆糊。
这篇帖子讲两件事:这个游戏的四种模式是怎么实现的、怎么互相咬合的;以及我是怎么一步步把 AI"驯"得服服帖帖的。
一、一套骨架,长出四种模式
核心幻想很朴素:你是一颗水滴,靠吞噬同类不断变大——水珠 → 水团 → 水洼 → 湖泊 → 江河 → 海洋 → 行星 → 恒星 → 星系 → 宇宙。围着这条成长线,做了四个模式。
1⃣ 试炼模式(主线)
一局 90 秒,节奏是"吞并成长 → 层级跃迁 → 天灾考验 → 重生培养"
跨过阈值就跃迁,一共 10 个层级,每层终点一场天灾终局(火焰、雷击……)
天灾按百分比扣水量,不管你现在多少水,压迫感都一样
每局限 3 次"天灾救济"(看激励广告补一口),留个翻盘窗口
死了不劝退:回局外用资源做永久培养,带着符文技能书再战
90 秒是刻意设计的——单局短、失败不肉疼,"再来一把"的心理成本几乎为零。
这里有两个我推翻过自己第一版的设计,值得单独唠:
⚡ 天灾为什么按百分比扣血?
最早是扣固定数值,实测当场露馅:发育快的水量大,扣那点不痛不痒;刚跨层的底子薄,一扣回解放前。同一个天灾,有人觉得白送,有人觉得天塌。
改成百分比之后,压迫感和当前水位解耦了——谁面对天灾都是"少两成"的体感,平衡问题从根上没了。这思路后来也顺手用在无尽模式的压力曲线上。
🛡 局内构筑为什么做保底?
试炼和无尽局内都有"三选一"构筑,纯随机立刻就崩:手气差的连抽三个防御向,输出起不来,90 秒打不出跃迁,一局稀碎。
最后对前几次三选一做保底——核心输出技能书保证前期出现,让每局都能成型一套 build,随机性全留给后期锦上添花。
肉鸽的乐趣是"随机里长出 build",但成型下限必须由设计兜着,否则玩家走的不是这一局,是这款游戏。
2⃣ 无尽模式
去掉 90 秒,改成波次生存,环境压力随波次持续上升,看你能活多久。配两条规则防它变成"熬时间刷时长":
💀 复活次数有限:基础 3 次,局外符文可加
🏆 排行榜按生存时长结算,逼你在"稳妥活着"和"激进吃资源"之间反复掂量
3⃣ 赛季模式
也是 90 秒一局,但外面套了层赛季系统。拿已完结的第一赛季"雷暴纪元"拆开看,一个赛季到底装了些啥:
⚡ 赛季专属货币"雷电印记"+ 赛季经验,双轨跑
👾 雷电系怪物强化和赛季变体,让老模式长出"这一季特有"的敌人
📈 赛季等级给长期目标:15 级拿赛季背景,30 级拿终极皮肤「雷暴主宰」——而且这皮肤的攻击特效是全模式通用的!赛季奖励溢出到别的模式,是拉人去试新赛季最有效的一手
🏅 专属榜按雷电击杀数和等级排,赛季结束归档
我们自己立了四条铁律,后来证明条条都对:
- 普通模式养本体,赛季模式拿限定——赛季奖励绝不混进通用成长,否则赛季一结束,玩家的动力结构就塌了
- 所有赛季数据带 seasonId 隔离——这是"换赛季不砸存档"的地基
- 旧赛季不能被新赛季覆盖——归档可查,玩家的历史战绩是资产
- 赛季是长期主题,不是活动弹窗——第一版故意不做战令、不做头像框称号这类碎奖励,先把"这一季只能这么玩"的识别度立起来
赛季 PRD 也是跟 AI 磨出来的,但不是丢一句"帮我设计个赛季系统",而是用一轮结构化追问:目标玩家是谁、反复玩的动机是什么、15 到 30 级之间拿什么留人、明确不做哪些东西。"非目标清单"和"目标"一样重要——正是"不做战令、不做碎奖励"这两条,保住了第一版的收敛。
4⃣ 爬塔模式
唯一一个完全推翻主模式操作方式的玩法:拖动瞄准、弹射。
🎯 拖的反向就是飞行方向,拖多长决定用多大力——往下拖,水滴往上飞
⚠ 空中不能二段跳,每次起跳都得重新蓄力
🟦 五类平台:普通(蓝)、弹力(绿,下一跳力度 +40%)、碎裂(踩上 1.2 秒消失)、横移(来回动)、腐蚀(踩上掉血)
🛡 摔落不直接死——低于判定线扣 1 点命(有护盾能挡),传送回本层安全平台;生命归零才真暴毙
双结算是这模式的魂:你随时能主动"平安撤离",带着残响水珠离场;也能继续往上贪——但暴毙坠落深渊,本局奖励清零。
每一层都在问同一句话:见好就收,还是再贪一层? 🤔
爬塔单上排行榜按最高层数排,跟主榜的质量榜、无尽的时长榜、赛季榜并列——一张榜对应一种玩法。
还有俩不起眼但特别影响体验的细节:
楼层提前预生成 7 层,让你抬头永远看得见接下来的路线,而不是边跳边随机
摔落后回溯最近 2 层找安全平台重生,保证复活点一定有落点,不会"复活即再摔"的恶性循环
这种单看都不大的细节,堆起来就是"手感的差别"。
二、技术实现,和一些翻过的车
1⃣ 三层分层:给 AI 画的第一根缰绳
项目第一个月就定死了目录结构,至今没破过例:
scripts/
├── core/ 纯逻辑状态机:不碰引擎、不碰渲染、不碰输入
├── ui/ 只做渲染和交互转发
└── data/ 数值配置表(V3Balance 3300 行)
core/ 里每个文件头都写着"纯状态机,无渲染/输入耦合"。这不是装饰——它是整个 AI 协作的地基。
最直接的红利:47 个测试文件用标准 Lua 解释器直接跑,测逻辑根本不用启动游戏引擎,秒级反馈。
2⃣ 一套 RunRules 框架,带三种局内模式
试炼、无尽、赛季共用同一个局内框架 V3RunRules:
模式就是个枚举值(TRIAL / ENDLESS / SEASON),差异全收进 MODE_CONFIGS
结算管线是显式状态机:HOME → PLAYING → BUILD_CHOICE → ENDING → PREVIEW_READY → REWARD_CHOICE_PENDING → FINALIZED → COMMIT_PENDING → COMMITTED,还显式定义了 RETRYABLE_ERROR 和 ABORT_PENDING 两个异常态
为什么结算要做这么重的状态机?
因为结算牵扯发奖励、写存档、传排行榜三个跨系统动作,任何一步都可能断网、闪退、被打断。显式状态机保证:每笔奖励要么没发、要么走完全流程,不存在"发一半"的中间态;断在半路,下次启动从 checkpoint 续走或重试。这设计后来帮我们扛过了无数次真机上诡异的宕机。
这里有个容易看懵的状态:REWARD_CHOICE_PENDING(奖励待选择)。
结算预览弹出来后,玩家可能正捏着"要不要看广告双倍"的选择,这时结算必须停在半路等玩家,不能自作主张替他领默认奖励。把"等待玩家决策"做成状态机里的正式状态,而不是一个 UI 弹窗标志位——是这趟管线里我最得意的一个决定。弹窗被杀、App 被切走,重启后管线还能从这里精确续走。
局内"三选一"构筑在三种模式间直接复用,一个模式做好,三个模式受益。
3⃣ 爬塔独立状态机:手感全配置化
爬塔差异太大,没硬塞进 RunRules,独立成状态机,但守同样的分层纪律。这里有个对调手感特别管用的做法:所有物理参数进配置表。
local LAUNCH_MIN_SPEED = pdef("launchMinSpeed", 5.0)
local LAUNCH_MAX_SPEED = pdef("launchMaxSpeed", 16.5)
local BOUNCE_BONUS = pdef("bounceBonus", 1.4) -- 弹力平台加成
local CRACK_TIMER = pdef("crackTimer", 1.2) -- 碎裂平台倒计时
发射速度区间、弹力倍率、碎裂计时、摔落判定线偏移、前方预生成层数……全部从 V3Balance 读表,缺省才回退到代码默认值。**改表即生效,调手感不用改代码。**爬塔上线前后调了十几轮手感,每轮就是改个数字。
4⃣ 模式之间怎么互相咬合
四种模式不是四个孤岛:
🧬 局外培养跨模式生效:永久技能和符文是全局的,通用成长四模式都吃得到——你在任意模式投入,都能感觉"变强了"
📊 每模式独立统计 + 四张排行榜:存档里 modeStats 按分桶记录,爬塔另立门户,云端的四张榜各维护一套 key,互不污染
🔢 排行榜数值压缩:主模式水量会大到天文数字,直接传既溢出又没区分度,做法是取对数 ×1000 再传——10 万倍的差距在榜上就是一条平滑的分数差,防溢出也防刷分
📅 赛季中心与每日补给:用 TrustedTime 做每日刷新判定,校验设备时间——改本机时间白嫖每日奖励,行不通
🔄 回归之路:专门给回流玩家的挑战活动链,完成的奖励直接进局外培养,把流失的人拉回任意模式
5⃣ 局外培养:一张带依赖关系的成长树
它不是"用金币买数值"的平面商店,而是一张技能依赖树。每个节点带三个字段:
生效数值(effectPerLevel,每级 +1.8%、+2% 这种百分比)
解锁层级(unlockTierId,比如某技能必须本体长到"水团"才开放)
前置技能(requiredSkillId,必须先点出某个才能开下一个)
三个字段合起来,把局外培养和局内进度绑成一条线:**局内冲到的最高层级,决定局外树能点亮哪块;局外树点的强化,又反过来决定下一局能冲多高。**局内局外互相咬合,这就是肉鸽"死了也不白死"的内核。
而这整张树就是配置表里的一组数据,加节点不用改代码——后来赛季换主题,培养树原样复用。
6⃣ 动态难度 + 长期模拟:不靠手感靠数据
两个 indie 最常忽略、却跟留存最相关的系统:
⚙ 动态难度(DDA 模块):记录玩家最近若干步的行为窗口,在预设安全窗口内做难度微调——压力大一点让强玩家不无聊,松一点让受挫玩家喘口气。
关键词是"安全":DDA 只允许在配置表圈定的区间内调,绝不允许突破上下限。AI 最爱在"智能调节"这种需求上放飞自我,写一套谁也看不懂的自适应逻辑;把它的自由度关进数值区间里,DDA 才是调难度,而不是随机数生成器。
📈 长期数值模拟器:人肉试玩能发现"前 30 分钟不舒服",发现不了"30 小时后崩坏"。
V3LongTermSimulator 用纯逻辑层直接跑虚拟生涯:以小时为单位推进,模拟重生次数、天灾压力、广告观看节奏,跑出几千小时的成长曲线,还能切换广告策略对比差异。层级阈值、天灾间隔、重生加速这些关键数值,全是模拟器先跑通、真机再确认的。没有模拟器做数值,等于闭着眼调菜的咸淡。 👨🍳
7⃣ 存档可靠性:六版迭代出来的教训
存档模块 V3Save 迭代了六个版本,现在做三件事:
💾 双槽备份:同时写 .a 和 .b 两个文件交替落盘,写坏一个还有另一个
📌 checkpoint 检查点:跑局中断、结算中断都有明确恢复点
🔧 启动自愈:V3Startup 启动时校验存档,损坏给明确 blockCode 和恢复路径(比如回退到上一个检查点),而不是闪退或读出一堆脏数据
六版按说是夸张了,但每一版都对应一个真实翻过的车:字段加错、版本迁移丢数据、写入中断半截 JSON……存档是这游戏最不能坏的东西,所以它的测试也写得最狠。
8⃣ 广告:曝光上报和发奖解耦
激励广告模块就一条铁律:进 onClose 回调就无条件上报一次曝光,跟发不发奖无关。发奖看 result.success,曝光看 onClose,两个通道分开;广告消费回调全 pcall 保护,请求带 120 秒超时。
这规矩来自一个实打实的教训:老版本拿"发奖成功"去拦曝光上报,结果广告数据永远比真实少一截,投放决策全被打偏。
9⃣ 一个诚实的教训:1.3 万行的 GameCanvas
不是全是好消息。😅
ui/GameCanvas.lua 现在单文件 13125 行,所有画布渲染、HUD、面板都往里堆。原因很讽刺:core/ 有测试围栏,AI 不敢乱写;ui/ 没围栏,AI 写得又快又高兴,债就这么欠下了。
架构纪律能守住的,只有你设了围栏的地方。
这是这项目给我最深的一课,下面展开。
三、怎么把 AI 收拾服帖
490 次提交背后的工作方式,我总结成四个手段、一个实战、四类高频错误和一个核心认知。
1⃣ 文档先行:先聊清楚,再让动手
任何新玩法,第一步不是让 AI 写码,而是先跟它来一轮头脑风暴:目标是什么、核心循环是什么、边界在哪。聊完落成设计文档(docs/superpowers/specs/ 下存着每一份),文档确认之前,一行实现代码都不许写。
爬塔的规格就是这么来的——最终落地版本的文件头,就是当年文档里七条规则要点的原文。
先写规则的巨大好处:AI 实现时是在"执行一份双方确认过的合同",而不是"自由发挥一个它理解的爬塔游戏"。前者跑偏了能对着文档改,后者跑偏了你压根不知道它理解成了啥。
2⃣ 变更包拆任务:大功能切块,一块一验收
光靠一份文档撑不起大功能。项目用 openspec 变更包:每个功能一个独立目录,里面有提案、任务清单和规格差异。至今攒了 15 个变更包,从"定义 V1 可玩原型"到"赛季中心与每日补给"——这游戏整个玩法演进史,就是这 15 个包。
对 AI 的约束在于:**任务清单是它唯一的施工许可。**做完一项对账一项,不许跳、不许合并、不许"顺手多做了"——AI 特别爱顺手多做,而"顺手",正是项目失控的第一步。
3⃣ 测试先行:AI 最怕的不是写不绿,是改红了
四条里最狠的一条,也依赖第一节说的分层架构。
core/ 纯逻辑 + 标准解释器可跑 → **每个功能先写测试、看着它红,再让 AI 把它写绿。**一个 584 行的跑局集成测试、一个 815 行的赛季系统测试,就是这么一红一绿磨出来的。AI 改坏任何已有行为,测试当场变红,想糊弄都糊弄不过去。
实践下来有个反直觉的观察:**约束越狠,AI 表现越好。**没测试的时候,AI 的代码"看起来能跑",深层 bug 全留给真机;有测试围栏,它会在围栏里反复自我修正,交付质量反而稳得多。
4⃣ 小步提交:490 个存档点
每次提交只做一个主题,490 次 commit 就是 490 个可回滚点。AI 跑偏是常态,重要的是跑偏时能 30 秒退回上个正确状态,而不是在浆糊里考古。
🔥 实战:换赛季,不砸老玩家存档
拿这个真实案例把四个手段串一遍。
第一赛季"雷赛季"要轮换下线、换新赛季,当时最大的风险不是新赛季做不出来,而是轮换动作把老玩家存档弄坏:赛季等级怎么算?上赛季榜的成绩去哪?领到一半的奖励怎么办?
按流程走:
文档先行:先在设计文档定死三条底线——历史赛季数据必须可查、奖励领取必须有凭证、赛季切换必须幂等(重复触发不会二次发奖)
任务切块:拆成赛季归档、凭证流水、切换时序三个变更包,一块一块过
测试先行:先写 815 行的赛季测试——模拟"玩家在旧赛季打到 20 级、领了 3 个奖励,然后跨过切换时刻",断言历史战绩还在、已领的不重发、未领的能补领。先看它红,再让 AI 写绿
小步提交:归档、凭证、切换各自独立提交,任何一块出问题单独回滚
最后落地的方案:旧赛季 ID 归档为"历史赛季",档案里留完整战绩;奖励领取用凭证流水(上限 64 条的 receipt 队列)做凭据,重复领取直接被拦下;切换判定用可信时间做日戳,不信任设备本地时钟。上线后没收到一条跟存档相关的玩家反馈。 🙌
这件事让我彻底想明白:
"驯服 AI"驯的从来不是单次代码质量,而是让整个变更过程可预测、可验证、可回滚。
AI 执行起来又快又准——前提是轨道是你铺的。
⚠ AI 常犯的四个错,和对应的围栏
490 次提交里 AI 犯的错高度重复,摸清规律后,每个错配一道围栏就够了:
❌ 错一:顺手多做。
让它修结算,它"顺手"重构了存档格式;让它加按钮,它"顺手"统一了全项目命名风格。每一处单看都更好,合起来就是一场没人审过的隐形大重构。
→ 围栏:任务清单许可制,做多做了一律不算验收。
❌ 错二:改一处破三处。
改天灾扣血公式,把无尽模式压力曲线带崩了,它还毫无察觉。
→ 围栏:已有测试不许红,旧测试全绿是每次提交的硬门槛,那个 584 行的跑局测试就是干这个的安全网。
❌ 错三:只写幸福路径。
让它做"领奖励",它漂亮地把领取流程写完,但断网呢?重复领呢?领到一半退出呢?——你不主动提,它一个字都不写。
→ 围栏:设计文档先定异常态,结算的 RETRYABLE_ERROR、存档损坏恢复、广告 120 秒超时,全是文档阶段点名的,AI 只是执行。
❌ 错四:口头汇报不可信。
AI 会非常自信地说"已完成并验证通过",直到真机一跑就露馅。
→ 围栏:验收只认两样东西——本地测试全绿 + 推到 Maker 真机亲手玩过。AI 说"已完成",只算开工,不算收工。
这几道围栏有个共同点:它们都不是在批评 AI,而是在承认一件事——AI 没有项目记忆,也没有全局责任。它每次都是第一次看你的项目,围栏,就是替它记住所有教训的办法。
🧠 核心认知:架构,就是那根缰绳
四个手段指向同一件事——AI 的产出质量,取决于你围栏的强度,而不是你 prompt 写得有多好。
这项目里最有说服力的对照组就是 core/ 和 ui/:同一个 AI、同一个开发者,core/ 因为"纯逻辑 + 可测试"的架构,四万行里逻辑层始终干净、可测、敢重构;ui/ 因为没围栏,长成了 1.3 万行的巨物。
不是 AI 在 ui/ 突然变笨了,是那边没有缰绳。
四、写在最后
回头看,这项目验证了一件事:一个人 + AI,确实能做出一个模式完整、运营系统齐全的肉鸽游戏——前提是你把"驯兽"的功夫做在写代码之前:文档先行、任务切块、测试围栏、小步提交。
给同样想用 AI 做游戏的朋友三条建议:
- 🪓 先建围栏,再放 AI 进来。 花一周给核心逻辑搭分层和测试框架,比之后花一个月给 AI 擦屁股便宜得多。
- 📊 数值别靠手感,靠模拟。 天灾扣多少、层级阈值差多少,我们用长期模拟器跑了成千上万局虚拟生涯验证曲线。人肉试玩只能发现"不舒服",发现不了"30 小时后崩坏"。
- 🧱 UI 层要像逻辑层一样早拆分。 别学我,那 1.3 万行的渲染文件,到现在还在慢慢还债。😅
游戏在 **TapTap 搜「重生!我的水滴无限大」**就能玩,四种模式都开放中。💧
重生!我的水滴无限大
重生!我的水滴无限大是一款TapTap制造游戏,TapTap 提供重生!我的水滴无限大最新版官方正版下载,一滴水能有多离谱?火焰想蒸发你,闪电想劈散你,干旱与裂隙还想...
http://taptap.cn/app/903472














