用Claude Code和MCP从空文件夹到可玩Unity游戏:AI编程实操全记录

发布时间:2026/10/12 4:46:19
用Claude Code和MCP从空文件夹到可玩Unity游戏:AI编程实操全记录
站在一个空文件夹面前说“这里会变成一个能玩的游戏”以前这话我只敢在脑子里过一遍。这几个月我拿 Claude Code 配合 MCP 试了一把 Unity 开发不得不承认AI 编程已经不再停留在“帮你补全函数”的层面而是能承担起从立项、搭工程、写代码、跑编译到查日志的一整条流水线。写这篇东西是想把这段实操过程完整复盘一遍调了哪些工具、踩了哪些坑、哪些环节值得自动化哪些地方必须留给人来判断。无论你是刚开始接触 AI 编程的 Unity 新手还是已经在 CI 流水线里摸爬滚打的开发者这篇内容应该都能给你一些可以直接抄作业的方法。1. 项目概述从空文件夹到可玩 Unity 游戏这件事为什么值得拆开看1.1 核心需求解析当“写代码”变成“写需求”工作流发生了什么变化先说清楚这个项目到底在做什么。目标不是做一个 3A 大作而是让一个完全空的目录在尽量少的人工干涉下通过 AI 编程代理生成一个真正可以双击运行、有交互、有界面、有计分的 2D 小游戏。整个链路里最关键的变量是 Claude Code 这个终端里的编程代理以及 MCPModel Context Protocol模型上下文协议这座桥。很多人在网上见过“AI 写了个贪吃蛇”“大模型生成了网页游戏”这类 Demo。但网页游戏和 Unity 游戏有一个本质区别网页游戏只需要一个 HTML 文件打开浏览器就能跑Unity 游戏涉及工程结构、资源导入管线、场景序列化、脚本编译、平台打包任何一个环节断了游戏都跑不起来。换句话说Unity 开发中“代码”只是冰山一角更大量、更容易出错的工作在于工程组织。所以这个项目的真正挑战不是让 AI 写几段 C#而是让 AI 能像人类开发者一样看到完整工程、修改工程文件、调用 Unity 编译、读取报错日志再回头改代码——这就必须有 MCP 在中间接一条“让模型能操作真实文件系统”的通道。1.2 适用场景与读者画像哪些人适合直接复刻这套玩法这套玩法适合三类人。第一类是自己写过一点 Unity 但总在脚本报错、场景搭建、资源导入上浪费大量时间的开发者AI 可以帮你把重复劳动吞掉一大半。第二类是产品、策划出身本身编程底子有限但想快速做原型验证玩法的手艺人关键在于你不需要精通 C# 语法而是需要能把想法拆成清晰的指令剩下的交给 Claude Code 迭代。第三类是关注 AI 工程化的人你未必做游戏但“让大模型操作文件系统”这套思路完全可以迁移到数据处理、自动化测试、文档生成等领域。我个人的建议是如果你连 Unity 编辑器都没打开过最好不要一上来就玩这套因为场景里的很多报错需要你至少能看懂 Unity 的 Console 面板。但如果你有过哪怕一次手动搭场景、挂脚本、跑 Build 的经历这套流程能给你省下大量时间。2. 技术选型与核心原理Claude Code 凭什么能“操控”Unity2.1 Claude Code 的优势不只是生成代码而是接管了整个开发闭环先说 Claude Code 是什么。它是跑在终端里的一款编程代理和你在网页对话框里提问最大的不同是它能读取工作目录里的文件能运行命令能根据执行结果不断调整下一步动作。也就是说它不是“一次性生成一段代码给你”而是“住”在你的项目里像一名外包工程师一样自己看代码、自己改、自己跑测试、自己修。和直接让大模型写 C# 代码相比Claude Code 的价值体现在四层上下文理解它能把整个 Assets 目录的结构、关键脚本内容、场景文件里的 GameObject 布局全部纳入理解范围给出的代码不会脱离当前工程的状态。主动行动它可以调用命令行工具执行 Unity 的批处理指令触发编译然后读取生成的日志根据报错信息修改代码。迭代闭环一次生成很少能直接跑通但 Claude Code 可以反复“改代码 — 跑编译 — 看日志 — 再改”直到错误消失。长期记忆在同一个会话里它能记住你项目里已经建立的约定比如命名风格、公共接口、目录规范后续生成的内容会和前文保持一致性。这四点合在一起才是“空文件夹变成游戏”的底气。如果只把 AI 当代码生成器用你最终还是得自己把代码粘进工程、自己打开编辑器等编译、自己看 Console 报错那只是把写代码这一步外包了剩下的活儿一点儿没少。2.2 MCP 的工作原理让模型拥有“手”和“眼睛”MCP 解决的是“模型看不到文件系统也无法执行操作”的问题。如果你用过 ChatGPT 的联网搜索或代码解释器可以这样理解MCP 就是给 Claude Code 外挂的一套工具集合让它可以调用文件读写、目录扫描、图片处理、项目构建这一类真实世界的 API。这里的关键认知是MCP 不是另一个“AI”而是一组工具的接口协议。你可以自己写一个本地服务暴露几个工具函数比如 read_file、write_file、list_directory、run_commandClaude Code 通过 MCP 协议和这个服务通信模型在推理过程中发现“我需要看看现在的场景文件内容”就会自动调用这些工具。对于 Unity 游戏开发这套机制最重要的意义是让 AI 能跑通“读代码 — 改代码 — 编译 — 查日志”的循环而这个循环恰恰是游戏开发中最消耗人力的部分。2.3 工具链全景实际用到的服务端与连接方式我从头到尾搭建的方案分三层第一层是 Claude Code 本体负责对话、推理、规划。第二层是一个本地 MCP 服务端负责把 Claude Code 的请求翻译成真正的文件系统操作和命令行调用我用的是一个轻量的 Python 脚本暴露了这些工具查询目录结构、读取文件、写入文件、执行终端命令、批量改名和移动文件、调用 Unity 命令行执行批处理任务、读取 Unity 编译日志。第三层是 Unity 本身。我并没有全程在编辑器里点按钮而是大量使用 Unity 的批处理模式通过命令行传参让 Unity 在后台打开工程、执行某个编辑器脚本、然后退出。这个模式特别适合 AI 自动化因为整个流程不需要显示窗口也无须人工介入。这样的分层带来一个直接好处AI 生成的任何一步操作都有真实反馈。它写入一个脚本可以马上跑一次编译看结果它改了一个场景可以运行一个校验脚本来确认 GameObject 是否存在。这种“每步都有反馈”的工作模式极大降低了 AI 生成代码的失控风险。3. 环境准备与基建搭建先把“AI 能看到、能操作”这件事做扎实3.1 初始化 Unity 空工程一行命令背后的原理新建 Unity 工程不用打开编辑器操作直接走命令行批处理更干净。我用的是下面的方式unity -batchmode -createProject ./MyGame -quit -logFile ./init.log这条命令让 Unity 在后台模式创建一个空工程然后立刻退出。注意-createProject后面的路径是相对路径所以执行前先确认你所在的目录没错。空工程生成后目录下会有 Assets、Packages 和 ProjectSettings 三个文件夹这才算有了一个可供 AI 操作的真实地基。之所以选择命令行而不是 Unity Hub 图形界面创建有两个原因一是命令行操作可记录、可重复后续 CI 或批量创建虚拟工程时能复用同一套脚本二是 AI 本身没法操作图形界面如果依赖 Unity Hub就又把“人工”拉了回来违背了自动化初衷。接下来需要确认 Unity 编辑器版本。我用的是 Unity 2022 LTS 版。为什么选 LTSAI 生成代码时对长期支持版本的 API 更熟悉出错的概率远低于新版尝鲜版。Unity 的新版本经常引入 API 改动比如 Input System 的迁移、渲染管线的变化任何一个差异都可能导致 AI 生成的代码在编译阶段挂掉。3.2 配置 Claude Code 与 MCP 服务端完整配置示例在空工程目录下创建一个配置文件让 Claude Code 启动时自动加载 MCP 服务端。我的配置长这样{ mcpServers: { unity-workspace: { command: python, args: [mcp_server.py], env: { UNITY_PATH: /opt/unity/Editor/Unity, PROJECT_PATH: /home/user/my-game } } } }这段配置的作用是告诉 Claude Code 有一个叫unity-workspace的 MCP 服务启动方式是用 Python 运行mcp_server.py同时传递给服务端两个环境变量Unity 编辑器的绝对路径和当前工程路径。有了这两个变量MCP 服务端在调用 Unity 命令行时就不用你在对话里反复说明。mcp_server.py的核心实现逻辑不复杂是标准 JSON-RPC 风格的请求分发收到list_directory请求就遍历目录收到run_command请求就通过 subprocess 执行终端命令并带回输出收到unity_build请求就拼装 Unity 批处理参数并执行。搭这个意思就是让 AI 有一套稳定的“手脚”具体实现用 Python、Node、Go 都行选 Python 纯粹是因为生态里文件处理和图片处理库最顺手。3.3 给 AI 用的“命名规范”与目录约定基建里最容易被忽略的一环接好工具之后还要在工程根目录放一个约定文件叫AGENTS.md或CLAUDE.md。这个文件很重要它相当于给 AI 的入职培训手册。我在里面写明了这样几条约定Assets 下的目录结构Animations、Prefabs、Scenes、Scripts、Sprites、UI 各司其职不允许乱放。脚本命名规则文件名必须与 MonoBehaviour 类名一致否则 Unity 无法挂载组件。C# 语言版本与可空类型要求工程启用了Nullableenable/NullableAI 生成的代码必须处理可空引用类型。目标平台当前只打 Windows 桌面端Build Target 切到 StandaloneWindows64。输入系统使用旧版 Input Manager 而非新的 Input System避免项目设置迁移的开销。公共接口核心管理类必须提供静态实例访问便于场景内其他脚本直接调用。写这个文件的初衷源于一次惨痛经验AI 在某个脚本里用了新 Input System 的 API而工程默认还是旧输入系统编译时报了一堆类型找不到的错误。当时 Claude Code 翻了好几次日志才弄明白是 API 不匹配。如果一开始就把约定写清楚这一步完全可以避免。4. 实操流程全记录让 AI 一步步把游戏“长”出来4.1 规划阶段不给 AI 写代码先让 AI 写计划很多人一上来就催 AI“写一个游戏出来”这是最不明智的用法。被催出来的结果是AI 会一次性生成一大堆文件你以为工程量很大实际上每个文件都是按它想象的结构写的和你想要的玩法常常对不上。我的做法是先让 Claude Code 产出一份开发计划。我给它的指令是“不要写代码。分析这个空 Unity 工程的结构为‘玩家操控角色移动收集星星并躲避障碍有计分和游戏结束界面’的小游戏制定开发计划输出为 PLAN.md列出需要创建的脚本、场景、资源导入方式、构建步骤。”这一步非常值得做。它会先调用 MCP 的list_directory查看当前目录然后用read_file读一下 ProjectSettings 里的版本信息最后才会按实际情况写计划。计划里会把每一项拆成可执行任务创建场景、导入精灵素材、写玩家控制脚本、写碰撞检测脚本、写 UI 脚本、配置 Build 设置。有了这份计划后面每一步我都能知道 AI 在干什么它也知道自己在干什么。4.2 素材准备让 AI 自己生成并切割图片资源Unity 游戏绕不开素材。这个案例里需要的素材是玩家角色、星星、障碍物。我并没有准备现成的美术资源而是让 AI 通过 MCP 调用 Python 脚本批量生成 PNG 图片。技术细节是Claude Code 可以调用run_command执行一段 Python 代码这段代码用 Pillow 库绘制图形。画星星的方式是用数学公式计算五角星顶点坐标再填充颜色画障碍物用矩形加细节纹理画玩家角色用圆形加高光。生成的 PNG 不需要多精美只要轮廓清晰、有透明通道Unity 里导入后就能用。这一步有个很重要的后续动作Unity 导入 PNG 后默认的 Sprite 模式是 Single单张图片如果图片里包含多帧或多元素需要手动在 Import Settings 里调整。更实用的方案是生成图片时就让 MCP 顺便修改.meta文件把 Sprite Mode 改成 Multiple然后调用 Unity 编辑器脚本自动切片。整个过程 Claude Code 是靠“生成代码 → 调 Unity 批处理 → 读日志”来确认切片结果不需要打开编辑器看一眼。4.3 场景搭建从空场景到可交互场景的关键路径Unity 的.unity场景文件本质上是 YAML 格式的文本理论上可以直接用文本方式构建但实际操作中让 AI 直接改 YAML 风险极高场景文件里 GameObject 的 FileID 互相引用一旦某个 ID 写错整个场景就废了。所以我不敢让 AI 去手写场景文件。更稳妥的方案是写一个编辑器脚本用 Unity 的 API 来创建场景、添加 GameObject、挂脚本组件、设置 SpriteRender 和 Collider。这个脚本由 AI 生成然后通过 MCP 调用 Unity 批处理执行执行完毕后再读取日志确认成功。在实际推演中我让 AI 生成SceneBuilder.cs编辑器脚本包含以下核心动作创建空场景、生成 Player 对象并挂上刚写的PlayerController.cs、生成星星和障碍物预制体、添加一个 EventSystem 和 Canvas 用于 UI、用代码设置相机背景色为正色。执行完这个脚本后场景就是有完整结构的了。这个方案唯一的代价是要额外写编辑器脚本但它比手工改 YAML 稳定得多值得。4.4 核心玩法代码玩家控制、碰撞与积分以下代码是 AI 生成的玩家控制脚本的核心部分。Unity 旧版 Input Manager 用的是Input.GetAxis这套 API 只要工程没切到新 Input System基本不会出错using UnityEngine; public class PlayerController : MonoBehaviour { public float moveSpeed 5f; public float boundaryX 8f; void Update() { float horizontal Input.GetAxis(Horizontal); float vertical Input.GetAxis(Vertical); Vector3 movement new Vector3(horizontal, vertical, 0) * moveSpeed * Time.deltaTime; transform.position movement; Vector3 clamped transform.position; clamped.x Mathf.Clamp(clamped.x, -boundaryX, boundaryX); clamped.y Mathf.Clamp(clamped.y, -4.5f, 4.5f); transform.position clamped; } }这里面需要考虑几个细节乘以Time.deltaTime是为了让移动速度与帧率无关否则高帧率下角色会瞬移boundaryX用来把玩家限制在屏幕范围内这是 2D 游戏非常常见的约束。碰撞检测用OnTriggerEnter2D来做。两个关键前提一个是检测方和被检测方至少一方要有Rigidbody2D另一个是碰撞对方的 Collider 要勾选 Is Trigger。AI 在这个环节踩过坑一开始只挂了 Collider 没挂 Rigidbody触发回调永远不执行。排查方式是生成一个诊断脚本专门遍历场景里所有对象检查 Rigidbody2D 是否存在才把问题揪出来。积分和游戏结束逻辑我用一个静态管理类GameManager里面用静态字段存分数、用静态方法更新 UI 文本、在星星被收集时播放一个简单的粒子特效。粒子特效这一块也是 AI 通过代码动态创建的它用ParticleSystemAPI 在脚本里实例化了一个爆炸效果没有额外做 prefab。4.5 渲染与 UI 层Canvas 绑定、动态生成绩效文本UI 部分最容易出现的问题不是逻辑而是 Canvas 的生成和层次关系。AI 生成的UIManager.cs会动态创建 Canvas、TextMeshProUGUI 文本对象然后在代码里把它们挂到 Canvas 下。但 TextMeshPro 需要导入 “TMP Essential Resources” 才能正常显示文字否则运行时会白屏或报缺失材质。我在实际项目中让 AI 通过 MCP 执行 Unity 批处理来导入 TMP 资源步骤是先调用PackageManager.Client.Add确保com.unity.textmeshpro包存在再调用TMP_PackageResourceImporter导入基础资源。这些操作每一步都能从日志里看到是否成功所以不需要打开编辑器来判断。另一个值得留意的点是如果不想处理 TMP直接用旧版Text组件会简单不少。但旧 Text 的字体在缩放和清晰度上不如 TMP做一个“能玩的游戏”用哪个都行我选择 TMP 是为了后续扩展 UI 动画时不用返工。4.6 一键构建把整个流程封装成可直接复用的命令行脚本当代码写完、场景调通之后最后一步是打包成可执行文件。我让 Claude Code 生成一个构建脚本通过 Unity 批处理调用BuildPipeline.BuildPlayer配置如下BuildPlayerOptions buildOptions new BuildPlayerOptions { scenes new[] { Assets/Scenes/Main.unity }, locationPathName Builds/MyGame.exe, target BuildTarget.StandaloneWindows64, options BuildOptions.None }; BuildPipeline.BuildPlayer(buildOptions);AI 写好这个脚本后通过 MCP 执行unity -batchmode -projectPath . -executeMethod BuildScript.PerformBuild -quit -logFile build.log日志显示构建成功后Builds 目录下就会出现一个完整的 Windows 应用程序。双击运行游戏就可以直接玩了。这一整条链路里唯一需要我人工确认的就是最后双击运行那一下其他所有动作都是 AI 通过 MCP 完成的。5. 常见问题与排查技巧实录AI 开发 Unity 最容易踩的坑5.1 脚本文件名和类名不一致AI 最常见的初级错误我在整个流程中遇到的第一个编译错误就是脚本名与类名不匹配。Unity 要求 MonoBehaviour 脚本的文件名必须和类名保持一致否则无法将脚本挂到 GameObject 上。AI 有时候会写PlayerController.cs打开文件一看类名却是PlayerMove。这类错误直接看编译器日志就能发现通常会提示 “CS1644” 或找不到类型。让 AI 自己修的时候它往往会选择重命名类名而不是文件名。我后来在AGENTS.md里明确写了一条规定当出现文件名与类名不一致时以类名为准重命名文件且必须同步更新所有引用该脚本组件的场景或预制体。有了这条约定AI 就很少再犯同类错误。5.2 MCP 服务端连接或执行超时不要让 AI 调用重型命令过于频繁本地 MCP 服务端偶尔会遇到连接断开或请求超时。最典型的情况是AI 在短时间连续调用十几次unity_build每次 Unity 启动都要消耗几十秒模型端等待响应超时后就会误以为工具执行失败进而做出错误的“修复”动作。解决方法是给 MCP 服务端加一个简单的队列和超时机制同一个时刻只允许一个 Unity 批处理任务运行任务启动前先检查是否有其他进程占用了工程目录的锁文件。这个细节非常实用尤其是当 AI 生成代码进入“编译报错 — 修改 — 再编译”的高速循环时如果没有排队机制两个 Unity 进程同时打开同一个工程会直接导致资源冲突。5.3 可空引用类型导致的编译告警升级为错误Unity 2022 及之后版本默认启用了 C# 的可空引用类型检查。AI 生成的代码经常在处理返回值时忽略 null 检查比如GetComponentT()直接取值然后在后续代码里对它做操作。编译阶段会提示可空警告如果工程把警告视为错误就直接卡住编译。修起来不难要么改代码保证对象不为空要么在明确不会为空的位置加!空值抑制符。但要命的是 AI 对哪里应该用!、哪里应该真的判空理解得并不总是准确。我的经验是让 AI 跑一个专门的诊断脚本统计所有GetComponent调用自动为可疑的调用位置增加判空保护。这一步提升了整个工程的健壮性尤其到后期加功能时不会因为前期留下的空引用问题连环炸。5.4 PNG 透明通道与 Sprite 模式设置素材导入比想象中更容易出问题AI 生成的 PNG 默认是 RGBA 格式理论上透明通道没问题。但 Unity 导入图片时的默认设置可能把 Texture Type 当作 Default 而非 Sprite导致 SpriteRenderer 无法正确渲染。更隐蔽的问题是生成的多边形图片在边界处出现黑边。这是因为 PNG 透明区域和颜色区域之间的像素在压缩纹理时被拉伸了。解决办法是在生成图片时就为图形周围预留一圈透明 padding或者在 Unity 的导入设置里把 Sprite 的 Mesh Type 设为 Tight并把 Generate Mip Maps 关掉。这些都是小细节但这类问题的排查往往非常耗时AI 通过 MCP 能读到日志却读不到渲染画面所以最好是让 AI 在生成阶段就规避。5.5 Unity 场景文件损坏风险永远不要手写 YAML前面我提到场景文件是 YAML手写风险极高。这个风险再强调一遍如果 AI 尝试直接修改.unity文件里的Transform组件很可能破坏整个文件结构导致场景加载时报 “Failed to load scene”。正确的做法永远是通过编辑器脚本Editor Script来操作场景。这也是 MCP 的价值所在让 AI 写编辑器脚本然后在 Unity 批处理模式下执行用 API 完成场景修改。这样所有操作都有校验和回滚的可能而不像直接改 YAML 那样“一把梭”。6. 经验总结与扩展思路这套流程真正改变了什么做完这个项目之后我最深的感受是AI 编程的价值天花板不在于它能生成多复杂的代码而在于它能不能在一个完整闭环里自我迭代。Claude Code 加 MCP 的组合把 Unity 开发中最耗时、最枯燥的“改代码 — 编译 — 看报错 — 再改”环节完全自动化了。我作为开发者从操作者变成了方向把控者我提需求、定约定、检查最终产出而 AI 在需求和产出之间把大量中间步骤吃掉了。如果你也想复刻这套玩法我的建议是从一个更简单的项目开始比如做一个点击计分数的 2D 小 Demo先跑通 MCP 链路再慢慢加功能。不要一上来就挑战复杂的 3D 场景或联网功能虽然理论上行得通但排查问题的时间和流程里的复杂度会急剧上升。进一步想扩展的话几个方向可以试试接入 Git 版本管理让 AI 每完成一个里程碑就自动提交一次或者接入截图工具让 AI 在运行游戏后自动截屏通过图像反馈来判断 UI 是否正常再或者把同一个 MCP 服务暴露给不同的 AI 客户端形成一套真正意义上的“AI 开发流水线”。这些方向我都还在实验中但思路是通的先让 AI 能看见再让 AI 能操作最后让 AI 能验证。这三步走通了空文件夹变成游戏就不再是标题党而是每天都能复用的工作方式。