godot-builtin-first · git:20261024.5ffa874 · 2026-10-24 · sha256 814cfa224a6fa168

godot-builtin-first git:20261024.5ffa874A

Immutable. This exact content never changes and is served at /api/v1/blob/814cfa224a6fa168.

---
name: godot-builtin-first
description: 在 Godot 4 项目里动手写任何功能之前先用,看到 project.godot .tscn .gd,或要自己写相机 缓动 状态机 UI 布局 JSON 加载 输入映射 音频池 存档 场景切换 编辑器工具时。先查引擎有没有现成的节点 资源 项目设置,再指向细分 skill。Use before implementing any feature in a Godot 4 project, GDScript or C#.
---

# 先用内置

Godot 的节点、资源和编辑器已经覆盖了大部分游戏功能。自己写之前先确认三件事:版本、内置方案、验证方式。细节去对应的细分 skill。

## 第一步 读项目

```
grep -E 'config/features|run/main_scene|stretch|renderer|physics_engine' project.godot
ls *.csproj *.sln 2>/dev/null
```

- `config/features` 里的版本号决定能用哪些 API。本套 skill 以 4.7.2 为准,标了 `4.5+` 之类的要对照项目版本
- 有 `.csproj` 是 C# 工程,改完先 `dotnet build`
- `rendering/renderer/rendering_method` 决定能用哪些渲染特性,没写这一项就是默认的 Forward+。SDFGI VoxelGI 体积雾只有 Forward+ 有,Mobile 和 Compatibility 都没有

## 第二步 查内置

| 想做 | 用这个 | 去哪个 skill |
| --- | --- | --- |
| 节点树 组件 引用 状态机 | PackedScene、`@export` 节点引用、`%UniqueName`、信号、分组 | godot-scene-architecture |
| 全局状态 跨场景数据 | autoload 只放真全局状态,其余用信号和 `Resource` | godot-scene-architecture godot-resources-data |
| 暂停菜单 场景切换 | `SceneTree.paused` 加 `Node.process_mode`、`change_scene_to_file`、`change_scene_to_packed` | godot-scene-architecture |
| 配置数据 角色数值 关卡定义 | 自定义 `Resource` + `.tres` | godot-resources-data |
| 异步加载 加载界面 | `ResourceLoader.load_threaded_request` | godot-resources-data |
| 存档 | JSON 加 `FileAccess` 写到 `user://`,不 `load()` 玩家可写的 `.tres` | godot-resources-data |
| 设置 | `ConfigFile` 写到 `user://` | godot-resources-data |
| 曲线 渐变色 路径数据 | `Curve`、`Gradient`、`Curve2D`、`Curve3D`,给 shader 用 `CurveTexture`、`GradientTexture1D` | godot-resources-data godot-animation |
| 位移 渐变 一次性过渡 | `Tween` | godot-animation |
| 关键帧动画 角色动画状态 | `AnimationPlayer`、`AnimationTree` | godot-animation |
| 逐帧精灵 | `AnimatedSprite2D` 加 `SpriteFrames` | godot-animation |
| 2D 移动 碰撞 | `CharacterBody2D.move_and_slide`、碰撞层 | godot-2d |
| 拾取 伤害区 触发区 | `Area2D`/`Area3D` 加信号 | godot-2d godot-3d |
| 2D 地图 | `TileMapLayer` | godot-2d |
| 相机跟随 边界 平滑 震屏 | `Camera2D` 的 limit 和 smoothing、`offset` + `FastNoiseLite` | godot-2d |
| 视差背景 | `Parallax2D` | godot-2d |
| 2D 光照 阴影 压暗 | `PointLight2D`、`LightOccluder2D`、`CanvasModulate` | godot-2d |
| 是否在屏幕内 离屏暂停 | `VisibleOnScreenNotifier2D`/`3D`、`VisibleOnScreenEnabler2D`/`3D` | godot-2d godot-3d godot-performance |
| 2D 寻路 | `NavigationRegion2D` 加 `NavigationAgent2D`,格子地图用 `AStarGrid2D` | godot-2d |
| 3D 寻路 避让 | `NavigationRegion3D` 加 `NavigationAgent3D` | godot-3d |
| 3D 角色 光照 GI 导入 | `CharacterBody3D`、`WorldEnvironment`、glTF 导入 | godot-3d |
| 第三人称相机不穿墙 | `SpringArm3D` | godot-3d |
| 3D 射线 范围查询 | `RayCast3D`、`ShapeCast3D`、`PhysicsDirectSpaceState3D.intersect_ray` | godot-3d |
| 头部看向 IK 尾巴摆动 | `LookAtModifier3D`、`SpringBoneSimulator3D`,腿臂 IK 用 `TwoBoneIK3D` 4.6+,都是骨骼修改器 | godot-3d |
| 灰盒关卡 网格拼装 LOD 遮挡剔除 | CSG、`GridMap`、`OccluderInstance3D`、`visibility_range_end` | godot-3d |
| 2D 角色放进 3D 场景 | `Sprite3D` billboard、`SubViewport` | godot-2d-in-3d |
| HD-2D 后处理 景深 雾 | `WorldEnvironment` 的 `Environment` 加 `CameraAttributesPractical` | godot-2d-in-3d godot-3d |
| HUD 菜单 布局 | Container + anchors + 项目级 `Theme` | godot-ui |
| 血条 | `ProgressBar`、`TextureProgressBar` | godot-ui |
| 打字机效果 拖放 悬浮提示 | `RichTextLabel.visible_ratio`、`Control._get_drag_data`、`tooltip_text` | godot-ui |
| 多语言 | `tr()`、翻译 CSV/PO、`TranslationServer` | godot-ui |
| 按键 手柄 改键 | InputMap 动作、`Input.get_vector` | godot-input |
| 音量分组 随机音效 动态音乐 | Audio bus、`AudioStreamRandomizer`、`AudioStreamInteractive` | godot-audio |
| 粒子 | `GPUParticles2D`/`3D` 加 `ParticleProcessMaterial` | godot-shaders-vfx |
| 辉光 雾 色调映射 | `Environment`,2D 另需 `rendering/viewport/hdr_2d` | godot-shaders-vfx godot-2d |
| 描边 溶解 闪白 | 先看 `StandardMaterial3D`、`CanvasItemMaterial` 的属性,再写 shader | godot-shaders-vfx |
| 编辑数据的工具 | `@tool`、`EditorPlugin`、Inspector 编辑 Resource | godot-editor-tooling |
| 大量同类物体 线程 卡顿 | `MultiMeshInstance2D`/`3D`、`WorkerThreadPool`、Profiler | godot-performance |
| 延时 周期 数值靠近目标 | `Timer`、`create_timer`、`move_toward`、`lerp` | godot-gdscript |
| 改完自己验证 | `godot --headless` 加载与冒烟场景 | godot-headless-testing |
| GDScript 写法 | 静态类型 信号 await | godot-gdscript |
| C# 写法 | 源码生成器 `StringName` 缓存 生命周期 | godot-csharp |

