写在前面
本次分享主要针对使用Agent进行Unity + C#的工作流分享,以前段时间的BooomJam为参考,介绍本人使用AI辅助游戏开发的工作流程和思路,最后总结一些心得体会。这个工作流理论上也适用于任何用AI开发点什么东西的流程

AI工具选择
早期的AI辅助开发一般是通过网页的Chat功能,使用者通过复制已有代码、写需求,或直接描述需求,然后根据AI的回复复制粘贴代码、或针对其建议手动对工程进行修改。这整个过程AI和工程之间是没有关联的,此时人才是作为AI和工程桥梁。 为了提高效率,我们就需要让AI和项目工程之间进行连接,针对本项目大概需要这些东西
- Agent:可以直接读工程、执行命令、改代码、跑流程的执行者
- Skills:一套固定工作流模板
- MCP:Agent 和外部工具/环境之间的连接层。
- LLM:底层语言模型本体,负责理解、推理和生成。同样的 Agent/Skill,不同模型,速度、稳定性、细节质量会不一样。
BooomJam 里高频用到的 Skill:
- /grill-me(核心) 用来把模糊需求问清楚。它会先读代码,再一题一题追问,最后收敛成可执行的决策。
- /xlsx 用来改表结构、补字段、批量填内容,尤其适合重复复制粘贴性的重复性工作。
- /unity-skills 主要处理 Unity 场景 / 预制体 / 组件绑定"这类需要在编辑器中操作的内容,同时还结合/unity-mcp使用
这里本人用到的Agent主要是Cursor和Claude Code,模型使用的是Kimi2.6,对于一些复杂的任务,则会使用Cursor中的高级请求。请各位根据经济情况和项目规模酌情选择。
原型开发
前段时间的BooomJam中,与团队成员确定了基础的开发方向后,我的早期开发工作就是尽可能快速的堆出原型。在确保原型一定会被放弃的原则下,快是当前开发的准则。 所以此时,完全可以站在一个完全不懂编程的新手视角,尽情的使用大白话和AI沟通,让他来逐步实现你想要的效果
以下效果就是在使用unity-mcp + Claude Code + Kimi 2.6来实现的,基本实现了原型所需要的交互和表现,甚至UI也是AI自己实现了。由于Kimi2.6具有识图功能,所以在运行时AI甚至还会自己截图分析运行结果

