三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Unity-MCP:用自然语言操控Unity编辑器,AI大模型与MCP协议实战

Unity-MCP:用自然语言操控Unity编辑器,AI大模型与MCP协议实战

1. 项目概述:当AI助手成为你的Unity开发伙伴

最近在和一些独立游戏开发者朋友聊天,发现大家普遍有个痛点:Unity编辑器功能强大,但操作界面复杂,菜单层级深。有时候想实现一个简单的功能,比如“给所有选中的物体添加一个随机旋转动画”,或者“批量修改场景中所有灯光的颜色”,都需要在Inspector、Hierarchy、Project窗口之间来回切换,点击多次鼠标,甚至写一小段编辑器脚本。这个过程打断了创作的心流,尤其对于策划或美术出身、编程经验不那么丰富的团队成员来说,更是如此。

就在这个背景下,一个名为“Unity-MCP”的项目进入了我的视野。它的核心目标非常直接:让你能用自然语言直接和Unity编辑器对话。想象一下,你只需要在聊天框里输入“把主摄像机对准那个红色的箱子”,或者“给场景里所有名字带‘Enemy’的物体加上一个闪烁的红色材质”,编辑器就能自动执行这些操作。这听起来像是科幻电影里的场景,但现在,通过结合AI大模型和一套名为MCP(Model Context Protocol)的协议,它正在变成现实。

简单来说,Unity-MCP是一个桥梁。它的一端连接着像ChatGPT、Claude这样的AI助手(我们称之为“客户端”),另一端则深度嵌入到Unity编辑器中。你向AI助手发出自然语言指令,AI理解后,会通过MCP协议调用Unity-MCP这个“服务器”提供的各种工具(Tools),这些工具本质上是一系列封装好的编辑器API操作,最终在Unity里完成你的指令。这不仅仅是“用AI写代码”,而是“用AI直接操作软件”,将意图(Intention)直接转化为行动(Action),极大地降低了工具使用的门槛。

这个项目适合所有Unity生态的参与者:独立开发者可以快速搭建原型、进行批量操作;技术美术(TA)能更流畅地测试Shader和视觉效果;团队中的非程序员成员(如策划、关卡设计师)可以自主进行一些简单的场景搭建和参数调整;甚至对于编程老手,在处理重复性、机械性的编辑器任务时,也能显著提升效率。接下来,我将深入拆解这个项目的实现思路、核心细节,并分享如何从零开始搭建和使用的完整过程。

2. 核心架构与MCP协议深度解析

要理解Unity-MCP如何工作,我们必须先搞懂它的基石——MCP协议。MCP,全称Model Context Protocol,你可以把它想象成AI世界里的“USB协议”或“蓝牙协议”。在传统的AI应用开发中,如果你想给大模型(如GPT-4)增加一些“超能力”,比如让它能查询数据库、发送邮件、控制智能家居,通常需要开发复杂的后端服务,处理认证、会话管理、工具调用等一系列问题,整个过程耦合度高,且难以复用。

MCP协议的出现,就是为了标准化AI模型与外部工具、数据源之间的交互方式。它定义了一套清晰的客户端-服务器模型:

  • 客户端(Client):通常是AI模型本身或其前端界面(如ChatGPT界面、Claude桌面端)。它负责理解用户的自然语言,并决定何时、调用哪个工具。
  • 服务器(Server):提供具体能力和数据的后端服务。比如,一个“天气查询服务器”可以提供“获取当前天气”的工具;一个“日历管理服务器”可以提供“创建会议”的工具。Unity-MCP本质上就是一个专为Unity编辑器定制的MCP服务器
  • 协议(Protocol):规定了客户端和服务器之间通信的格式。主要包括“工具列表查询”、“工具调用请求”、“工具调用结果返回”等标准化的JSON消息。

对于Unity-MCP而言,它的服务器端运行在Unity编辑器进程内(通常作为一个Editor Window或后台服务)。它向AI客户端“宣告”自己拥有一系列强大的工具,例如:

  • list_game_objects: 列出场景中所有游戏对象。
  • select_object: 在Hierarchy中选择指定对象。
  • get_component: 获取对象上的组件及其属性。
  • set_property: 设置组件的某个属性值(如位置、旋转、颜色)。
  • execute_menu_item: 执行一个编辑器菜单命令(相当于点击了某个菜单)。
  • create_primitive: 创建一个基础几何体(立方体、球体等)。

