关于 godot-master
godot-master 是面向 Godot 4.7+ 项目架构师和开发者的知识中心,提供架构决策框架、专家工作流,以及引擎系统和游戏类型相关指导。它不作为版本迁移日志使用。
主要功能
- 01Godot 4.7+ 架构指导
- 02状态归属与信号设计
- 03按场景选择架构方案
- 04项目搭建工作流
- 05跨系统及游戏类型模式
适用场景
- 01规划 Godot 项目架构
- 02设计模块化实体和状态转换
- 03为特定游戏类型选择系统方案
- 04通过 Godot CLI 构建工具搭建项目
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-master安装后在 Claude Code 中输入/godot-master确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/2d-animation-cutout-and-skeletal.md2d-animation-expert-techniques.md2d-animation-migration-notes.md2d-animation-signals-and-frame-events.md2d-animation.md2d-physics-area2d-and-queries.md2d-physics-collision-layers-masks.md2d-physics-migration-notes.md2d-physics.md3d-lighting-environment-and-fog.md3d-lighting-gi-and-bake-recipes.md3d-lighting-migration-notes.md3d-lighting.md3d-materials-migration-notes.md3d-materials-pbr-workflows.md3d-materials.md3d-world-building-gridmap-and-csg.md3d-world-building-migration-notes.md3d-world-building-streaming-and-procgen.md3d-world-building.mdability-system-elite-ability-patterns.mdability-system-migration-notes.mdability-system.mdadapt-2d-to-3d-migration-notes.mdadapt-2d-to-3d-migration-recipes.mdadapt-2d-to-3d.mdadapt-3d-to-2d-dimension-reduction.mdadapt-3d-to-2d-migration-notes.mdadapt-3d-to-2d.mdadapt-desktop-to-mobile-migration-notes.md详细介绍
Godot Master:首席架构师知识中心
每个章节都通过聚焦 知识增量——基础模型已有知识与资深 Godot 工程师在交付真实产品过程中积累的知识之间的差距——来证明其价值。
知识库目标版本 — Godot 4.7+
所有领域技能镜像均以 Godot 4.7+(稳定版)为目标。对于任何引擎版本升级(1.x/2.x legacy → 3→4 → 逐步升级 4.x),请使用 godot-version-migration——不要把本知识中心当作迁移变更日志。
进行分类时,请留意以下跨领域的 4.7 提示:AreaLight3D / HDR → 3D Lighting;Asset Store 与 Asset Library → 导出/平台模块;RichTextLabel ImageUnit、输入设备 ID 常量、Jolt 行为 → 迁移中心模块说明。
🧠 第 1 部分:专家思维框架
“谁负责什么?”——架构健康检查
在编写任何系统之前,请针对每一份状态回答以下三个问题:
- 谁拥有数据?(
StatsComponent拥有生命值,而不是CombatSystem) - 谁可以修改它?(只有所有者能通过
apply_damage()这样的公共方法修改) - 谁需要知道它已发生变化?(任何监听
health_changed信号的对象)
如果你无法针对每个状态变量回答这三个问题,说明你的架构存在耦合问题。这不是 OOP 封装——这是 Godot 特有的,因为信号系统就是强制执行机制,而不是访问修饰符。
Godot“分层蛋糕”
将每项功能划分为四层。信号只向上流动,绝不向下:
┌──────────────────────────────┐
│ PRESENTATION (UI / VFX) │ ← Listens to signals, never owns data
├──────────────────────────────┤
│ LOGIC (State Machines) │ ← Orchestrates transitions, queries data
├──────────────────────────────┤
│ DATA (Resources / .tres) │ ← Single source of truth, serializable
├──────────────────────────────┤
│ INFRASTRUCTURE (Autoloads) │ ← Signal Bus, SaveManager, AudioBus
└──────────────────────────────┘
关键规则:表现层绝不能直接修改数据。基础设施只能通过信号进行通信。如果某个 Label 节点调用了 player.health -= 1,说明架构已被破坏。
信号总线分级架构
- 全局总线(Autoload):仅用于生命周期事件(
match_started、player_died、settings_changed)。代价是调试范围扩大——事件数量应限制在 15 个以内。 - 作用域功能总线:每个功能文件夹都有自己的总线(例如,
CombatBus仅供战斗节点使用)。这是可扩展的折中方案。 - 直接信号:单个场景内的父子通信。绝不要跨场景边界通信。
🔗 “智能互联”原则
专家系统的定义不在于彼此孤立,而在于其负载合成能力。
- 物理 → 性能:
PhysicsServer2D和RenderingServer可绕过SceneTree节点开销。用于处理 1,000+ 个子弹或粒子,实现 O(1) 处理。 - 动画 → 物理:
AnimationTree.get_root_motion_position()会将动画位移转换为物理velocity,避免复杂移动中的“脚底打滑”。 - 数据 → 响应性:序列化的
Resource对象(如Stats)在修改时会发出信号,让 UI 自动更新,同时避免紧密耦合。 - 资源 → 生成:基于 Dictionary 的 O(1) 缓存(在
ResourceLoader异步阶段预加载)可避免生成物品或敌人时出现 I/O 卡顿。 - 移动端 → 视觉效果:在加载画面期间实例化隐藏效果,以强制编译 GPU 着色器管线,避免运行时帧卡顿。
- 网络 → 带宽:使用位打包将数据写入
PackedByteArray进行同步,而非使用 JSON/Strings,将数据包控制在 100 字节以内。 - 类型合成:
Shooter:严格使用intersect_ray()(直接空间状态),而非RayCast3D节点,性能可提升 100 倍。RPG:伤害遵循base * pow(scaling, level),以支撑游戏后期的成长。RTS:根据群组的质心移动,并使用Relative Offset保持阵型完整。Metroidvania:使用ResourceLoader.load_threaded_request()实现无缝房间切换。Platformer:必须加入Jump Buffering(约 0.15s)和Coyote Time,带来专业的操作手感。Simulation:使用Tick Manager批量处理;避免对每个实体单独调用_process,以支持数千个单位。Romance:使用多轴好感度(吸引力、信任、舒适度)映射复杂的叙事分支。Architecture:Signal Architecture必须严格遵循“信号向上,调用向下”,以消除场景间的循环耦合。
🧭 第 2 部分:架构决策框架
主决策矩阵
| 场景 | 策略 | 必读技能链 | 权衡 |
|---|---|---|---|
| 快速原型 | 事件驱动单体 | 阅读:基础 → 自动加载。不要加载类型或平台参考资料。 | 启动快,有变成意大利面代码的风险 |
| 复杂 RPG | 组件驱动 | 阅读:组合 → 状态 → RPG 属性。不要加载多人游戏或平台参考资料。 | 前期设置繁重,可无限扩展 |
| 大型开放世界 | 资源流式加载 | 阅读:开放世界 → 保存/加载。另请加载性能。 | I/O 复杂,超过 10K 单位后会出现浮点精度抖动 |
| 服务端权威多人游戏 | 确定性 | 阅读:服务端架构 → 多人游戏。不要加载单人游戏类型参考资料。 | 延迟高,反作弊安全性强 |
| 移植到移动端/Web | 自适应响应式 | 阅读:UI 容器 → 从桌面适配到移动端 → 移动平台。 | UI 复杂度高,覆盖面广 |
| 应用 / 工具 | 应用组合 | 阅读:应用组合 → 主题。不要加载游戏专用参考资料。 | 与游戏采用不同范式 |
| 恋爱 / 约会模拟 | 好感度经济系统 | 阅读:恋爱 → 对话 → UI 富文本。 | UI/叙事密度高 |
| 秘密 / 彩蛋 | 有意混淆 | 阅读:秘密 → 持久化。 | 提升社区参与度,有调试风险 |
| 收集任务 | 寻宝逻辑 | 阅读:收集 → Marker3D 放置。 | 提升玩家留存率,推动探索 |
| 季节性活动 | 运行时注入 | 阅读:复活节主题 → 材质替换。 | 快速打造品牌风格,不污染资源 |
| 类魂式死亡机制 | 风险与回报式复活 | 阅读:复活/尸体寻回 → 3D 物理。 | 紧张感强,有令玩家受挫的风险 |
| 波次制动作游戏 | 战斗节奏循环 | 阅读:波次 → 战斗。 | 紧张感逐步升级,需设计遭遇战 |
| 平衡 / 难度 / 经济节奏 | 蒙特卡洛平衡实验室 | 阅读:资源 → 经济系统 → 战斗 / RPG 属性 / 波次(按需选择)→ 蒙特卡洛平衡器 → 测试 → 构建器。 | 统计严谨;抽象模拟必须对照无头 Godot 进行校准 |
| 生存经济系统 | 采集循环 | 阅读:采集 → 库存。 | 资源稀缺,循环可持续 |
| 竞速 / 速通 | 验证循环 | 阅读:计时赛 → 输入缓冲 → 竞速类型。 | 精度要求高,推动幽灵记录竞争 |
| 恐怖 / 潜行 | 紧张感管理 | 阅读:恐怖类型 → 潜行类型 → 音频。 | 营造氛围,凸显玩家的脆弱感 |
| 卡牌 / 棋盘游戏 | 规则执行 | 阅读:卡牌游戏类型 → 回合系统。 | 状态确定性强,UI 工作量大 |
| 模拟 / RTS | 批处理 | 阅读:模拟类型 → RTS 类型 → 性能。 | 单位数量多,逻辑为 O(1) |
| HDR / 电影级视觉效果 | 显示管线 | 阅读:3D 光照 → 桌面平台 → 着色器。在项目设置中启用视口 HDR。 | 需要针对平台调校色调映射 |
| 矩形区域光 | AreaLight3D | 阅读:3D 光照 → 3D 材质。优先使用 AreaLight3D,而非自发光+GI 变通方案。 | 需要 Forward+ 渲染器才能获得完整画质 |
| 移动端触控控制 | 原生摇杆 | 阅读:移动平台 → 从桌面适配到移动端。使用内置虚拟摇杆(4.7+)。 | 减少对插件的依赖 |
| 插件 / 资源发现 | 资源商店 | 阅读:项目基础 → 导出构建。资源商店取代 Asset Library。 | 商店 UI 仍处于 Beta 阶段——请逐个核实插件的许可 |
| Agent 视觉 / 可视化 QA | 捕获 → WebP → 评估标准 | 阅读:Agent 视觉。捕获截图资源、窗口/区域/屏幕,或临时编辑器桥接——然后进行结构化审查。不要加载类型参考资料。 | 仅限主机端;绝不使用 Autoload / 绝不保留暂存插件 |
| 制品 → Godot 项目 | 先建台账,再创建存根 | 阅读:GDAS-reader → REA。在存根指明类型之前,不要加载类型参考资料。 | 仅创建存根;未知行为保持为 pass |
“何时不该使用 Node”的决策
这是影响最大的专家级决策之一。Godot 文档明确指出“避免事事都使用节点”:
| 类型 | 适用场景 | 成本 | 专家用例 |
|---|---|---|---|
Object | 自定义数据结构、手动内存管理 | 最轻。必须手动调用 .free()。 | 自定义空间哈希映射、类似 ECS 的数据存储 |
RefCounted | 临时数据包、会自动删除的逻辑对象 | 没有剩余引用时自动删除。 | DamageRequest、PathQuery、AbilityEffect——不需要场景树的逻辑数据包 |
Resource | 可序列化且支持检查器的数据 | 比 RefCounted 略重。负责 .tres I/O。 | ItemData、EnemyStats、DialogueLine——设计师应能在检查器中编辑的任意数据 |
Node | 需要 _process/_physics_process,需要存在于场景树中 | 最重——每个节点都有 SceneTree 开销。 | 仅用于需要逐帧更新或空间变换的实体 |
专家模式:所有逻辑数据包和数据容器都使用 RefCounted 子类。仅将 Node 用于必须存在于空间树中的对象。对于复杂系统,这能将场景树开销减半。
🔧 第 3 部分:核心工作流
工作流 1:专业脚手架
从空项目到可用于生产环境的容器。
必须 — 阅读整个文件:基础
- 按功能(
/features/player/、/features/combat/)而非类类型组织。player/文件夹包含玩家的场景、脚本、资源和测试。 - 阅读:信号架构 — 创建包含少于 15 个事件的
GlobalSignalBus自动加载。 - 阅读:GDScript 精通 — 在 Project Settings → GDScript → Debugging 中启用
untyped_declaration警告。 - 应用**项目模板**,获取基础
.gitignore、导出预设和输入映射。 - 使用 Builder(
builder_create_scene.py、builder_add_node.py、builder_save_scene.py),通过 Godot CLI 以编程方式生成场景层级。
注意
工作流 1 禁止事项
- 绝不在逻辑脚本中使用
res://路径。使用@export_file或@export_dir,确保资源移动后仍然有效。- 绝不在
_init()中初始化子节点。此时场景树尚未就绪。请使用_ready()或@onready。- 绝不保留“Default”项目的
Physics Ticks设置。将其设为 60 以保持一致,或使用Engine.physics_ticks_per_second实现自适应逻辑。- 绝不在
_process()中使用print()进行调试;请使用Debugger或push_error(),避免帧耗时突增。
脚手架搭建期间不要加载战斗、多人游戏、游戏类型或平台相关参考资料。
工作流 2:实体编排
构建模块化、可测试的角色。
强制链路 — 全部阅读:组合 → 状态机 → CharacterBody2D 或 Physics 3D → Animation Tree 不要加载实体相关工作的 UI、Audio 或 Save/Load 参考资料。
- 状态机查询
InputComponent,绝不直接处理输入。这样即可在不重构的情况下切换 AI/玩家。 - 状态机只处理状态转换。逻辑应放在组件中。
MoveState告知MoveComponent执行操作,而不是反过来。 - 每个实体都必须通过 F6 测试:按下“运行当前场景”(F6)必须能够正常运行,不发生崩溃。如果发生崩溃,说明实体依赖于场景外部内容。
注意
工作流 2 绝对禁止清单
- 绝不要调用
parent.do_thing()。如果父节点发生变化,实体就会出问题。应改为发出信号request_action。- 绝不要使用
_process移动。使用_physics_process,以避免在可变刷新率显示器上发生抖动。- 绝不要硬编码动画名称。使用
StringName常量或Resource映射,以便在AnimationPlayer中轻松重命名。- 绝不要使用绝对路径调用
get_node()。使用%UniqueName,以便在重构树结构后仍能正常工作。
工作流 3:数据驱动系统
通过 Resources 连接 Combat、Inventory 和 Stats。
强制链路 — 全部阅读:资源模式 → RPG 属性 → Combat → Inventory
- 创建一个继承自
Resource的ItemData.gd。将其实例化为 100 个.tres文件,而不是编写 100 个脚本。 - HUD 绝不直接引用 Player。它会监听 Signal Bus 上的
player_health_changed。 - 对所有
@export Resource变量启用“Local to Scene”,或在_ready()中调用resource.duplicate()。未能做到这一点是第 8 部分中的 Bug #1。
注意
工作流 3 绝对禁止清单
- 绝不要在 Signal Bus 中传递
Node引用。对象会被释放;长期跟踪时,RID 或 ID 更安全。- 绝不要在运行时通过代码修改
.tres文件(这会修改磁盘文件)。修改前务必调用.duplicate()。- 绝不要使用
Array进行高频搜索。使用以StringName为键的Dictionary,实现 O(1) 查找。- 绝不要使用
float表示物品数量或精确的资源跟踪;应使用int,并在显示时进行缩放。
工作流 4:持久化流程
强制阅读:Autoload 架构 → Save/Load → 场景管理
- 使用字典映射进行序列化。添加新字段时,旧存档文件绝不能损坏——使用
.get("key", default_value)。 - 对于程序生成的世界:保存 Seed 和修改项的 Delta-List,而非整张地图。100 MB 的世界可以只需 50 KB 的存档。
注意
工作流 4 绝对禁止清单
- 绝不要保存整个
Object或Node实例。它们包含临时指针。应将数据提取到Dictionary或自定义Resource中。- 绝不要对需要严格类型的数据(例如
Vector2)使用JSON。对于结构化的 Godot 类型,请使用var_to_bytes或ConfigFile。- 绝不要因自动存档而阻塞主线程。使用
Thread或WorkerThreadPool序列化大型字典。- 绝不要在导出的项目中保存到
res://;持久化数据必须使用user://。
工作流 5:性能优化
先诊断再优化(绝不盲目优化):
- 脚本耗时高 → 使用内置 Profiler 进行性能分析。检查是否有数百个节点在调用
_process。改用单一管理器模式或 Server API(参见第 6 部分)。 - 绘制调用过多 → 对重复几何体使用
MultiMeshInstance。使用 ORM 纹理合并材质。 - 物理卡顿 → 将碰撞简化为基本形状。加载 2D 物理 或 3D 物理。检查移动逻辑是否误用了
_process,而不是_physics_process。 - VRAM 使用过量 → 将纹理改为 VRAM 压缩格式(桌面端使用 BPTC/S3TC,移动端使用 ETC2)。绝不发布原始 PNG。
- 间歇性帧尖峰 → 通常由 GC 回收、同步
load()或 NavigationServer 重新计算导致。使用ResourceLoader.load_threaded_request()。
注意
工作流 5 绝对禁止清单
- 绝不在
_process中使用get_nodes_in_group()。这是每帧执行的 O(n) 操作。在_ready()中缓存数组。- 绝不使用
Area2D信号处理“停留”逻辑。应定期调用get_overlapping_bodies(),或在管理器级别使用PhysicsServer检查。- 绝不在性能分析前优化。如果有 2000 次绘制调用拖垮 GPU,那么 1 ms 的脚本耗时无关紧要。
- 绝不在热点路径中使用
load();严格使用preload,或使用ResourceLoader进行异步加载。
工作流 6:跨平台适配
必须遵循:输入处理 → 桌面端改为移动端 → 移动平台 还需按需阅读:桌面平台、Web 平台、主机平台、VR 平台。
- 使用
InputManager自动加载,将所有输入类型转换为规范化操作。绝不直接读取Input.is_key_pressed()——这会阻碍控制器和触控支持。 - 移动端触控目标:物理尺寸至少为 44px。对于带刘海/挖孔的设备,使用
MarginContainer并处理安全区域。 - Web 导出:Godot 的
AudioServer需要用户交互后才能首次播放(浏览器策略)。通过“点击开始”界面处理此问题。
注意
工作流 6 绝对禁止清单
- 绝不使用
OS.get_name()检测功能。应使用OS.has_feature("mobile")或自定义功能标签,以处理“SteamDeck”等细分平台。- 绝不假定特定的宽高比。始终结合
Anchor节点使用Expand或Keep Aspect。- 绝不在移动端/Web 上使用仅适用于桌面端的着色器(例如复杂的深度采样),除非提供 GLES3/Compatibility 次级路径。
- 绝不在桌面端构建中忽略
physical_keycode;它能确保键盘布局(AZERTY/QWERTY)不会导致移动操作失效。
- 绝不将未经清理的字符串传递给
JavaScriptBridge.eval()——这可以防止 Web 构建中的脚本注入。请使用sanitize_js_string()辅助函数。
工作流 7:程序化生成
必须:Procedural Gen → Tilemap Mastery 或 3D World Building → Navigation
- 始终使用带有固定
seed的FastNoiseLite资源,确保生成结果具有确定性。 - 切勿在主线程上烘焙 NavMesh。请使用
NavigationServer3D.parse_source_geometry_data()+NavigationServer3D.bake_from_source_geometry_data_async()。 - 对于无限世界:区块加载必须使用
WorkerThreadPool在后台线程中进行。在场景树之外构建场景区块,然后在主线程上调用add_child.call_deferred()。
注意
工作流 7 禁止事项
- 切勿为“背景”噪声实例化节点。对于数千个细小细节,请使用
MultiMeshInstance或在_draw中使用绘制循环。- 切勿因一处改动而重新生成整张地图。使用“脏区块”系统,仅更新实际发生变化的部分。
- 切勿在使用
concave_polygon_shape时与网格生成同帧放置碰撞体,这会使物理线程卡顿。- 切勿每帧都为所有单位执行寻路查询。请使用
NavigationAgent,并通过计时器更新target_position。
工作流 8:多人游戏架构
必须阅读:Single→Multiplayer → Networking → Server Arch 不要加载单人游戏类型蓝图。
- 客户端发送输入,服务端计算结果。客户端绝不能决定伤害、位置变化或库存变更。
- 使用带服务端校正的客户端预测:在本地预测,并根据服务端快照进行修正。可隐藏最多约 150 ms 的延迟。
- 在 Godot 4 中,
MultiplayerSpawner负责处理复制。请按场景配置,而非全局配置。
注意
工作流 8 禁止事项
- 切勿在未验证的情况下信任
rpc_id(1, ...)(客户端到服务端)。遭到入侵的客户端可以发送damage = 999999。- 切勿直接复制
_process变换。应复制Input向量,并在双方模拟移动。- 切勿将
TCP用于高频数据包(移动)。请使用UDP/ENet,并通过插值处理丢包。- 切勿同步每个投射物;请对视觉效果使用客户端预测,并仅通过 RPC 发送“开火”事件。
ReflectionProbe与VoxelGI和SDFGI的对比:探针成本低且为静态,VoxelGI 为中等成本且需烘焙,SDFGI 成本高且为动态。请根据平台预算进行选择(参见第 5 部分)。
工作流 9:响应式 UI 与专家级主题(审计已验证)
- F6 原则:每个 UI 场景都必须能够独立测试。仅在背景上使用
MOUSE_FILTER_STOP,子节点使用PASS。 - 留白空间:使用
add_theme_constant_override("separation", X),而非手动添加内边距。 - 自适应缩放:使用
ui_containers_responsive_layout_builder.gd,根据断点切换移动端/桌面端布局。 - 生命周期安全:不要在同一帧内滚动到新子节点。修改
scroll_vertical前,先执行await get_tree().process_frame。 - 数据集成:使用
Resource-to-UI绑定;UI 节点必须是无状态的投影层。
注意
工作流 9 禁止事项
- 禁止使用绝对像素偏移。在 4K 或超小移动屏幕上,UI 会变得难以辨认。请使用
Container尺寸设置。- 禁止深层嵌套
MarginContainers。这会导致 Inspector 无法使用。请使用单个Theme资源统一设置整个项目的边距。- 禁止将 UI 按钮直接连接到游戏逻辑。UI 发送“Signal”,由
PlayerController监听。这可以防止删除 UI 时发生崩溃。- 禁止使用
_process()将 UI 元素移动到目标位置。请使用Tween,避免卡顿和帧率依赖。- 禁止让透明容器的
mouse_filter保持为STOP;它会“吞掉”后方所有内容的点击。
- 禁止在未验证
res://前缀和安全扩展名(.tres、.res、.theme)的路径上使用动态load()——这可以防止任意代码/资源执行。
工作流 10:电影级光照与 VFX(审计已验证)
- GI 选择:室内场景使用 VoxelGI,开放世界使用 SDFGI。禁止同时启用并让两者重叠。
- 阴影预算:投射阴影的 DirectionalLight 最多 2 个。移动端补光使用
3d_lighting_fake_gi_bounce.gd。 - VFX 生命周期:优先使用
finished信号,而非计时器。使用restart()重新运行,避免异步 GPU 卡顿。 - 优化:使用
ORM Texture打包(AO/Rough/Metal),节省 GPU 缓存和纹理槽位。 - 批处理:使用
Instance Uniforms为数千个实例创建材质变体,而不会增加绘制调用开销。
注意
工作流 10 禁止事项
- 禁止缩放
CollisionShape节点;应严格缩放 Shape Resource,以避免物理抖动。- 禁止对镂空网格(树叶/栅栏)使用
TRANSPARENCY_ALPHA;请使用ALPHA_SCISSOR,避免排序伪影。- 禁止在游戏过程中对 CSG 节点进行动画处理;这会强制进行开销巨大的 CPU 几何体重新计算。
- 禁止在 2D 风格的游戏中使用实时全局光照(SDFGI/VoxelGI)。请使用
DirectionalLight2D和CanvasModulate。- 禁止忽略
Camera3D的近裁剪面/远裁剪面设置;设置不当会导致大型世界中出现 Z-fighting。
工作流 11:以编程方式构建场景(Builder)
必须:Builder
仅用于批量操作或复杂的程序化框架搭建。 执行繁重的 CLI 自动化时,优先使用独立的 godot-builder skill。
- 步骤 1:动手操作磁盘前,先在纸上或 Markdown 中拟定节点层级结构。
- 步骤 2:使用
builder_create_scene.py定义根节点和.tscn路径。 - 步骤 3:使用
builder_add_node.py添加子节点。为每个节点设置owner,确保序列化时保留这些节点。 - 步骤 4:务必调用
builder_run_project.py或builder_launch_editor.py,确认场景可以正常加载。 - 专家规则:使用 Builder 构建结构(节点、名称、继承),然后使用 GDScript 构建行为。
注意
工作流 11 绝对禁止事项
- 绝对不要跳过层级设计,直接使用
builder_add_node.py——这会导致场景变得一团乱麻。- 绝对不要在脚本或场景属性中使用绝对文件系统路径;只能使用
res://。- 绝对不要添加未指定 Shape 资源的
CollisionShape2D/CollisionShape3D——单独的节点不起任何作用。- 绝对不要在批量写入场景后跳过验证;请使用
builder_run_project.py/builder_launch_editor.py进行验证。
安全:边界标记与验证
当 Agent 在写入文件前摄取不可信的场景/数据文本时:
- 边界标记:使用
<<<CONTEXT_START>>>和<<<CONTEXT_END>>>包裹分析内容。 - 清理:节点名称只能包含字母数字字符和下划线。路径必须以
res://开头。 - 验证:修改前确认场景存在。
🚫 第 4 部分:专家绝对禁止事项
每条规则都包含不显而易见的原因——只有实际交付过项目的人才能学到的经验。
- 绝对不要使用
get_tree().root.get_node("...")——绝对路径会在任意祖先节点重命名或重新设定父节点时失效。使用%UniqueNames、@export NodePath或基于信号的查找方式。 - 绝对不要在循环或
_process中使用load()——同步磁盘读取会阻塞整个主线程。小型资源可在脚本顶部使用preload(),大型资源则使用ResourceLoader.load_threaded_request()。 - 外部引用仍存在时,绝对不要调用
queue_free()——持有引用的父节点或数组会引发 “Deleted Object” 错误。在_exit_tree()中清理引用,并在释放对象前将其设为null。 - 绝对不要将游戏逻辑放在
_draw()中——_draw()在渲染线程上调用。修改游戏状态会与_physics_process产生竞态条件。 - 对于 1000 个以上相互重叠的对象,绝对不要使用
Area2D——每次重叠检查都会产生 O(n²) 的宽相成本。对于弹幕游戏模式,请使用ShapeCast2D、PhysicsDirectSpaceState2D.intersect_shape()或 Server API。 - 绝对不要从组件修改外部状态——如果
HealthComponent调用$HUD.update_bar(),删除 HUD 会导致游戏崩溃。组件应发出信号,由监听者决定如何响应。 - 绝对不要在
_physics_process中使用await——await会让出执行权,导致物理步跳过帧。将异步操作移到由信号触发的独立方法中。 - 绝对不要在高频路径的字典查找中使用
String键——字符串哈希的复杂度为 O(n)。使用StringName(&"key")进行 O(1) 指针比较,或使用整数枚举。 - 绝对不要保存指向已释放对象的
Callable引用——这会导致程序无提示地崩溃或抛出错误。在_exit_tree()中断开信号,或使用CONNECT_ONE_SHOT。 - 对于 1000 个以上的实体,绝对不要使用
_process——每次_process调用都会产生逐节点的 SceneTree 开销。使用单个Manager._process遍历数据结构数组(面向数据的模式),或直接使用 Server API。 - 绝对不要在可能被释放的节点上使用
Tween——如果 Tween 运行期间节点被queue_free(),就会报错。在_exit_tree()中终止 Tween,或绑定到 SceneTree:get_tree().create_tween()。 - 绝对不要在
_process中向RenderingServer或PhysicsServer请求数据——这些 Server 异步运行。调用 getter 函数会强制触发同步停顿,严重影响性能。这些 API 特意设计为在高频路径中只写不读。 - 绝对不要用
call_deferred()掩盖初始化顺序错误——这会掩盖架构问题(依赖场景树顺序)。使用显式初始化信号或@onready修复实际依赖。 - 绝对不要创建循环信号连接——节点 A 连接到 B,B 又连接到 A。这会在首次发出信号时造成无限循环。使用中介者模式(信号总线)打破循环。
- 绝对不要让继承层级超过 3 层——超过 3 层后,调试
super()调用链会变得极其困难。使用组合(Node子节点)添加行为。 - 在物理运算密集的游戏类型(FPS/ARPG)中,绝对不要使用
_process进行命中检测或移动;务必使用_physics_process,以确保碰撞检测不受帧率影响。 - 对于持久化游戏状态(Health、XP、Inventory),绝对不要信任客户端的授权信息。应完全通过服务器权威机制或安全校验和处理。
- 高频运行时检查中,绝对不要使用普通字符串;务必使用
StringName(&"active"),以避免 O(n) 哈希开销。 - 在单位数量众多的游戏(RTS/MOBA)中,绝对不要每帧手动处理 RVO 避让;将其交由
NavigationAgent的内部线程处理。 - 绝对不要因过程式生成或繁重的 I/O 操作而阻塞主线程;务必将任务交给
WorkerThreadPool。 - 对于用于独立实例(例如敌人属性)的 Resources,绝对不要忽略
Local-to-Scene;否则会导致所有实例之间出现共享内存错误。 - 绝对不要用
float表示货币;务必使用整数分(Integer Cents),避免复杂经济系统中的精度偏差。 - 绝对不要在
physics_frame之前设置target_position;导航地图在_ready()期间尚未准备就绪。 - 对于大型镂空表面(如树叶),绝对不要使用
TRANSPARENCY_HASH或ALPHA;请使用ALPHA_SCISSOR,以提升性能并改善排序。 - 绝对不要缩放
CollisionShape节点(Node2D/3D 缩放)——使用形状手柄或调整资源大小,避免出现不可预测的物理法线和抖动。 - 当
is_on_floor()为 true 时,绝对不要施加重力——这会导致微抖动并妨碍贴地。务必将垂直速度重置为 0 或一个较小的常数。 - 绝对不要忘记断开动态信号(捕获 Lambda)——Godot 无法自动断开捕获局部变量的 Lambda;它们会导致已释放对象发生崩溃。
- 绝对不要在移动设备上使用鼠标事件处理触控——务必使用
InputEventScreenTouch和InputEventScreenDrag,以可靠地支持多点触控。 - 绝对不要在移动设备上使用 Forward+ 渲染器——务必使用 Mobile 或 Compatibility 渲染器,避免 GPU 瓶颈和电量消耗。
- 绝对不要将鼠标旋转直接累加到变换上——务必单独存储 Yaw/Pitch 变量,以避免万向节死锁和精度损失。
- 绝对不要在高频运行时检查中使用普通字符串——务必使用
StringName(&"active"),以避免 O(n) 哈希开销。 - 绝对不要信任客户端提供的游戏状态(Health、Inventory)——客户端只提出操作建议,由服务器验证并广播,以防作弊。
- 绝对不要在移动更新中使用
ReliableRPC——请使用UnreliableOrdered,以避免高延迟场景下的队首阻塞。
📊 第 5 部分:性能预算(具体数值)
| 指标 | 移动端目标 | 桌面端目标 | 专家说明 |
|---|---|---|---|
| 绘制调用 | < 100(2D),< 200(3D) | < 500 | 使用 MultiMeshInstance 处理植被/碎片 |
| 三角形数量 | < 100K 可见 | < 1M 可见 | 超过 500K 时必须使用 LOD 系统 |
| 纹理 VRAM | < 512MB | < 2GB | VRAM 压缩:ETC2(移动端),BPTC(桌面端) |
| 脚本耗时 | 每帧 < 4ms | 每帧 < 8ms | 将热点循环移至 Server API |
| 物理体 | < 200 个活动物理体 | < 1000 个活动物理体 | 大规模模拟时使用 PhysicsServer 直接 API |
| 粒子 | < 2000 个 | < 10000 个 | 使用 GPU 粒子,手动设置 visibility_aabb |
| 音频总线 | < 8 个同时运行 | < 32 个同时运行 | 使用 音频系统 总线路由 |
| 存档文件大小 | < 1MB | < 50MB | 程序化世界使用种子 + 增量模式 |
| 场景加载时间 | < 500ms | < 2s | ResourceLoader.load_threaded_request() |
⚙️ 第 6 部分:Server API — 专家级性能逃生舱
这是大多数 Godot 开发者永远不会了解的知识。当场景树成为瓶颈时,可使用 Godot 的底层 Server API 完全绕过它。
何时改用 Server API
- 渲染实例超过 10K(精灵、网格):使用带 RID 的
RenderingServer,而不是Sprite2D/MeshInstance3D节点。 - 弹幕游戏 / 粒子系统需要脚本交互时:使用
PhysicsServer2D创建物理体,而不是Area2D节点。 - 大规模物理模拟:直接使用
PhysicsServer3D,用于布娃娃场、碎片或类流体模拟。
📊 性能对比:SceneTree 与 Server API
绕过 SceneTree 可以消除节点生命周期管理、信号传播和虚函数(如 _process)带来的大量 CPU 开销。
| 指标 | SceneTree(节点) | Server API(RID) | 专家说明 |
|---|---|---|---|
| 对象上限 | ~1,000 - 5,000 | 50,000+ | SceneTree 遍历开销为 O(n);Server 使用 O(1) 直接 RID 句柄。 |
| 内存开销 | 每个节点约 2KB - 10KB | 每个 RID < 200 bytes | 节点包含树状态、信号和检查器元数据。RID 是不透明的 24-byte 句柄。 |
| CPU 耗时 | 高(虚调用) | 极低(直接 API) | 每个节点实例都必须调用 _process。Server 会在 C++ 中批处理操作。 |
| 线程处理 | 仅主线程 | 天然线程安全 | 大多数 Server API 都是线程安全的(必须在 Project Settings 中启用)。 |
| 垃圾回收 | 自动(RefCounted) | 手动(分配/释放) | Server 需要手动管理生命周期(创建/删除 RID)。 |
专家说明:使用 RID 可以管理原始数据并直接与引擎核心逻辑交互。这是弹幕游戏、大规模植被或复杂程序化模拟的主要“逃生舱”,适用于 SceneTree 的维护工作成为瓶颈的情况。
RID 模式(专家级)
Server API 通过 RID(资源 ID)通信——它是服务器端对象的不透明句柄。关键规则:
# Create server-side canvas item (NO node overhead)
var ci_rid := RenderingServer.canvas_item_create()
RenderingServer.canvas_item_set_parent(ci_rid, get_canvas_item())
# CRITICAL: Keep resource references alive. RIDs don't count as references.
# If the Texture resource is GC'd, the RID becomes invalid silently.
var texture: Texture2D = preload("res://sprite.png")
RenderingServer.canvas_item_add_texture_rect(ci_rid, Rect2(-texture.get_size() / 2, texture.get_size()), texture)
使用 Server API 进行线程处理
- 场景树不是线程安全的。但在 Project Settings 中启用后,Server API(RenderingServer、PhysicsServer)是线程安全的。
- 可以在工作线程上构建场景块(实例化 + add_child),但必须使用
add_child.call_deferred()将其附加到活动场景树。 - GDScript Dictionary/Array:跨线程读写是安全的,但调整大小(append、erase、resize)需要使用
Mutex。 - 绝不要同时从多个线程加载同一个
Resource——请使用一个加载线程。
🧩 第 7 部分:专家级代码模式
常见架构与游戏玩法系统的专家级实现。
- 组件注册表:集中式字典组件检索。
- 安全信号处理器:防止对已释放对象的引用导致崩溃。
- 异步资源加载器:通过线程加载资源。
- 状态机转换守卫:验证状态变更。
- 线程安全分块加载器:底层 server-api 构建。
- 视野锥检测:使用点积和射线检测实现专家级 NPC 视野。
- 声音传播系统:声学遮挡逻辑。
- 潜行隐藏逻辑:全局可见性与隐蔽管理。
🔥 第 8 部分:Godot 4.x 易踩坑点(仅供资深用户)
@export资源默认会共享:多个场景实例会共享同一个Resource。在_ready()中使用resource.duplicate(),或启用“Local to Scene”(场景局部)复选框。这是新手报告最多的 Godot 4 问题。- 信号语法会静默失效:
connect("signal_name", target, "method")(Godot 3 语法)虽然能通过编译,但在 Godot 4 中不起作用。必须使用signal_name.connect(callable)。 Tween不再是 Node:通过create_tween()创建,并绑定到创建节点的生命周期。如果该节点被释放,Tween 也会随之销毁。要创建持久补间,请使用get_tree().create_tween()。PhysicsBody的图层与遮罩:collision_layer=“我是什么”。collision_mask=“我要扫描什么”。将两者设置为相同的值会导致自碰撞或漏检。- 高频路径中的
StringName与String:StringName(&"key")使用指针比较(O(1))。String使用字符比较(O(n))。_process中的字典键始终使用StringName。 @onready的时机:在_init()之后、_ready()期间运行。如果需要在构造时进行设置,请使用_init()。如果需要访问场景树,请使用@onready或_ready()。混用会导致空值。- 服务器查询会造成卡顿:在
_process中调用RenderingServer或PhysicsServer的 getter 函数会强制同步刷新管线。这些服务器以异步方式运行,从它们请求数据会导致整个管线停顿,直到服务器追上进度。 move_and_slide()API 变更:返回bool(是否发生碰撞)。velocity现在是属性,而非参数。调用move_and_slide()前,先执行velocity = dir * speed。
📂 第 9 部分:模块目录(100 个蓝图)
重要
仅加载当前工作流所需的模块。使用第 2 部分中的决策矩阵确定要遵循的链路。
架构与基础
基础 | 组合 | 应用组合 | 信号 | 自动加载 | 状态 | 资源 | 模板 | 分析员 | 审计员 | 构建器 | GDAS-reader | REA
版本升级(外部中心): godot-version-migration — 完整历史路由器(旧版本时期、3→4 桥接、4.0→4.7 跳转);此处未镜像该内容。
GDScript & Testing
GDScript Mastery | Testing Patterns | Debugging/Profiling | Performance Optimization
2D Systems
2D Animation | 2D Physics | Tilemaps | Animation Player | Animation Tree | CharacterBody2D | Particles | Tweening | Shader Basics | Camera Systems
3D Systems
3D Lighting | 3D Materials | 3D World Building | Physics 3D | Navigation/Pathfinding | Procedural Generation | Raycasting
Gameplay Mechanics
Abilities | Combat | Dialogue | Economy | Inventory | Questing | RPG Stats | Turn System | Audio | Scene Transitions | Save/Load | Secrets | Collections | Waves | Harvesting | Time Trials | Revival | Monte Carlo Balancer
UI & UX
UI Containers | Rich Text | Theming | Input Handling | Seasonal Theming | Agent Vision
Connectivity & Platforms
Multiplayer | Server Logic | Export Builds | Desktop | Mobile | Web | Console | VR
Adaptation Guides
- Adapting Desktop -> Mobile
- Adapting Mobile -> Desktop
- Adapting Single -> Multiplayer
- Adapting 2D -> 3D
- Adapting 3D -> 2D
类型蓝图(完整)
动作角色扮演 | 射击游戏 | 第一人称射击游戏 | 即时战略 | 多人在线战术竞技游戏 | Rogue-like | 生存游戏 | 开放世界 | 类银河战士恶魔城 | 平台游戏 | 格斗游戏 | 潜行游戏 | 沙盒游戏 | 恐怖游戏 | 解谜游戏 | 竞速游戏 | 节奏游戏 | 体育游戏 | 大逃杀 | 卡牌游戏 | 视觉小说 | 恋爱游戏 | 模拟游戏 | 塔防游戏 | 放置点击游戏 | 派对游戏 | 教育游戏
🐛 第 10 部分:专家级诊断模式
“不可见节点”错误
症状:节点存在于树中,但没有渲染。
专家诊断链:visible 属性 → z_index → 父级 CanvasLayer 图层错误 → modulate.a == 0 → 位于摄像机 near 裁剪面之后(3D)→ 未设置 SubViewport.render_target_update_mode → CanvasItem 不在任何 CanvasLayer 中(渲染在所有内容之后)。
“输入被吞掉”错误
症状:点击或按键间歇性地被忽略。
专家诊断:另一个 Control 节点的 mouse_filter = STOP,与目标重叠。或者,模态 PopupMenu 正在消耗未处理的输入。或者,另一个脚本中的 _unhandled_input() 调用了 get_viewport().set_input_as_handled()。
“物理抖动”错误
症状:角色在与表面接触时振动。
专家诊断:Safe Margin 过大。或者,使用 _process 而不是 _physics_process 移动(插值不匹配)。或者,生成时碰撞形状重叠(导致它们永久地相互推开)。
“内存泄漏”
症状:游戏运行时 RAM 持续增长。
专家诊断:调用了 queue_free(),但 Array/Dictionary 中仍保留着引用。或者,信号使用 CONNECT_REFERENCE_COUNTED 连接,却没有清理。使用 Profiler 的 “Objects” 选项卡查找孤立实例。搜索没有父级的 Node 实例。
“帧率骤降”
症状:FPS 平稳,但会周期性下降。
专家诊断:GDScript GC 扫描。或者,对大型资源进行同步 load()。或者,NavigationServer 重新烘焙。或者,Server API 查询停顿(在 _process 中向 RenderingServer 请求数据)。使用内置 Profiler 进行分析 → 查找函数级别的尖峰。
🚀 第 11 部分:快速入门 — 从 Unity(C#)到 Godot(GDScript)
从 Unity 生态系统转型的资深工程师需要调整的思维模型。
1. 节点与 GameObject 和组件
在 Unity 中,GameObject 是 Components 的容器。在 Godot 中,一切都是节点。
- Unity:
GameObject+Transform+MeshFilter+Script。 - Godot:一个
MeshInstance3D节点(它本身就是一个 Transform 和 Mesh),并附加一个脚本。 - 专家思维转变:使用节点组合。如果需要“生命值组件”,就添加一个名为 “Health” 的
Node或Area3D作为子节点。对于仅包含逻辑的组件,使用RefCounted以节省内存。
2. 场景是嵌套的预制体
Godot 没有“预制体”,因为每个场景都是一个预制体。
- 可以在一个场景中实例化另一个场景,层层嵌套,深不见底。
- 专家思维转变:每个可复用系统(玩家、敌人、UI 按钮)都应该有自己的
.tscn文件。这有助于实现“后序遍历”(子节点会先于父节点就绪)。
3. 信号与事件/操作
Godot 的 Signal 系统是观察者模式的原生实现。
- Unity:
event Action OnDeath;。 - Godot:
signal died。 - 专家思路转变:信号是一等公民。它们会显示在检查器中,并且可以动态连接或通过编辑器连接。对于全局事件,使用“信号总线”模式(Autoload),以模拟 Unity 的单例管理器。
4. 脚本作为类扩展
将脚本附加到节点时,该脚本就是该节点。
- Unity:
GetComponent<MyScript>()。 - Godot:脚本会扩展节点的类(例如,
extends CharacterBody3D)。 - 专家思路转变:使用类型化 GDScript(
var x: int = 5),以提升编译速度并获得编辑器补全。编译时已知类型的情况下,类型化 GDScript 会使用经过优化的操作码。
5. 内存管理:没有垃圾回收停顿
与可能出现“GC 峰值”的 Unity C# 不同,GDScript 使用引用计数。
- 专家思路转变:对象一旦不再被引用,就会立即释放。这带来确定性的性能,并避免大型 Unity 项目中常见的间歇性“卡顿”。
6. StringNames 与性能
Unity 使用 int 或 Enum 来提升性能。Godot 使用 StringName。
- 专家思路转变:使用
&"name",在字典查找和信号查找中进行常数时间(O(1))的指针比较。