这个系列写到第三篇了。前两篇我分别聊了AI在独立游戏开发里的整体可行性,以及怎么靠AI把最小玩法原型跑通,当时给的结论比较明确:在单个系统、单个页面的开发层面,AI确实能顶得上半个初级程序员;但一旦涉及全局架构,AI的表现就完全是另一回事了。这篇我花点篇幅,把我实际搭建项目框架时踩过的坑、最后定下来的方案,以及整套流程里哪些环节必须人来做主,一次讲清楚。
如果你也在做独立游戏,手里有个项目想做但代码底子不算扎实,这篇内容应该能帮你少走不少弯路。我会把框架设计怎么定、AI对话怎么组织、生成出来的代码怎么审查、以及框架搭完之后怎么验证,尽量以实操记录的方式完整过一遍。
1. 为什么框架搭建是AI辅助开发里最不该偷懒的一环
1.1 框架是什么,以及它在游戏项目里到底解决什么问题
先用一个生活化的类比。装修毛坯房的时候,水电管线怎么走、承重墙在哪里、各个房间的功能分区是什么,这些事必须在贴瓷砖之前定好。游戏框架就是毛坯房里的管线布局:它不决定某个房间长什么样,但决定了整个房子能不能稳定住人、后续改造会不会砸到承重墙。
放到游戏项目里,框架主要解决三件事。第一件事是启动流程:游戏从打开到进入主界面,中间要加载哪些配置、初始化哪些系统,顺序不能乱。第二件事是资源管理:贴图、音频、字体这些资源什么时候加载、什么时候缓存、什么时候释放,失控就会内存膨胀。第三件事是系统之间的通信方式:背包系统要把“获得一件道具”的消息告诉UI层,UI层要刷新界面,如果没有一个统一的通信规矩,代码会迅速变成一团乱麻。
在我这个项目里,前两篇结束时已经有了单点能力验证,比如角色移动、物品拾取、道具合成这些功能都能用AI写出来并跑通。但问题是,这些功能是各写各的,没有统一的底座。UI的窗口是自己管理的,资源加载是随手调的,全局状态也散落得到处都是。这时候要加新功能,每加一个都是在给项目埋雷。所以我停了手上的功能开发,先把框架补上。
1.2 AI能生成单个模块,但很难直接生成一套好框架
这一节的结论来自我实际跑了二三十轮对话之后的观察。让AI单独生成一个资源管理器,它能写出来,功能看着也完整;让AI单独生成一个场景切换器,同样能写出来。但如果你跳过设计,直接对AI说“帮我把整个项目的框架搭出来”,结果大概率会让你头疼。
一个典型现象是:AI会非常热衷于创建抽象层和中间层。它可能给你生成出“BaseManager”“AbstractProvider”“IFactory”一堆层层叠叠的类,每个都有模有样,但实际项目中根本不需要这么多间接层。另一个典型现象是:AI缺乏全局记忆。它在这个会话里生成了一个接口,下个会话里就把接口签名忘得干干净净,重新生成一个同名但参数不同的版本。这两个现象叠加起来,就是“看起来搭好了,一编译全是接口对不上”。
所以我的判断很明确:框架搭建这件事,AI可以大量参与执行,但顶层设计必须人来定。不是AI做不到,而是现在的AI对话模型本质上是“逐字预测”,它更擅长局部正确,不具备持续稳定把控全局的能力。框架恰恰是最吃全局一致性的工作。
1.3 我在项目里最终定下来的分层原则
这个生存建造类小游戏的Demo,我最后把框架分成三层加一块配置。最底层叫基础设施层,负责生命周期、资源加载、场景切换、事件总线这类跟具体玩法无关的能力。中间层叫系统层,负责跟玩法相关的模块,比如背包、建造、生产、时间系统。最上层叫组件层,是挂在游戏对象上的小零件,负责把系统能力暴露给具体实体。
依赖规则只有一条:上层可以依赖下层,下层绝不能反向依赖上层。组件层可以调用系统层,系统层可以调用基础设施层,但基础设施层绝不应该知道背包里装了什么物品。这条规则写进AI对话的固定上下文里之后,生成出来的代码质量有了非常明显的提升。原因也好理解:AI在没有边界约束的时候会自由发挥,有了清晰约束它反而容易在边界内生成更贴近需求的代码。
2. 动手生成代码之前,先把这四个决策定下来
2.1 决策一:面向数据而不是面向对象
游戏项目里有一个特别容易让代码失控的点,就是数值和逻辑混在一起。比如道具的重量、合成配方、建造消耗,直接在代码里写成变量,看起来方便,改起来要命。AI做代码生成时,它只会按照你的当前需求写一个“看起来合理”的实现,不会替你考虑以后改数值方不方便。
我定下的方案是:所有跟玩法相关的数值、配方、道具定义全部放到配置文件里,代码只负责读取和转发。这个方案对AI辅助开发还有一个额外好处:配置文件是纯数据,结构简单,AI生成单个配置文件的容错率高得多;就算它把某个数值写错了,改起来也只是改数据,不会碰逻辑。
举个例子,木材和石头的堆叠上限,在配置里就是两个字段,改100还是200只是一行数据的事。但如果没有这个决策,AI大概率会把堆叠上限直接写成代码里的一个常量,后面要调就得改代码、跑编译、重新提审,全是成本。
2.2 决策二:模块划分按职责切,不按功能切
模块划分是框架设计里最消耗精力的一件事。我当时的折线标准只有一个:一个模块只负责一个职责方向。背包系统管物品的增删查,建造系统管摆放校验和消耗扣除,生产系统管配方和产出,这三个模块就像三个独立工位,各自只处理自己桌上的事。
为什么必须按职责切而不是按功能切?原因很简单。如果按功能切,背包里的“获得物品”逻辑就可能会既管物品数据,又管UI刷新,还管任务进度。AI生成的时候,它会倾向于把跟“获得物品”沾边的东西全塞进一个函数里。这个函数越写越长,最后变成一个没人敢动的巨大函数。按职责切模块之后,物品数据归背包,UI刷新归UI层,任务进度归任务系统,各干各的,谁的状态都不需要关心别人怎么变。
2.3 决策三:系统之间通信走事件总线,禁止直接互相调用
系统之间免不了要通信。背包加了一件道具,任务系统要知道进度变了;时间系统走过了一天,生产系统要结算一次产出。如果这些通信都做成函数调用,系统之间的依赖会越来越深,最后改一个模块拖累一片。
我的做法是引入一个轻量的事件总线。事件总线说白了一个发布订阅机制:模块A发一个事件,不关心谁在听;模块B监听事件,不关心是谁发的。这样两个模块之间的耦合就只剩一个事件名。AI生成代码时,事件名是字符串,字符串的一致性检查比函数签名简单得多,出错概率也低。
需要提醒的是,事件总线这个方案要控制使用范围。别所有通信都走事件,那会让代码变得难以追踪;也别完全不用,那会让模块耦合越来越重。我的平衡点是:跨模块通信走事件,模块内部方法直接调用,两条规则都写进了后续每个AI对话上下文的固定背景块里。
2.4 决策四:目录结构和命名规范必须强约束
这一条看着不起眼,实际体验下来价值非常大。AI没有“项目全局目录”的概念,它默认会把自己生成的东西放到它认为合理的地方。这个“它认为合理”跟你的项目结构很可能对不上,结果就是文件到处乱飞。
所以我在开工前先把目录结构写死,之后每轮对话开始前都把这份结构复制给AI。目录分成资源、代码、配置、工具四大块,代码里再细分基础设施层、系统层、组件层。命名规范也很简单:模块名文件加模块名前缀,事件名以EVENT_开头,配置键用下划线连接。这些约束本身不复杂,但有了它们,AI生成的代码放到正确位置的命中率从原来的四成左右提到了八成以上。
3. 实操全记录:让AI从零把框架撑起来
3.1 搭建一套适合框架生成的AI对话工作流
先说整体思路。框架搭建不能像之前写单个功能那样,打开对话窗口就开始聊。我需要让AI在每次对话中都记得项目背景、技术约束和当前进度,不然它只能基于上下文窗口里的片段猜。我用了一个很笨但非常有效的方法:每次开始新对话前,先粘贴一段固定的“项目背景描述块”,内容不超过几百字,但包含了关键信息。
背景块里一般写这几类信息:项目类型和开发环境、目录结构、依赖分层规则、命名规范、当前本次任务的具体目标、出口约束。这个背景块就是每次会话的“开机配置”。开头第一次写的时候花了点时间,之后每次只需要微调任务描述那一栏,其他内容一辈子不用改。效果很明显:新会话里的AI能说出和上一个会话一致的设计语言,模块间的接口对不上的问题少了很多。
3.2 第一步:让AI生成项目骨架与初始化配置
框架搭建的实操第一步,是让AI生成项目骨架。这一轮对话的目标很简单:初始化目录结构、生成入口文件、生成基础配置载入逻辑。我不让它写任何业务流程,只要求框架能跑起来、空窗口能打开就行。
给AI的提示词大致是这个风格:我现在要初始化一个生存建造类2D游戏的项目骨架,你只需要创建目录结构、入口脚本、配置载入脚本和日志工具,不要实现任何玩法功能;每个新文件给出它的职责和依赖方向;只输出启动一个空窗口所必需的代码。
这一轮AI完成得比较快,因为它生成的代码量不大,目录结构又是提前给好的。生成完之后,我把文件合入项目,启动编译,验证空窗口能正常打开。这个“验证点”非常重要。框架搭建最忌讳一次合并一大堆代码然后发现根本跑不起来,宁愿每轮前进一小步,每步都能启动、能编译。
3.3 第二步:核心基础设施模块逐个落地
骨架能跑起来之后,开始逐个落地基础设施层模块。我按依赖顺序排了一下,生命周期管理在最前面,因为它控制所有系统什么时候初始化。接下来是场景管理,它负责场景的注册、切换、卸载。然后是资源管理,处理素材的加载和释放。最后是UI基础层,负责界面栈和界面层级。
这里要强调一点:这些模块不是让AI一口气生成的,而是一个会话只做一个模块。做场景管理那一轮,对话就只围绕场景管理;做资源管理那一轮,对话就只围绕资源管理。一个会话做太多事情,AI的上下文很快就被占满,后面生成的内容质量明显下降。
每个模块生成之后,我会做三件事。第一件,通读接口签名,对着我们提前定好的模块边界核对。第二件,把它接入生命周期,确认初始化时能加载。第三件,用一个最简单的测试场景验证基础能力,比如场景管理器能不能成功切到第二个空场景。全部验证通过,这个模块就算落地,然后开始下一个。
3.4 第三步:让AI对自己写的代码做两轮“挑毛病式复盘”
代码合入后没有报错,不等于代码质量过关。框架代码最怕的是“能用但有隐患”,比如资源引用了没释放、事件监听了没移除。这类问题在功能开发期不明显,项目跑大了才爆雷。我试过一个很有效的方法:让AI当代码审查员,专门挑自己刚写的代码的毛病。
提示词可以这样组织:请你以资深技术专家的身份审查刚才生成的文件,重点找三类问题:资源引用释放缺口、事件监听生命周期不匹配、接口之间有隐藏的循环依赖;不要修改代码,只输出问题清单和修改建议。AI输出问题清单之后,我再针对清单逐条确认,有时它挑出的问题确实存在,有时它在自己吓自己,但总归能逼着我对这个模块重新梳理一遍,查漏补缺的效果很好。
3.5 第四步:人工合并、编译通过、跑通最小闭环
最后一轮是整合。基础设施层四个模块各自独立能跑,但合在一起还要经过一轮总测试。我先检查每个模块的接入点是否符合当初的分层约定,再把它们全部接入生命周期,然后启动项目,跑一遍最小闭环:从标题界面进入游戏,加载一个测试场景,移动角色几秒,再退出场景回到标题界面。
这个最小闭环的价值在于,它把框架的每一根管线都用上了:生命周期管了系统启动和关闭、场景管理管了切换、资源管理管了场景素材的载入和释放、UI基础层管了两个界面之间的跳转。如果这个闭环能稳定跑下来,框架的地基就算打住了。我在实测里遇到过一个小问题,是场景切换时上一个场景的资源没有及时释放,排查后发现是资源管理器的引用计数逻辑漏了一种情况,修掉之后整体就稳了。
4. 框架搭建阶段实测踩坑记录与排查手册
4.1 问题一:AI生成的代码结构性“过度设计”
第一次让AI搭框架时,它交上来的代码里充斥着层层抽象。某个跟“可保存的物品数据”相关的接口,它给抽象出了一个IStorable接口,又写了一个AbstractStorable基类,再写了一个ConcreteStorable实现类,最后还留了一个注释说“未来如果加入存档系统,可以在这里扩展”。项目里根本没有任何存档需求,这套抽象纯属自作主张。
原因在于,AI训练语料里的技术博客和代码示例大量充斥着“为了扩展而扩展”的写法,它学到了形式,没学到背后的取舍。解决办法是提示词里明确加一条约束:只实现当前需求,不为不存在的情况预留扩展;禁止创建仅有一个实现类的抽象基类和接口。加上这条约束之后,这类问题明显减少。
4.2 问题二:上下文丢失导致模块接口对不上
这个坑最隐蔽。上午让AI生成了事件总线接口,下午新开一个会话让它写生产系统,它在代码里直接调用了事件总线里的一个事件名,但事件名大小写或者参数跟上午定义的版本不一致。编译时因为事件名就是字符串,编译器根本不会报错,直到运行时这个事件没人响应,才会暴露出来。
要根治这个问题,只靠AI自己不行。我后来维护了一份“系统接口备忘单”,把当前所有模块的公共接口、事件名、配置键都记录下来,每完成一个模块就更新一次。之后每个新会话开始,除了项目背景块,再把这个备忘单一起复制进去。AI基于这份信息生成的代码,接口一致性就得到了保证。这不算什么高端技巧,但确实是把AI聊天记忆不牢的问题从流程层面解决了。
4.3 问题三:AI对引擎版本和API的幻觉
AI对特定引擎的具体API经常产生记忆幻觉。它把不存在的静态方法写出来,或者把一个函数的参数数量记错,编译没过才发现。这个问题在框架搭建期尤其致命,因为框架代码要牵动很多模块,API错了改起来牵一发动全身。
我的处理办法是:在每轮涉及引擎调用的对话中,把对应API的官方文档片段直接贴在提示词里。比如场景管理需要用到引擎的场景加载函数,就把该函数的标准用法、参数说明和返回值示例贴进去,然后让AI忽略自己记忆里关于这个API的内容,完全基于我提供的文档信息来写代码。实测下来,编译报错的数量断崖式下降。AI并不蠢,它只是容易把训练时的知识张冠李戴,给它准确资料它就能正常发挥。
4.4 问题四:依赖注入与全局状态的纠缠
有一段时间我的代码里出现了一个会被到处引用的全局状态对象,几乎所有模块都能读写它。表面上很方便,实际上一旦出问题,根本查不到是谁在什么时候把某个值改掉的。这个状态对象倒不是某一次AI会话生成出来的,而是几次会话中的AI都不约而同地选择了“全局对象”这种最省事的写法。
这个问题的根源在于AI生成代码时永远倾向于走最短路径,而全局对象是它眼里的最短路径。我后面在项目背景约束里补了一条:所有全局数据必须存放于数据配置模块,读取走统一入口,写入必须经过对应系统的方法,禁止跨系统直接修改全局数据。这条规矩立起来之后,代码的可追踪性高了不少,排查问题时能明显定位到具体模块。
4.5 常见问题速查表
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 生成了一堆抽象类但没人调用 | 提示词缺少“按需最简”约束 | 加约束:只实现当前需求,禁止无使用方的抽象层 |
| 新旧会话里同一个接口签名不一致 | 上下文丢失 | 维护系统接口备忘单,每次会话复制给AI |
| 编译报错,引擎函数不存在 | AI对API的记忆过时或编造 | 在提示词中粘贴官方API文档片段 |
| 多个模块能改同一个全局数据,出问题查不到来源 | 缺少数据写入规则 | 建立系统间数据读写规范,禁止跨模块改全局状态 |
| 场景切换后内存不断增加 | 资源管理器释放逻辑有缺口 | 通过引用计数排查,按场景切换周期做资源释放验证 |
5. 框架验收清单与后续扩展建议
框架搭建完成后,我给自己列了一份验收清单。这份清单不一定适合所有项目,但对于独立游戏这种规模来说,至少能防止框架搭完却立不住。
第一项是依赖方向检查。把代码目录里所有模块间的引用关系梳理一遍,确认没有出现底层反向依赖上层的情况。第二项是核心闭环验证。跑通标题界面到游戏场景再到退出的完整流程,过程中不能有报错和卡死。第三项是资源释放验证。连续切换场景二十次左右,观察内存占用是否稳定,不持续上涨。第四项是配置可调验证。随便改一个配置里的数值,比如把木材堆叠上限从五十改成三十,重启后确认生效。第五项是错误定位体验。故意在某个模块的初始化流程里制造一个异常,确认异常信息能定位到具体文件和具体环节。
这些验收项不追求完美,追求的是“框架能稳定支撑后续开发”。如果有一项没过,就说明框架里还有边界模糊或者生命周期没理顺的地方,宁可现在回头改,也别留到内容铺开之后再返工。
验收通过之后,接下来的开发节奏就能加快很多。新玩法模块只要按照既定分层做出来,接到生命周期和事件总线上,再补上配置数据,就能顺利插进项目里。这个阶段能明显感受到AI辅助开发的优势:模块边界清晰之后,AI生成的代码命中率大幅提升,因为它不需要反复猜测该把代码放在哪里,也不需要自己去定义一个通信机制。
最后再分享一点个人经验。框架这个东西,在很多独立游戏项目里是最容易被跳过的部分,因为“能跑就行”是很多人的第一反应。但AI辅助开发会让这件事反转:如果框架是糊的,AI每改一个需求就会在某个角落给你埋一个不兼容,后续维护成本会成倍放大;而框架边界清楚之后,AI生成的代码反而质量更高、返工更少。我的体会是,框架不是给AI看的,是给你自己看的——你把边界画明白,AI才可能帮你在边界内干好活。