当你在AI客户端的聊天框里说:“在场景原点创建一个蓝色的球体,然后把它向上移动5个单位。” AI客户端(如Claude)会进行以下思考链:

  1. 意图理解:用户想创建一个球体,修改其颜色,并改变其位置。
  2. 工具规划:要完成这个任务,可能需要按顺序调用create_primitiveset_property(设置材质颜色)、set_property(设置位置)这几个工具。
  3. 参数提取:从指令中提取关键参数:类型=球体,位置=(0,5,0),颜色=蓝色。
  4. 协议调用:通过MCP协议,向Unity-MCP服务器发送第一个工具调用请求:{“tool”: “create_primitive”, “parameters”: {“type”: “Sphere”}}
  5. 执行与反馈:Unity-MCP服务器收到请求,在编辑器内执行GameObject.CreatePrimitive(PrimitiveType.Sphere),创建成功后,将新对象的唯一标识符(如GUID或实例ID)返回给客户端。
  6. 链式调用:客户端拿到新对象的ID,接着发起第二个调用:{“tool”: “set_property”, “parameters”: {“object_id”: “xxx”, “component”: “Renderer”, “property”: “material.color”, “value”: “blue”}}。如此循环,直到完成所有步骤。

这个架构的精妙之处在于解耦标准化。AI模型提供商(如Anthropic, OpenAI)只需要让它们的模型支持MCP客户端,而工具开发者(如我们)则可以专注于开发好用的MCP服务器。一个支持MCP的AI助手,可以同时连接你的Unity编辑器、你的数据库、你的项目管理软件,成为一个真正的全能助手。

注意:MCP是一个新兴的开放协议,由Anthropic公司推动。这意味着它并非某个特定AI产品的私有功能,而是一个有望被广泛采纳的标准。Unity-MCP项目正是基于此协议构建,保证了其未来的兼容性和扩展性。

3. 环境搭建与项目初始化实战

理论讲清楚了,我们动手把它跑起来。整个过程可以分为三个部分:准备AI客户端、配置Unity-MCP服务器、以及将两者连接起来。我会以目前对MCP支持比较友好且免费的Claude Desktop作为AI客户端示例,因为它的集成相对简单直观。

3.1 第一步:安装并配置Claude Desktop的MCP功能

  1. 下载Claude Desktop:前往Anthropic官网下载并安装Claude Desktop应用程序。确保你有一个可用的Claude账号(目前部分区域可能需要等待名单)。

  2. 定位配置文件:Claude Desktop通过一个配置文件来加载本地的MCP服务器。这个文件通常位于:

    • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows:%APPDATA%\Claude\claude_desktop_config.json
    • Linux:~/.config/Claude/claude_desktop_config.json如果目录或文件不存在,你需要手动创建。
  3. 编辑配置文件:用文本编辑器(如VS Code)打开这个JSON文件。我们需要在其中声明Unity-MCP服务器。一个基础的配置示例如下:

    { "mcpServers": { "unity-editor": { "command": "node", "args": [ "/ABSOLUTE/PATH/TO/Unity-MCP-Server/index.mjs" ], "env": { "UNITY_PROJECT_PATH": "/ABSOLUTE/PATH/TO/YOUR/UNITY/PROJECT" } } } }
    • unity-editor:是你给这个服务器起的任意名字。
    • command: 由于Unity-MCP服务器通常是一个Node.js脚本,所以这里填node
    • args: 指向Unity-MCP服务器主脚本的绝对路径。你需要提前将Unity-MCP项目的代码克隆到本地。
    • env: 设置环境变量。这里最关键的是UNITY_PROJECT_PATH,必须指向你想要操作的Unity项目的根目录的绝对路径。
  4. 保存并重启:保存配置文件,然后完全退出并重新启动Claude Desktop应用程序。