提供清晰的架构和流程说明
早期通过AI进行游戏开发的时候,我当时的观点是,只要沟通和需求明确,就能产出足够好的结果。事实也证明,确实能产生预想的结果。但这个整个过程和结构没有被严谨定义,工程的扩展性和可维护性是很差的,跟前写完就马上抛弃的原型开发方案其实差别并不大。
AI Coding时代,对宏观的架构把控会比熟练实际的API和语法更重要,如果目标是开发一个中长期持续扩充需求的项目,需要开发者有一定的架构系统的能力,需要对游戏整体进行把控。这个时候就不能继续站在一个完全不懂编程的新手的视角来进行开发了(至少在AI进化到能完全掌控项目之前不能)。此时就需要人类拥有足够的抽象能力和架构能力,至少需要做到以下几点
- 模块化
- 接口与契约优先
- 数据流和状态管理
- 可扩展性设计
- 抽象与模式复用
本项目使用了QFramework,所以上述的几条架构原则在QFramework中是很容易实现的,以下内容摘自QFramework的Github主页
QFramework系统设计架构分为四层及其规则:
- 表现层:ViewController层。IController接口,负责接收输入和状态变化时的表现,一般情况下,MonoBehaviour 均为表现层
- 可以获取System
- 可以获取Model
- 可以发送Command
- 可以监听Event
- 系统层:System层。ISystem接口,帮助IController承担一部分逻辑,在多个表现层共享的逻辑,比如计时系统、商城系统、成就系统等
- 可以获取System
- 可以获取Model
- 可以监听Event
- 可以发送Event
- 数据层:Model层。IModel接口,负责数据的定义、数据的增删查改方法的提供
- 可以获取Utility
- 可以发送Event
- 工具层:Utility层。IUtility接口,负责提供基础设施,比如存储方法、序列化方法、网络连接方法、蓝牙方法、SDK、框架继承等。啥都干不了,可以集成第三方库,或者封装API
- 除了四个层级,还有一个核心概念——Command
- 可以获取System
- 可以获取Model
- 可以发送Event
- 可以发送Command
- 层级规则:
- IController 更改 ISystem、IModel 的状态必须用Command
- ISystem、IModel状态发生变更后通知IController必须用事件或BindableProperty
- IController可以获取ISystem、IModel对象来进行数据查询
- ICommand不能有状态
- 上层可以直接获取下层,下层不能获取上层对象
- 下层向上层通信用事件
- 上层向下层通信用方法调用(只是做查询,状态变更用Command),IController的交互逻辑为特别情况,只能用Command
基本的架构设计哲学是: 向下调用原则:
- 上层模块可以调用同级或下层模块
- 禁止下层模块反向调用上层
学过计算机网络的同学应该知道,网络的架构模型也是这样一种设计哲学。
以下是项目CLAUDE.md中部分内容,用于约束AI,对其提出的架构需求和流程管理需求
## 代码架构
### QFramework — 项目核心架构
所有玩法代码应基于 QFramework 的 MVC 风格分层来写,**不要直接在 MonoBehaviour 里塞业务逻辑**。核心定义集中在单文件 `Assets/QFramework/Framework/Scripts/QFramework.cs`(约 950 行)。
分层与职责(参考 `IArchitecture` 接口):
- **Architecture**:`Architecture<T>` 单例容器,负责注册并装配 Model / System / Utility,玩法入口需新建一个继承 `Architecture<MyApp>` 的子类,在 `Init()` 内 `RegisterModel/RegisterSystem/RegisterUtility`
- **Model(IModel/AbstractModel)**:数据状态(存档、配置、运行时数值),持有 `BindableProperty<T>` 暴露给 UI/系统订阅
- **System(ISystem/AbstractSystem)**:业务逻辑,跨 Model 协调,处理事件
- **Command(ICommand/AbstractCommand)**:写操作单元(修改 Model、触发副作用),通过 `this.SendCommand(cmd)` 触发
- **Query(IQuery<T>)**:只读查询单元,通过 `this.SendQuery(query)` 拿结果
- **Controller(IController)**:MonoBehaviour 通常实现该接口,作为视图与架构的桥梁,通过 `this.GetModel<T>() / SendCommand / RegisterEvent` 与底层交互
- **Utility(IUtility)**:第三方/平台 SDK 封装、纯函数库
事件与绑定:
- `this.SendEvent<TEvent>()` + `this.RegisterEvent<TEvent>(handler)` 实现解耦通信,注册返回 `IUnRegister`,常配合 `UnRegisterTrigger` MonoBehaviour 自动反注册
- `BindableProperty<T>` 用于 Model 字段双向绑定到 UI
### 已实现的分层目录(`Assets/_ProjectAssets/Scripts/`)
- **`Core/Architecture/GameArchitecture.cs`**:装配所有 Model / System / Utility
- **`Core/Model/`**:`IGameStateModel`(回合、计时器、发展值等)、`IGridStateModel`(网格占用、解锁区域)、`IWindowRegistryModel`(窗口注册表,替代 `FindObjectsOfType`)
- **`Core/System/`**:`ITurnSystem`(回合循环与结算)、`IProductionSystem`(建筑生产)、`IWindowSpawnSystem`(开局生成)、`IGridSystem`(坐标转换与网格线)、`ICraftSystem`(合成配方)
- **`Core/Command/`**:`MoveWindowCommand`、`DeleteWindowCommand`、`ExpandGridCommand`、`CompleteSettlementCommand` 等
- **`Core/Query/`**:`GetWindowAtQuery`、`CanPlaceWindowQuery`
- **`Core/Event/`**:`RoundStartedEvent`、`RoundEndedEvent`、`ResourceProducedEvent`、`GridExpandedEvent` 等
- **`Core/Utility/`**:`IGridConfigUtility`(Luban 表封装)、`IWeightedRandomUtility`、`IGridWindowFactory`
- **`Core/Controller/`**:`GameEntryController`(入口初始化)、`GameplayEntryController`(游戏场景启动)、`GridWindowController`(窗口拖拽)、`TurnUIController` / `SettlementUIController`(UI 绑定)、`InputController`(全局输入)、`CameraController`(相机跟随)
- **`View/`**:纯视图 MonoBehaviour — `BaseGridWindow`(基类,含 SpriteRenderer + BoxCollider2D + TextMeshPro 标签)、`WorldWindow`、`TerrainWindow`、`BuildingWindow`、`ResourceWindow`、`LaborWindow`
### QFUI 面板与 UICodeGenerator(Bind 工作流)
- UI 引用**只通过预制体上的 `Bind` 组件**登记,由 **UICodeGenerator**(`Assets/@UI Kit - Create UICode` / Alt+C)生成 `*.Designer.cs` 与 `UIElement` 子类
- **禁止手改** `*.Designer.cs`;若编译报 `CS0103` 缺少 `Btn_xxx` 等字段,应检查预制体 Bind(`MarkType`、节点名、`CustomComponentName`、是否重复 Bind),修复后重新生成代码
- 槽位根节点(如 `Btn_Slot1`)使用 **Element**(`MarkType = Element`);子控件(继续/新游戏/文案)使用 **Default**(`MarkType = DefaultUnityElement`),且 **GameObject 名与字段名一致**
- 业务逻辑只写在 `UIStoragePanel.cs`(非 Designer partial),通过 `Btn_Slot1.Btn_Slot1_Continue`、`Panel_OverwriteConfirm.Btn_OverwriteConfirm` 等访问;槽位卡片按钮用 `Btn_Slot1.GetComponent<Button>()`
- 本项目菜单:**BooomJam → QFUI → UIStoragePanel 修复 Bind 并生成代码**(`UIStoragePanelBindCodegenEditor.cs`):补全缺失 Bind、删除空 Bind、调用 `UICodeGenerator`
### View 层关键实现细节
- `BaseGridWindow` 在 `Awake` 中动态创建 `SpriteRenderer`(白色 1×1 Sprite,`SpriteDrawMode.Sliced` + `SpriteMeshType.FullRect`)和 `TextMeshPro` 标签子对象
- 中文标签使用运行时动态 `TMP_FontAsset`(从 `Assets/TextMesh Pro/Fonts/NotoSansCJK-Regular.ttc` 创建,`AtlasPopulationMode.Dynamic`)
- URP 2D 场景必须保留 `Light2D`(Global Light),否则 `Sprite-Lit-Default` 材质的 Sprite 不可见
- `WindowSpawnSystem` 根据解锁区域控制窗口 `Hidden/Blackout` 状态
- **View 层获取子对象必须使用 `SerializeField` 引用绑定,禁止在代码中使用 `transform.Find` 或 `GameObject.Find` 做运行时查找**。子对象引用应在 prefab 中通过 Inspector 拖拽绑定,确保编译期即可验证引用关系,避免运行时因路径变更导致空引用。
### QFramework Toolkits(位于 `Assets/QFramework/Toolkits/`)
- **_CoreKit**:基础工具集(ActionKit / EventKit / FSMKit / IOCKit / PoolKit / SingletonKit / FluentAPI / BindableKit / TableKit 等),程序集 `QFramework.CoreKit` 仅 references `QFramework`
- **UIKit**:UI 面板系统(`IPanel`、`PanelInfo`、`PanelOpenType`、`PanelSearchKeys`、`UIKitHierarchyMenu` 编辑器菜单),用于注册/打开/隐藏面板,依赖 CoreKit
- **ResKit**:资源加载(基于 Resources/AB),独立程序集
- **AudioKit**:音频管理(音乐/音效/语音三通道)
- **SupportOldQF**:旧版 QF 兼容层,新代码不应使用
程序集依赖链:`UIKit → QFramework.CoreKit → QFramework`,`ResKit` 与 `AudioKit` 独立,`Assembly-CSharp`(默认用户代码)autoReferenced 这些程序集。
除此之外,还有一些根据一些AI经常出现的不合适的情况,我也推荐写入到CLAUDE.md中的内容
- 不写防御性代码:不加多余的 null check、try-catch、边界判断
- 不写空生命周期函数(空的 Awake/Start/Update 直接删)
- 不在 Update 里调用 GetComponent,Awake 里缓存
- 不用 Find / FindObjectOfType,用 SerializeField 直接引用
无论是CLAUDE.md还是类似于Cursor的Rules等任何对AI行为进行约束的文件,都应该写入应该做什么和不应该做什么这两方面。就类似在绘图相关的AI应用中写正向提示词和反向提示词一样。
开发具体功能模块
我主要使用/grill-me这个SKILL来进行具体功能的开发。清晰的指令对于AI来说很重要,但很多时候你认为自己的需求已经很明确了,依然会有一定的瑕疵,grill-me 本质是一个需求拷问机,在你提出模糊的需求后,不断追问,直到把模糊的想法锤炼成清晰的指令
以下是我与AI对话的对话样例,我已经开发完成了了一个简单的任务系统和配方系统,现在需要实际的UI实装(对于Unity内的预制体或场景,还需要搭配/unity-skills和/unity-mcp来食用)
接下来,我需要你为我实现任务和配方的 UI 实装
1. UI 面板的预制体我已经创建好了,通过 QFramework 创建
2. UI 的绑定使用 QFramework 的 Bind 脚本,进行自动生成
3. UI 示意图在 docs/TaskImg 中(任务Tab.png / 配方Tab.png)
4. UI 分为两个 Tab:任务视图、配方视图
5. UI 是从屏幕左侧抽出来的浮窗
6. 任务需求:完成时浮窗、折叠、红点、悬停消红点……(这里比较长,文中省略了)
7. 配方需求:解锁浮窗、折叠、红点、未解锁系列不显示标题、关闭弹窗后才算解锁……(这里比较长,文中省略了)
8. 任务/配方玩法已实装,细节可查 issue 和 PR
9. 配方按 typeForShow 分类;任务按主线/支线 + 系列分类
10. /grill-me 11. 执行时单独开一条 worktree
/grill-me在动手前做了什么:
/grill-me根据用户需求,扫描代码库,对需求的细节进行追问,像出题一样给出方案
| 阶段 | AI行为 | 人的作用 |
|---|---|---|
| 摸底 | 列示意图目录、读 Model/System、发现UI预制体只有根节点 | |
| 拷问 | 按依赖顺序逐题澄清(解锁语义 → 面板生命周期 → 红点 → 弹窗 →触发方式) | 选择方案进行拍板 |
| 收敛 | 输出「设计决策总览表」+ 文件改动清单 | 审计划、改需求、确认需求 |
这里是原型图和最终实现的对比,可以看到还是十分还原的,功能基本没问题,后续只需要换贴图和进行微调

