0%

零帧起手——第一次做游戏的踩坑笔记


这是一篇写给自己的复盘。我是个写了多年 Python / JS 的程序员,业余时间用 Godot 做一款像素风的「连线消除 + Roguelike」单机游戏(暂名《勇闯昆图库塔》)。从一张白纸到一个能让真人坐下来玩的版本,踩了不少坑,也总结出一些”早知道就好了”的经验。趁记忆还热,记下来温故知新。

一、最反直觉的一课:别从写代码开始

程序员做游戏,第一反应往往是”先搭个棋盘渲染出来”。我也是。但回头看,项目真正的起点是做减法——在写第一行代码之前,把一堆开放性的选择先锁死:

  • 平台:手机还是 PC?我选了 Steam 单机优先。这个决定直接影响分辨率、输入方式、付费模型,越早定越省。
  • 美术方向:像素 / 矢量 / 3D?我选像素——不是因为好看,是因为它是我这种没有美术功底的人唯一能用 AI 辅助批量产出的风格
  • 核心玩法循环:一局游戏 30 秒里玩家在干什么?这个循环必须能用一句话说清。
  • 世界观 / 名字 / 调性:哪怕是占位,也要有,否则后面所有文案、UI 文字都没法写。

我把这些决策单独列成一张表,每一项都标注”已锁定”,然后约束自己后面不再反复推翻。这一步看起来很”虚”,但它决定了后面三个月不会因为”要不要改成卡牌玩法”这种问题反复推倒重来。

教训一:**游戏开发 90% 的浪费来自方向反复横跳,而不是代码写得不够快。**先花两周想清楚”做什么 / 不做什么”,比急着写引擎代码划算得多。

二、原创的边界:借鉴”设计模式”,不抄”具体内容”

我这款游戏的玩法骨架,借鉴了同品类经典游戏里被验证过的设计模式,比如:

  • 多通道独立随机数:装备掉落、技能抽取、棋盘生成各用一条独立的 RNG,互不污染,这样存档/复盘/调试都可控。
  • 双轨升级:经验值练角色属性,溢出资源换装备词缀,两条线各自三选一。
  • 资源的双重用途:同一种格子,先用来修护甲,溢出后转成升级点——一个资源两个出口,决策密度立刻上来了。
  • 对称的优点-缺点系统:每个增益配一个代价,自然形成平衡。

但我给自己立了一条红线,时常自我审查:

“如果玩家一眼能说出’这就是某游戏的 X’,太具体,不能用。
如果只能说’这有点像某类游戏的 Y 设计’,OK,这是模式层面的借鉴。”

名字、文案、美术、数值、世界观——全部重新设计。 玩法模式是行业公共财富,可以学;但具体的可识别内容是别人的劳动成果,必须绕开。这条线对独立开发者尤其重要,宁可保守。

三、用”里程碑”代替”阶段”,给自己定一条防烂尾铁律

独立游戏最大的敌人是烂尾。我把开发拆成一串可玩的里程碑(M0 到 M6),而不是抽象的”开发阶段”:

里程碑 交付物
M0 工程脚手架(多语言 / RNG / 像素配置跑通)
M1 核心循环(棋盘 / 连线 / 重力 / 死亡重开)
M2 真实战斗匹配 + 状态效果架构 + 动画
M3 成长系统(属性 / 双轨升级 / 装备 / 镶嵌)
M4 内容铺量(职业 / 技能 / 敌人 / Boss)
M5 美术 + 音效 + 本地化(占位换成品)
M6 教学 + 打包发布

关键不在于这张表本身,而在于配套的一条铁律:

防烂尾铁律:每个里程碑结束,游戏都必须能完整跑通一局。

也就是说,永远不存在”写了一半、跑不起来”的中间态。哪怕一个系统只做了占位实现,它也得能跑。这条规矩逼着我优先保证”可玩”,把”完美”往后放——美术用纯色块占位,文案先硬编码占位(但走多语言接口),机制没定型前绝不批量产美术资源。

四、给游戏写一个”机器人”:自动化测试不只是单元测试

这是整个项目里我最得意的一招,也是程序员背景带来的最大红利。

游戏逻辑很难测——你不可能每改一个数值就手动玩 50 局。于是我做了两层自动化:

第一层:无头自检(selftest)。 引擎用 --headless 跑一遍所有核心逻辑断言,覆盖匹配规则、伤害结算、状态效果、技能派发……目前积累到 60 条。每改一处逻辑就跑一遍,几秒钟出结果。每修一个 bug 就加一条断言,回归测试自然就长出来了——这套测试帮我抓出过好几个真 bug。

第二层:自动试玩机器人(bot)。 我写了一个贪心策略的 AI,让它自己玩游戏:血少了去连药水、甲薄了去连盾、否则打架、能升级就升级。然后批量跑:

1
godot --headless --path game -- --simulate class=all runs=50 seed=1