3.2 第二步:获取并准备Unity-MCP服务器

  1. 克隆项目:打开终端,找一个合适的目录,克隆官方的Unity-MCP服务器仓库(请以GitHub实际仓库为准):
    git clone https://github.com/官方仓库地址/Unity-MCP-Server.git cd Unity-MCP-Server
  2. 安装依赖:该项目通常是一个Node.js项目,使用npm或yarn安装依赖。
    npm install # 或 yarn install
  3. 关键检查:index.mjs文件:确保在项目根目录下存在类似index.mjsserver.js的主入口文件。这个文件就是我们在Claude配置中指定的那个。用编辑器打开它,快速浏览一下,确认它内部是通过某种方式(如文件系统监听、网络Socket)与Unity编辑器通信的。

3.3 第三步:在Unity中安装并运行配套插件

Unity-MCP服务器需要与Unity编辑器内部的一个插件(或称为“桥接器”)进行通信。这个插件负责接收外部指令并调用真正的Unity API。

  1. 导入插件包:在Unity-MCP服务器的代码仓库中,通常会有一个UnityPluginEditor文件夹,里面包含一个.unitypackage文件。在你的目标Unity项目中,通过Assets -> Import Package -> Custom Package...导入这个包。
  2. 启动插件:导入后,在Unity编辑器中,你应该能看到一个新的菜单项,例如Window -> MCP Bridge。点击打开一个编辑器窗口。
  3. 启动服务:在这个窗口中,可能会有一个“Start Server”或“Connect”按钮。点击它。此时,Unity编辑器内部会启动一个本地服务(可能是HTTP服务器或WebSocket服务器),并监听某个端口(如8080)。
  4. 验证连接:查看Unity编辑器控制台,通常会有日志输出,如“MCP Server listening on port 8080”,表示插件已就绪。

3.4 第四步:建立连接与测试

至此,三个部分都已就位:

  • AI客户端:Claude Desktop,配置好了指向Node.js服务器的指令。
  • MCP服务器:Node.js脚本,知道Unity项目路径。
  • Unity插件:在Unity内部运行,提供API端点。
  1. 确保Unity项目处于打开状态,并且MCP Bridge插件已启动。
  2. 在Claude Desktop中,新建一个对话。如果配置正确,Claude的输入框附近可能会出现一个微小的插件图标(如一个小拼图),或者你可以尝试输入“/”查看可用命令列表,理论上应该能看到与Unity相关的工具提示。
  3. 进行首次测试:输入一条简单的指令,例如:“列出当前场景中的所有游戏对象。”
  4. 观察过程:
    • Claude会思考,并显示它正在调用list_game_objects工具。
    • Node.js服务器收到请求,通过本地网络(如HTTP请求http://localhost:8080/list)向Unity插件发送指令。
    • Unity插件执行SceneManager.GetActiveScene().GetRootGameObjects()并遍历所有对象,将结果列表返回。
    • Node.js服务器将结果格式化为MCP协议要求的格式,发回给Claude。
    • Claude将结果以清晰易读的方式呈现给你。

如果这一步成功了,恭喜你,桥梁已经贯通!你可以开始尝试更复杂的指令了。

实操心得:最大的坑往往在路径端口。务必使用绝对路径,并确保Node.js脚本、Unity插件、Claude配置中的项目路径指向同一个Unity工程。如果连接失败,首先检查Unity控制台的错误日志,其次是Node.js服务器的运行终端输出。防火墙有时也会阻止本地回环地址(localhost)的通信,必要时可以临时关闭防火墙进行测试。

4. 核心工具详解与高阶使用技巧

成功连接后,我们来看看Unity-MCP到底能做什么。其能力完全取决于其实现的“工具集”。下面我分类解析一些最常用和最具威力的工具,并分享一些高阶使用技巧。

4.1 场景对象探查与操作

这是最基础也是最常用的功能集,让你能像在Hierarchy窗口中一样浏览和选择对象。

  • list_game_objects/find_objects_by_name: 获取场景对象列表或按名称搜索。技巧:你可以让AI先列出对象,然后基于结果进行后续操作。例如:“找出所有名字里包含‘Wall’的物体,然后把它们的材质都改成‘Brick’。”
  • select_object: 在编辑器中选择对象。这非常有用,因为后续很多操作(如set_property)默认会作用于当前选中的对象。技巧:你可以让AI进行复杂的选择,如“选中所有灯光,然后同时选中所有摄像机”,这在手动操作时需要按住Ctrl键多次点击,而用语言描述则非常自然。
  • get_component/get_property: 获取对象的组件和属性详情。技巧:在修改属性前,先让AI“看看这个物体的Transform组件当前值是什么”,可以避免误操作。

4.2 属性批量修改与动画

这是体现AI自动化威力的核心领域,特别适合技术美术和关卡设计师。

  • set_property: 这是“瑞士军刀”。你可以修改位置、旋转、缩放、颜色、强度、布尔值等几乎所有通过脚本可访问的属性。
    • 示例指令:“将选中的五个箱子的Y轴坐标随机设置为1到3之间的值。”
    • 底层原理:AI需要理解“随机”、“1到3之间”的含义,并将其转化为对每个对象执行transform.position = new Vector3(transform.position.x, Random.Range(1f, 3f), transform.position.z)。MCP服务器需要能解析并执行这样的逻辑。
  • add_component/remove_component: 为对象添加或移除组件。
    • 示例指令:“给所有敌人对象添加一个‘Rigidbody’组件,并设置质量为2。”
    • 技巧:结合set_property,可以在添加组件后立即配置其参数,一步到位。
  • 简易动画序列:通过组合多个set_property工具,可以实现简单的关键帧动画。
    • 示例指令:“让那个红色的方块在5秒内,从当前位置移动到(10,0,0),然后再用3秒移回来。”
    • 实现思路:AI需要将这个指令分解为:1) 记录起始位置。2) 计算移动速度(位移/时间)。3) 通过循环或协程(在服务器端实现)分帧修改位置属性。这要求MCP服务器具备一定的“脚本”执行能力,而不仅仅是单次API调用。