其他样例
功能搬迁
BooomJam 里我做过几次功能表现和交互不变,但是底层逻辑变动的示例。
举一个简单的例子,早期游戏的窗口单位的渲染方式是用的SpriteRenderer 拼出来的,但是后面根据美术需求需要,游戏窗口单位需要支持自适应,用UGUI渲染是最好的选择。为了整体面板体系统一,我直接把窗口背景和交互迁到共享 Canvas,用 Image + 纯 UGUI事件,不再混两套渲染逻辑。这种搬迁我一般就不用 grill-me了,因为改动的需求很清楚:全部 UGUI化,不改任何玩法和交互。
编辑器工具制作
在开发过程中,常常有多个功能的底层逻辑做出来了,但是做交互和UI进行串联验证的情况出现,好在使用了QFramework进行了清晰的架构,将数据逻辑和表现层分离,这时候使用AI快速做一个编辑器界面,来快速验证是十分方便的。以及在测试时,需要一点开发者外挂的手段,也是需要编辑器工具辅助。
配表
配表这方面则是面向配置表中的重复性劳动,以这样一个固定工作流来执行:
使用
/xlsxSKILL 改表结构或字段 -> 跑 Luban 生成 -> Unity 编译 -> 再接代码。
举一个简单例子,这次BooomJam中做的游戏中,需要为每个游戏窗口单位配置其对应的图标,需要在表格中配置美术素材相关图标路径以供程序运行时读取。美术素材已经在工程目录的情况下,将路径填入表中,这一步操作如果让人为操作,涉及繁重的复制粘贴工作,那么这个时候使用 /xlsxSKILL让AI做是最合适的。