表里没有的需求,先在类参考里搜关键词:

```
grep -ril '<关键词>' <godot源码>/doc/classes | head
```

或者打开 `https://docs.godotengine.org/en/stable/classes/class_<小写类名>.html`。

## 第三步 验证

写完至少做到:

- GDScript:新增 `class_name` 或资源后先 `godot --headless --path . --import`,再对每个改动的脚本 `godot --headless --path . --check-only -s x.gd`
- C#:`dotnet build` 无错误
- 改到运行时行为:写一个冒烟场景无头跑几帧并断言,见 godot-headless-testing

判失败不能只看退出码。`--import` 打开工程后退出码恒为 0,导入错误和脚本语法错误都一样,运行时 `SCRIPT ERROR` 和 `--quit-after` 到点也是 0。每条命令的输出都要 grep `SCRIPT ERROR|Parse Error|^ERROR:`,有就算失败。现成的 `gdrun` 函数和退出码表见 godot-headless-testing。

不确定某个方法是否存在时,不要猜,查:

```
mkdir -p /tmp/godot-doc
godot --headless --doctool /tmp/godot-doc
grep -l 'name="move_and_slide"' /tmp/godot-doc/doc/classes/*.xml
```

导出的 XML 说明文字是空的,只能确认名字和签名。要看行为说明去类参考网页,或者在脚本里用 `ClassDB.class_has_method`。

## 什么时候可以自己写

内置方案不满足硬约束时才自研,并在代码里留一条注释写明约束:

- 锁步联机或回放要逐帧复现:内置物理不保证确定性,官方物理介绍页明确写了无论哪个物理引擎都一样。模拟用自己的定点数和计时,表现层再用内置节点
- 要按任意帧 seek 重算表现:`Tween` 没有 seek,`custom_step` 只能向前推,`AnimationPlayer.seek` 可以跳到任意秒,先试它
- profiler 证明内置节点是瓶颈:大量子弹改用 `PhysicsServer2D` 和 `RenderingServer`,自己管 RID 释放,先试 `MultiMesh` 和对象池,见 godot-performance

## 陷阱

- 网上大量教程是 Godot 3,`KinematicBody2D`、`yield`、`export var`、`onready var`、`instance()` 都是旧写法
- `TileMap`、`ParallaxBackground`、`ParallaxLayer` 在 4.7 已弃用,新代码用 `TileMapLayer`、`Parallax2D`
- 代码里 `new` 一整棵节点树会让场景在编辑器里不可见不可调,能做成 `.tscn` 的就做成 `.tscn`
- 静态字段或字典缓存 `Texture2D`、`Material` 会持有强引用,资源不随引用归零释放,而且 `ResourceLoader` 已经按路径缓存