4.3 编辑器菜单与资产操作

直接调用编辑器菜单命令,大大扩展了操作范围。

  • execute_menu_item: 执行任何编辑器菜单命令。你需要知道该命令的完整路径。
    • 示例指令:“在项目Assets/Scripts文件夹下,创建一个新的C#脚本,命名为‘PlayerMovement’。”
    • 对应操作:这相当于点击了Assets/Create/C# Script,然后在对话框中输入名称。AI需要知道菜单路径是"Assets/Create/C# Script"
  • 资产导入与处理:虽然不一定是标准工具,但可以扩展。例如:“将D:/Textures目录下的所有PNG图片导入到项目的Assets/Textures文件夹,并设置为Sprite类型,最大尺寸1024。”

4.4 高阶技巧:复杂工作流编排

真正的生产力提升来自于将简单工具组合成复杂的工作流。

  1. 场景快速搭建:“创建一个地形,在上面随机放置50棵树和20块石头,然后放置一个玩家出生点,最后在四个角落各放置一个光源。”

    • AI需要依次调用:创建地形 -> 循环创建/放置树木和石头(可能需要随机位置和旋转)-> 创建空对象命名为SpawnPoint -> 循环创建四个灯光并设置位置和旋转。
  2. 批量性能检查:“遍历场景中所有带有MeshRenderer的物体,检查它们使用的材质球是否使用了标准着色器(Standard Shader),如果是,把列表报给我。”

    • 这需要AI进行条件判断和结果汇总,展示了从“操作”到“分析”的进阶。
  3. 与版本控制结合:在完成一系列复杂的场景修改后,你可以说:“帮我生成一个描述刚才所有操作的变更日志,然后打开Git窗口,提交这些更改,提交信息就用刚才生成的日志。”

    • 这需要MCP服务器集成Git命令或调用Unity的Version Control API,展现了AI作为工作流协调者的潜力。

注意事项:自然语言存在歧义。当你说“把那个物体放大一点”,AI对“一点”的理解可能是1.1倍,也可能是1.5倍。在关键操作上,尽量使用精确的数值或相对明确的描述,如“放大到原来的1.2倍”。对于非常重要的场景,在让AI执行批量不可逆操作前,可以先让它“模拟”或“描述”将要进行的操作,确认无误后再执行。

