AIGC标识 将一个Godot大项目拆分成n个小项目的心得体会

本文不推荐任何中转

Before:很多关卡,高耦合,因此也在拆分出项目的时候受到很大阻力
After:一个关卡一个项目,便于进行单个关卡的维护,交给原先的大项目进行统筹协调,低耦合

GPT 5.6 Terra写的心得: 写到这里的时候Terra medium还没跑完,跑完后直接跟我说还有很多报错,不干了,我让他继续也是懒狗一条啊,根本推进不了,只能推倒重来
图片
最后换了Deepseek v4flash-0731 Max
lowiq就是没法比,再经过中转的加持和Luna下架(其实没下架的时候Luna Max也是让人等着干着急)的影响下,中转Deepseek更有性价比了,梁老板牛逼
图片

以下是deepseek-v4-flash-0731写的心得体会:

Godot4.7 大项目拆分心得体会

背景

一个 Godot 项目里塞了十几个关卡,共享一个 State.gd 全局单例、一套主菜单 UI、
以及互相引用的资源目录。任务是把每个关卡拆成独立可玩的小项目:能单独
--import、能无头运行、缺什么依赖一目了然,并且不修改源项目。

一、方法论:先算依赖闭包,再做白名单删除

拆分最大的风险不是"搬文件",而是你不知道一个文件到底被谁引用。我的做法分四
步:

  1. 依赖闭包:以每个关卡的入口场景为根,BFS 收集全部引用——res:// 路径、
    class_name、uid 三种引用方式都要覆盖,直到集合不再增长。

  2. 跨关卡依赖迁移:A 关卡用到了 B 关卡目录下的材质、字体、贴图,就把它们复制
    进 A 的 level/A/deps/<原路径>/,并精确改写引用。这一步解决"依赖在其他关卡
    文件夹里"的问题。

  3. 系统层解耦:对话系统、活动系统、patches/pck 加载、item 系统、主菜单 UI 全
    部删除;State.gd 是共享状态的集中地,删掉 patch 常量、patch 加载函数、背
    包存档段、活动变量。注意:删函数时一定要搜残留调用(我踩过
    _merge_patch_levels() 只删了定义没删调用的坑,脚本直接编译不过)。

  4. 孤儿判定:引用闭包之外、又不在白名单里的脚本就是垃圾,直接删。但 .uid 伴
    生文件不能按文本引用判断——只要 .gd 保留了,.uid 必须一起留。

二、踩过的坑(按杀伤力排序)

  • GDRE 二进制资源不能碰:Seabed 的 level_1.tscn 是 GDRE 打包的二进制格式,编
    辑器里保存一次就转坏,出现 39 个 Array[float]→Array[StringName] 错误。对
    策:所有项目先 git init,误存就 git checkout -- 恢复。

  • 隐藏的二进制依赖:一个 Note.material(GDRE 二进制)内部引用
    res://activities/ball.png,字符串不是连续编码,文本搜索根本抓不到。删掉
    activities 后 MainLine 加载失败,才通过 import
    日志暴露。结论:静态分析只是线索,import 日志才是最终裁判。
    修复方法是临时恢复 activities/ball.png 让材质能加载,用 Godot
    脚本改写纹理引用并重存,再删临时目录。

  • uid 与路径回退:旧格式资源没有内嵌 uid,场景里引用的 uid://... 失效时
    Godot 会回退用文本路径加载,警告无害。但如果你重存了资源,uid
    会变,别指望旧 uid 还能对上。

  • 路径含空格:Scripts/ui/DLRS GAS/ 这种路径会让 res://[^\s...]
    正则提前截断,静态分析大面积误报。正则要允许空格,用引号/括号做结束符。

  • 编辑器重开场景的假错误:--import 会恢复编辑器上次打开的场景,@tool 脚本的
    _ready 会在 import 时执行,产生"新增"报错。对比 HEAD 干净状态的 import 日
    志即可确认是既有行为,与游戏运行无关。

  • gdmcp 跑错场景:run_project 默认运行编辑器当前打开的场景,不是项目主场景。
    Origin 那次就是跑到了 GAMEUI.tscn 而不是关卡,必须显式传 scene_path。