当然,重复性劳动肯定不止这一方面,类似音频,一些带有规律性的数值配置也可以让AI来完成。
建议
通过列点来给提示词
给 AI 的提示词最好是通过列点的形式,一方面为了更方便验收, 一个点对应一个行为,另一方面在在一定程度上对AI进行了行为约束。 当然,需要拷问细节的,即使列点了,也要/grill-me,越是涉及范围大的工作,越是要进行拷问。
规范文件很重要
CLAUDE.md或rules 这类文件,本质上就是项目级提示词。 主要不能只写“推荐做什么”,还要写“明确不能做什么”。比如:
- 应该做:QFramework 分层、Bind 生成、Luban 流程、常用菜单入口;
- 不应该做:把业务逻辑塞进 MonoBehaviour、随手改存档结构、在查找组件使用Find 将这两边都写清楚,AI 才会稳定,才像真正可执行的开发约束。
通过Git来审查AI代码
这里直接先列出几点建议:
- 以干净的工作区开始,如果AI产生了过多的冗余的代码,或者严重错误的代码,请使用Git进行重置
- 在下一部分开始之前,确保每个可工作的部分都已经提交到Git中
- 每次修复尝试失败后,回到干净的代码状态再进行下一次尝试,不要在错误的基础上让AI持续修复
虽然大部分Agent都提供了查看文件差异的功能,但是我实测下来大部分都会偶尔出现因为人为或Bug导致的展示的差异和文件实际的差异不一致的情况,所以这个时候,Git所展示的文件差异是最权威的。在人为进行代码审查时,也最好通过Git进行审查,一般来说,一些现代IDE都内置了很好用的差异查看功能。
心得
这次使用AI辅助进行全流程的从0到1的构建效果目前来看还是很好的,这次开发95%的代码和30%的场景以及预制体编辑均由AI完成。以我自身的能力来说,AI的效率是我的好几倍。
Vibe Coding不会颠覆游戏开发,我经常会听到身边“有技术的人”会因为AI发展导致的焦虑,因为自己学到东西突然好像没有意义而焦虑,而我的观点是AI的出现让执行的差距减少了,但更放大了决策与品味的能力,而这正是游戏这个领域最重要的东西,人更应该专注于这方面的提升,而非技术本身。
这关乎品味
“归根结底,这关乎品味。这关乎让你自己置身于人类所创造的最优秀事物中,然后尝试将这些事物融入到你真正正在做的事情里。 ---乔布斯”
AI爆炸式的增长,技术的门槛被拉低,让一切都充满了无限的可能,让不少人“有技术的人”焦虑,但AI还无法定义什么叫“优雅”,什么叫“美”,AI也无法产生人的体验,人的感受。人负责定义“优雅”与“意义”,负责在无限的可能中找到最符合直觉与美感的方案。所以,有无技术,或对技术掌握的深浅,在历史进程的推进下都将变得毫无意义,而人的思考是永垂不朽的。品味,将成为未来程序员的核心竞争力。
这关乎问题
答案是廉价的,高质量的问题才最有价值。AI能高效的指令,但AI不产生欲望,不产生情感,没有人的体验,人的感受。所以同样的,他也无法洞察人类未被满足的深层需求。在这样的时代下,我们将模糊的愿景转化为清晰的逻辑,进行一场苏格拉底式的持续追问来激发AI的最大潜能。
最后欢迎读到本文的朋友游玩我们的游戏神谕之窗.exe