输出每个职业的:平均通关楼层、各 Boss 到达率、通关率、死亡原因分布。数值平衡从”拍脑袋”变成了”数据驱动”——我能看到”6 层左右大量玩家被物理伤害磨死”,于是定位到”玩家防御成长斜率 < 敌人数量成长斜率”,精准下刀,而不是瞎调。

这套东西把调参变成了一个循环:跑模拟 → 看数据 → 改一个旋钮 → 重跑对比 → 迭代。

教训二:**能自动化验证的东西,绝不靠手动玩。**给游戏写一个会自己玩的机器人,是把”手感玄学”逼成”工程问题”的最好办法。

五、但要清醒:机器人永远比真人弱

上面这套很爽,但它有个致命的认知陷阱,我栽过:bot 的数据是有系统性偏差的。

我的贪心 bot 不会”留着大招打 Boss”,不会打复杂连招,选路也很笨。所以:

  • 那些靠连招爆发的职业(比如我的刺客),bot 打出来的通关率只有 15%,但真人能轻松打到更高——因为 bot 根本用不出它的核心玩法。
  • 反过来,bot 的数据能可靠反映相对信号(哪个职业偏强、哪一层是卡点、哪种死因最多),但绝对难度永远偏悲观

所以我最终的结论是:bot 负责”相对平衡”和”防崩盘”,绝对难度和手感必须真人实玩校准。 这恰恰是 AI 辅助开发的盲区——逻辑可以验证,但”这一下打出去爽不爽”,只有人坐下来玩才知道。

教训三:**自动化能告诉你”哪里不对”,但告诉不了你”好不好玩”。**别让漂亮的通关率曲线骗了你。

六、数值平衡是个无底洞,所以要”旋钮化”

我一度陷在数值地狱里:改了 A 崩了 B,修了 B 又崩了 C。后来想明白一件事——不要把数值散落在代码各处,要把它们提炼成一组命名清晰的”旋钮”

1
2
3
4
const SPECIAL_HP_MULT := 2.2   # 精英怪血量倍率
const BOSS_ATK_MULT := 3.3 # Boss 攻击倍率
const SPECIAL_PROMOTE_TURNS := 8 # 几回合提升一只精英
const ENEMY_ATK_DIV := Vector2(65, 55) # 敌人攻击成长除数(越小越难)

调难度的时候,我面对的是”几个有意义的旋钮”,而不是”满屏的魔法数字”。每个旋钮我都在文档里记下它的作用和方向。这样哪怕几周后回来,也知道”想让前期软一点该拧哪个”。

还有一个血泪教训:警惕经济系统里的”印钞机”。 我有个技能能把药水炼成升级点,结果玩家发现可以反复刷药水farm,武器直接练到爆表,整个曲线全废。任何”资源 A 换资源 B”的设计,都要算一下它的循环上限,否则就是无限套利。

七、和 AI 结对开发:分工是关键

这个项目我是和 Claude(Claude Code)结对做的,磨合下来形成了一套稳定分工:

  • AI 负责:写逻辑、写自检断言、跑模拟、做数据分析、按我的意图批量铺内容(职业/技能/敌人)、写文档。它在”把明确的规则翻译成正确的代码并自我验证”这件事上极强。
  • 我负责:定方向、做手感判断、拍板取舍(”刺客就是要难,保留难度”)、玩真人实测、把控原创边界和法律红线。

最舒服的节奏是:我描述一个机制 → AI 实现 + 加自检 + 跑模拟给数据 → 我看数据和实玩反馈 → 给下一步指令。AI 把我从”手写样板代码”里解放出来,让我能把精力放在只有人能做的判断上。

教训四:**AI 不是替你做决定,是替你把决定快速、正确地落地。**方向、品味、取舍仍然是你的活。

八、那些”早点做就好了”的工程小事

最后几条零碎但真实的经验:

  1. 尽早做版本系统和一键构建。 我拖到比较后期才加版本号 + build.sh 一键导出,之前每次给人试玩都手忙脚乱。一个脚本搞定”从版本号命名 → 导出 → 签名”,省心太多。
  2. 所有玩家可见文本,第一天就走本地化接口。 哪怕你现在只做中文,也别硬编码字符串。后期补英文时,硬编码的文本会让你想哭。
  3. 占位优先,美术最后。 纯色块能玩通的机制,才值得花钱画美术。机制没定型就出美术资源,等于提前烧钱。
  4. 把”为什么这么做”写进文档/记忆。 几周后的你,会忘记今天为什么把某个数值定成这个值。记下决策的理由,比记结果更重要。

写在最后

从 0 到一个能让真人坐下来玩的版本,最大的收获不是学会了 Godot,而是明白了:做游戏是一个”在不确定里持续做减法和判断”的过程,而不是一个”把需求翻译成代码”的过程。

程序员的工程能力(自动化测试、数据驱动、模块化、版本管理)是巨大的优势;但游戏最终好不好玩,靠的是那个会坐下来一局一局玩、然后皱眉说”这里不对劲”的人。

下一步是美术、音效和本地化,把占位换成成品。等做到能发布的那天,再来写续集。

共勉:**先让它能跑,再让它好玩,最后让它好看。**顺序别反。