三、验证体系:这是最值得投入的部分

  1. 基线先行:拆分前先用 godot --headless <场景> --quit-after 150 记录每个关
    卡的报错数(物理信号 Cannot convert argument 1 from Object to Object 等源
    项目固有报错,Amnesia 高达 248 条)。之后每次清理都以"错误数不变 +
    missing=0"为回归标准。

  2. 两层冒烟:--import 全过只是下限;跑主场景 150 帧,对比基线错误数,并 grep
    Failed loading / non-existent 确保 missing=0。

  3. 运行时验证:headless 起编辑器加 --mcp-server,run_project 启动游戏,通过
    runtime API 找到 MainLine,读位置 → 调 turn() → 等 1 秒再读位置。8 个项目
    全部 moved,才算"可玩"实锤。

  4. 每步一个 commit:git init + 每轮清理单独提交,是敢删的前提。删错了(比如
    误删被二进制场景引用的脚本)git checkout 秒回滚。

四、收益与反思

收益:每个关卡独立发布、独立调试,资源互不污染;错误定位从"整个大项目里猜"变
成"单个小项目里查";发布体积也大幅缩小。

反思:

  • 拆分工作量的大部分来自历史技术债——关卡之间共享资源目录、全局单例里堆了所有
    系统。如果当初每个关卡就做依赖隔离,拆分只是复制粘贴。

  • 静态分析有极限:二进制资源编码、动态 load() 拼接、uid 缓存,都可能导致误
    判。把"Godot 自己能不能加载"作为最终标准,比任何脚本都可靠。

  • 清理策略要克制:"闭包外即垃圾 + 场景可玩即可"是合适的原则。过度清理(比如
    为了整洁去重构数据结构)风险高、收益低,留到真正需要时再说。

  • 需求澄清很重要:用户说"不用管",实际意思是"直接删"。"不用管"≠保留,可能
    是"不用管它会不会被重构,删了就行",这类歧义要尽早确认,否则会多一轮返工。

一句话总结:拆分 Godot 大项目的本质不是搬家,而是"算清楚依赖 + 建好验证基线 + 用 git 兜底",三者缺一不可。

重构

这次 8 关迁移任务让我有几条比较深的体会:

  1. 工具化的价值远大于"手改"
    最大的教训是把转换做成 Python 工具而不是逐关手写场景。8 关里最大的是 Seabed 1.1M 行、War 78K 行,手改根本不现实。convert_generic.py 从 Loss 起步,每处理一关就暴露一批通用缺陷(ext_id 误匹配 uid、Obstacle 自带 2x 缩放导致碰撞重叠、sub_resource 依赖顺序、AnimationPlayer2 取错节点、FBX/二进制资源路径重写等),修一次就惠及后面所有关卡。先做对一关,再复制模式,是最快路径。
  2. "旧场景就是真相",文件名相似不等于等价
    很多地方差点凭名字想当然。比如:
  • 新 Player 用 basis*BACK(+Z),旧 MainLine 用局部 (0,0,-1),方向要按每关道路实测,不能套同一套 firstDirection;
  • Seabed 的 tapers 在 x=-26 我才确认道路朝 -X,初设 90° 是错的;
  • pitch_scale=2 不能直接变成 timeScale=2(Loss 音乐 57s vs 动画 55.5s,2x 会脱节)。
  1. 并行 subagent 的教训
    前两次并行 subagent 全部返回空结果、什么都没改,浪费了不少时间。后来我先把工具做到能在两关上跑通、验证通过,再带着"现成转换器 + 具体 config schema + 已验证的参考产物"分派给 6 个 subagent,才真正并行成功(5 个完整报告 + 1 个我自己兜底)。给 subagent 的不是任务描述,而是可复用的工件。
  2. 门禁检查要在"最终场景"上做
    残留引用 gate(MainLine/BaseCam/Diamond/State/gamepart 等)必须对最终场景跑,且要区分"旧类引用"和"普通节点名"。例如 War 的 Diamonds 容器名会误报,Loss/Winter 里旧 Diamond 的 MeshInstance3D override 子节点引用了已消失的父路径——这些都是单独清理后才干净的。
  3. 有头运行验证补上了 headless 的盲区
    headless 下某些时序(如 Winter 玩家 turn() 时未落地)会被掩盖。用户坚持"有头运行 + player.turn() 报告位置"是对的——真实渲染下确认了每关 1 秒后沿正确方向前进、音乐播放、玩家存活。
    总体上:先小规模跑通闭环,再放大;把经验固化进工具和文档;让验证覆盖"能加载、能运行、能玩"三个层次。 这也是 plan.md 里"逐关完成再提交"的价值所在。
posted @ 2026-08-12 21:04  meny  阅读(5)  评论(0)    收藏  举报