5. 自定义工具开发:释放无限潜能

Unity-MCP自带的工具集可能无法满足你的所有需求。幸运的是,MCP协议和Unity-MCP框架通常都支持自定义工具开发。这意味着你可以教会你的AI助手做任何你能用Unity Editor Scripting(编辑器脚本)实现的事情。

5.1 开发一个自定义工具的流程

假设我们想添加一个工具,用于快速查找场景中缺失了Collider组件的可移动物体(一种常见的性能或逻辑错误)。

  1. 在Unity插件端定义工具逻辑: 你需要修改或扩展Unity端的MCP桥接插件代码。通常,这里有一个工具注册表。你添加一个新的工具处理函数。

    // 示例伪代码,位于Unity插件的某个处理类中 [MCPTool("find_objects_missing_collider")] public static McpResponse FindObjectsMissingCollider(McpRequest request) { var allObjects = GameObject.FindObjectsOfType<GameObject>(); var results = new List<string>(); foreach (var go in allObjects) { // 简单的筛选逻辑:有Renderer(可见)但没有Collider if (go.GetComponent<Renderer>() != null && go.GetComponent<Collider>() == null) { // 检查它是否在某个“可移动”的层,这里假设第8层是“Movable” if (go.layer == LayerMask.NameToLayer("Movable")) { results.Add($"{go.name} (Path: {GetHierarchyPath(go)})"); } } } return new McpResponse { content = new[] { new McpContent { type = "text", text = results.Count > 0 ? $"找到 {results.Count} 个缺失Collider的可移动物体:\n" + string.Join("\n", results) : "未找到符合条件的物体。" }} }; }
  2. 在MCP服务器端声明工具: Node.js服务器需要知道它提供了这个新工具。你需要在服务器的工具定义列表(通常是index.mjsschema.js中)添加这个工具的元数据,包括名称、描述、参数列表等。

    // 在服务器的工具定义数组中添加 { name: "find_objects_missing_collider", description: "查找场景中所有位于‘Movable’层、有Renderer组件但缺少Collider组件的游戏对象。", inputSchema: { type: "object", properties: {} // 这个工具不需要输入参数 } }
  3. 建立通信映射: 确保当AI客户端调用find_objects_missing_collider时,Node.js服务器能正确地将这个调用转发到Unity插件的对应端点(如http://localhost:8080/tools/find-missing-collider)。

  4. 重启服务: 重启Unity编辑器中的插件和Node.js MCP服务器,使更改生效。

  5. 测试新工具: 在Claude中直接输入:“帮我找找场景里哪些应该可移动的物体忘了加碰撞体。”

5.2 自定义工具的设计原则

  • 单一职责:一个工具只做一件事,并且做好。不要设计一个“查找并修复缺失碰撞体”的工具,而应该拆分成“查找”和“修复”两个工具,这样更灵活。
  • 清晰的描述:在工具定义中提供详尽、准确的描述,这能帮助AI模型更好地理解何时该调用此工具。
  • 健壮的错误处理:在Unity插件端的代码里,一定要做好异常捕获和错误信息返回,这样当工具调用失败时,AI和用户都能得到清晰的反馈。
  • 考虑性能:避免在工具中执行全场景遍历等重型操作而不加限制。可以提供分页或过滤参数。

通过自定义工具,你可以将团队内部的工作流、常用的检查项、特定的资产处理流程都封装成AI可调用的指令,从而打造一个高度定制化、与团队工作方式深度契合的智能开发环境。

6. 常见问题排查与性能优化指南

在实际使用Unity-MCP的过程中,你肯定会遇到各种问题。下面我将常见问题、原因及解决方案整理成表,并分享一些性能优化的思路。

6.1 连接与通信问题

问题现象可能原因排查步骤与解决方案
Claude提示“无法连接到MCP服务器”或“工具调用失败”。1. Node.js服务器未启动。
2. Claude配置文件中路径错误。
3. Unity插件未启动或端口被占用。
1. 检查终端,确保Node.js脚本正在运行,无报错。
2.逐字符核对Claude配置中的args路径和env中的项目路径,必须是绝对路径
3. 查看Unity控制台,确认MCP插件已成功启动并打印监听端口。使用netstat -ano | findstr :8080(Windows)或lsof -i :8080(macOS/Linux)检查端口占用。
连接成功,但执行任何指令都无反应或超时。1. Unity插件与Node.js服务器之间的网络通信失败。
2. 工具实现有Bug,导致Unity端卡死或无响应。
1. 在Node.js服务器代码中增加详细日志,打印出发送给Unity的请求和收到的响应。检查Unity端是否收到请求。
2. 尝试一个最简单的工具,如list_game_objects。如果这个都失败,可能是基础通信链路问题。如果这个成功,复杂工具失败,则检查该工具的Unity端实现逻辑。
Claude能识别工具,但调用时参数错误。1. AI模型对指令理解有偏差,生成了错误的参数。
2. 工具的参数Schema定义不够严格或清晰。
1. 尝试将指令写得更精确、无歧义。例如,不说“把那个弄亮一点”,而说“将‘Directional Light’对象的‘Intensity’属性设置为1.5”。
2. 在自定义工具时,仔细定义参数的type(字符串、数字、布尔值)、enum(可选值列表)和description,这能极大地引导AI生成正确的参数。

6.2 功能与执行问题

问题现象可能原因排查步骤与解决方案
指令执行了,但结果不符合预期(例如物体移动到了错误位置)。1. 坐标系理解错误(世界坐标 vs 本地坐标)。
2. 属性路径(property path)引用错误。
1. Unity中Transform.position是世界坐标。如果你想说“向右移动”,AI可能操作的是localPosition。在指令中明确说明“在世界坐标系中”或“相对于父物体”。
2. 使用get_property工具先查看一下目标对象的准确属性结构和当前值,再设计修改指令。
执行批量操作时,编辑器卡顿甚至无响应。1. 单次操作涉及对象太多,或操作本身开销大(如实例化物体、加载资源)。
2. AI在频繁进行“思考-调用-等待”循环,网络延迟叠加。
1.实施分块处理:在自定义工具中,对于大规模操作,加入分批处理逻辑,每处理N个对象后yield return null一下,避免阻塞主线程。或者指令改为“先找出所有对象,然后分10批进行修改”。
2.优化指令:尽量让一条指令完成一个完整任务,而不是拆分成几十条微小指令来回通信。
AI无法理解复杂的、多步骤的指令。1. 当前AI模型的上下文长度或规划能力有限。
2. 指令过于模糊,依赖未提供的上下文。
1. 将复杂工作流拆解成几个明确的子指令,分步下达。例如,不要一次性说“搭建一个战斗场景”,而是“第一步,创建一个平面当地面;第二步,在(0,0,0)放一个玩家模型...”。
2. 在进行复杂操作前,先用语言建立上下文。例如:“我们现在要处理‘Level_01’这个场景。场景里有一个叫‘Player’的角色。接下来,请围绕这个角色执行以下操作...”

6.3 安全与稳定性考量

  • 操作不可逆:AI驱动的操作目前缺乏完善的“撤销”栈管理。在执行可能破坏场景的批量操作前,务必手动保存项目或使用版本控制。一个良好的实践是,让AI在执行此类操作前,先创建一个场景备份或提示用户确认。
  • 权限控制:在团队环境中,需要考虑不同成员能使用哪些工具。例如,实习生可能只能使用查询和简单的属性修改工具,而不能执行“删除所有未使用资源”这样的高危操作。这需要在MCP服务器层面实现简单的权限校验。
  • 资源消耗:长时间保持Unity插件、Node.js服务器和AI客户端的连接,会额外消耗内存和CPU资源。在不需要时,可以关闭Unity中的MCP插件窗口以释放资源。

我个人在深度使用这类工具后最大的体会是,它并非要取代程序员或设计师,而是成为一个强大的“杠杆”。它将我们从重复、繁琐的点击劳动中解放出来,让我们能更专注于创意和逻辑本身。它的价值不在于执行一条“创建立方体”的指令,而在于当你脑海中浮现一个复杂场景构思时,能够通过一连串的自然语言描述,快速看到它在编辑器中具象化,这种流畅的“想法到实现”的转换,才是它最迷人的地方。

← 返回列表