关于 godot
godot 是面向 LLM 编码助手的 Godot Engine 游戏与应用开发技能,重点涵盖场景和资源文件格式、验证、架构模式、模板及测试流程。
主要功能
- 01.gd、.tscn 和 .tres 文件指导
- 02.tscn 与 .tres 验证脚本
- 03组件化与信号驱动模式
- 04可复用代码和资源模板
- 05GUT 单元测试指导
适用场景
- 01创建或编辑 Godot 场景与资源
- 02排查资源加载和语法错误
- 03构建组件化游戏系统
- 04使用 GUT 测试游戏逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bfollington/ terma --skill godot安装后在 Claude Code 中输入/godot确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/templates/attribute_template.gdcomponent_template.gdinteraction_template.gditem_resource.tresspell_resource.tresreferences/architecture-patterns.mdcommon-pitfalls.mdfile-formats.mdgodot4-physics-api.mdscripts/validate_tres.pyvalidate_tscn.py详细介绍
Godot Engine 开发技能
专为使用 Godot Engine 开发游戏和应用提供的指导,重点关注 LLM 编码助手与 Godot 独特文件结构之间的高效协作。
概述
Godot 项目使用 GDScript 代码文件(.gd)和基于文本的资源文件(场景使用 .tscn,资源使用 .tres)。GDScript 简单易用,但资源文件有严格的格式要求,与 GDScript 语法有显著差异。本技能提供文件格式专业知识、经过验证的架构模式、验证工具、代码模板和调试工作流,助力高效开发 Godot 项目。
何时使用本技能
在以下情况调用本技能:
- 处理任何 Godot Engine 项目
- 创建或修改 .tscn(场景)或 .tres(资源)文件
- 实现游戏系统(交互、属性、法术、物品栏等)
- 调试“文件加载失败”或类似的资源错误
- 设置基于组件的架构
- 创建信号驱动系统
- 实现基于资源的数据(物品、法术、技能)
关键原则
1. 了解文件格式差异
GDScript(.gd)——完整的编程语言:
extends Node
class_name MyClass
var speed: float = 5.0
const MAX_HEALTH = 100
func _ready():
print("Ready")
场景文件(.tscn)——严格的序列化格式:
[ext_resource type="Script" path="res://script.gd" id="1"]
[node name="Player" type="CharacterBody3D"]
script = ExtResource("1") # NOT preload()!
资源文件(.tres)——不支持 GDScript 语法:
[ext_resource type="Script" path="res://item.gd" id="1"]
[resource]
script = ExtResource("1") # NOT preload()!
item_name = "Sword" # NOT var item_name = "Sword"!
2. .tres 和 .tscn 文件的关键规则
在 .tres/.tscn 文件中绝对不要使用:
preload()——改用ExtResource("id")var、const、func——这些是 GDScript 关键字- 未指定类型的数组 ——使用
Array[Type]([...])语法
在 .tres/.tscn 文件中始终使用:
- 外部资源使用
ExtResource("id") - 内联资源使用
SubResource("id") - 类型化数组:
Array[Resource]([...]) - 使用前先正确声明 ExtResource
3. 分离关注点
将逻辑放在 .gd 文件中,将数据放在 .tres 文件中:
src/
spells/
spell_resource.gd # Class definition + logic
spell_effect.gd # Effect logic
resources/
spells/
fireball.tres # Data only, references scripts
ice_spike.tres # Data only
这样可以让 LLM 编辑更安全、更清晰。
4. 基于组件的架构
将功能拆分为小型、专注的组件:
Player (CharacterBody3D)
├─ HealthAttribute (Node) # Component
├─ ManaAttribute (Node) # Component
├─ Inventory (Node) # Component
└─ StateMachine (Node) # Component
├─ IdleState (Node)
├─ MoveState (Node)
└─ AttackState (Node)
优点:
- 每个组件都是小型、专注的文件
- 易于理解和修改
- 职责明确
- 可在不同实体之间复用
5. 信号驱动通信
使用信号实现松耦合:
# Component emits signals
signal health_changed(current, max)
signal death()
# Parent connects to signals
func _ready():
$HealthAttribute.health_changed.connect(_on_health_changed)
$HealthAttribute.death.connect(_on_death)
优点:
- 系统之间没有紧密耦合
- 易于添加新的监听器
- 自说明(信号会显示可用事件)
- 无需修改游戏逻辑,UI 就能连接信号
使用捆绑资源
验证脚本
在 Godot 中测试之前,先验证 .tres 和 .tscn 文件,以便及早发现语法错误。
验证 .tres 文件:
python3 scripts/validate_tres.py resources/spells/fireball.tres
验证 .tscn 文件:
python3 scripts/validate_tscn.py scenes/player/player.tscn
在以下情况使用这些脚本:
- 以编程方式创建或编辑 .tres/.tscn 文件后
- 调试“加载失败”错误时
- 提交场景/资源变更前
- 用户报告自定义资源存在问题时
参考文档
需要详细信息时,加载参考文件:
references/file-formats.md ——深入介绍 .gd、.tscn、.tres 语法:
- 各类文件的完整语法规则
- 常见错误及示例
- 安全与高风险编辑模式
- ExtResource 和 SubResource 的用法
references/architecture-patterns.md ——经过验证的架构模式:
- 基于组件的交互系统
- 属性系统(生命值、法力值等)
- 基于资源的效果系统(法术、物品)
- 物品栏系统
- 状态机模式
- 组合使用多种模式的示例
在以下情况阅读这些参考资料:
- 实现新的游戏系统时
- 不确定 .tres/.tscn 语法时
- 调试文件格式错误时
- 为新功能规划架构时
代码模板
使用模板作为常见模式的起点。模板位于 assets/templates/:
component_template.gd - 包含信号、导出变量和激活逻辑的基础组件:
# Copy and customize for new components
cp assets/templates/component_template.gd src/components/my_component.gd
attribute_template.gd - 数值属性(生命值、法力值、耐力):
# Use for any numeric attribute with min/max
cp assets/templates/attribute_template.gd src/attributes/stamina_attribute.gd
interaction_template.gd - 交互组件基类:
# Extend for custom interactions (pickup, door, switch, etc.)
cp assets/templates/interaction_template.gd src/interactions/lever_interaction.gd
spell_resource.tres - 包含效果的法术示例:
# Use as reference for creating new spell data
cat assets/templates/spell_resource.tres
item_resource.tres - 物品资源示例:
# Use as reference for creating new item data
cat assets/templates/item_resource.tres
工作流
工作流 1:创建新的组件系统
示例:为敌人添加生命值系统。
步骤:
-
阅读架构模式参考:
# Check for similar patterns Read references/architecture-patterns.md # Look for "Attribute System" section -
使用模板创建基类:
cp assets/templates/attribute_template.gd src/attributes/attribute.gd # Customize the base class -
创建专用子类:
# Create health_attribute.gd extending attribute.gd # Add health-specific signals (damage_taken, death) -
通过编辑 .tscn 将其添加到场景中:
[ext_resource type="Script" path="res://src/attributes/health_attribute.gd" id="4_health"] [node name="HealthAttribute" type="Node" parent="Enemy"] script = ExtResource("4_health") value_max = 50.0 value_start = 50.0 -
立即在 Godot 编辑器中测试
-
如果出现问题,验证场景文件:
python3 scripts/validate_tscn.py scenes/enemies/base_enemy.tscn
工作流 2:创建资源数据文件(.tres)
示例:创建新的法术。
步骤:
-
参考模板:
cat assets/templates/spell_resource.tres -
按正确结构创建新的 .tres 文件:
[gd_resource type="Resource" script_class="SpellResource" load_steps=3 format=3] [ext_resource type="Script" path="res://src/spells/spell_resource.gd" id="1"] [ext_resource type="Script" path="res://src/spells/spell_effect.gd" id="2"] [sub_resource type="Resource" id="Effect_1"] script = ExtResource("2") effect_type = 0 magnitude_min = 15.0 magnitude_max = 25.0 [resource] script = ExtResource("1") spell_name = "Fireball" spell_id = "fireball" mana_cost = 25.0 effects = Array[ExtResource("2")]([SubResource("Effect_1")]) -
测试前进行验证:
python3 scripts/validate_tres.py resources/spells/fireball.tres -
修复验证器报告的所有错误
-
在 Godot 编辑器中测试
工作流 3:调试资源加载问题
当用户报告“资源加载失败”或类似错误时。
步骤:
-
阅读错误中指出的文件:
# Check file syntax Read resources/spells/problem_spell.tres -
运行验证脚本:
python3 scripts/validate_tres.py resources/spells/problem_spell.tres -
检查常见错误:
- 使用
preload()而不是ExtResource() - 使用
var、const、func关键字 - 缺少 ExtResource 声明
- 数组语法不正确(未指定类型)
- 使用
-
如有需要,阅读文件格式参考:
Read references/file-formats.md # Focus on "Resource Files (.tres)" section # Check "Common Mistakes Reference" -
修复错误并重新验证
工作流 4:根据架构模式实现功能
实现已知模式(交互系统、状态机等)时。
步骤:
-
阅读相关模式:
Read references/architecture-patterns.md # Find the specific pattern (e.g., "Component-Based Interaction System") -
复制相关模板:
cp assets/templates/interaction_template.gd src/interactions/door_interaction.gd -
自定义模板:
- 重写
_perform_interaction() - 添加用于配置的自定义导出变量
- 如有需要,添加自定义信号
- 重写
-
按照模式创建场景结构:
[node name="Door" type="StaticBody3D"] script = ExtResource("base_interactable.gd") [node name="DoorInteraction" type="Node" parent="."] script = ExtResource("door_interaction.gd") interaction_text = "Open Door" -
逐步测试
使用 GUT 进行单元测试
使用 GUT(Godot 单元测试)测试纯逻辑——任何不依赖场景树的 RefCounted 或 Resource 类都适合作为测试对象。例如卡牌系统、计分、状态机、地图生成器、挑战逻辑等。
安装
- 从 GitHub releases 下载(v9.5.0 适用于 Godot 4.5;v9.6.0+ 需要更新版本的 Godot)
- 将
addons/gut/放入项目中 - 在“项目设置” →“插件”中启用插件
- 在项目根目录创建
.gutconfig.json:
{
"dirs": ["res://test/unit"],
"prefix": "test_",
"suffix": ".gd",
"log_level": 1
}
编写测试
测试文件位于 test/unit/,文件名以 test_ 开头,并继承 GutTest:
extends GutTest
func test_score_calculation() -> void:
var scoring := Scoring.new()
assert_eq(scoring.calculate(3, 0), 100, "Base score for 3 moves")
assert_gt(scoring.calculate(2, 0), scoring.calculate(3, 0), "Fewer moves = higher score")
func test_deck_shuffle() -> void:
var rng := RandomNumberGenerator.new()
rng.seed = 42
var deck := CardSystem.create_shuffled_deck(rng)
assert_eq(deck.size(), 52, "Full deck")
主要约定:
- 测试方法必须以
test_开头 - 辅助方法使用
_前缀(不会被识别为测试) - 使用
before_each()/after_each()进行设置和清理 - 关键断言:
assert_eq、assert_ne、assert_true、assert_false、assert_gt、assert_lt、assert_null、assert_not_null
运行测试
# Run all tests (returns exit code 0 on pass, 1 on fail)
godot -d -s --path "$PWD" addons/gut/gut_cmdln.gd -gexit
# Run a specific test file
godot -d -s --path "$PWD" addons/gut/gut_cmdln.gd -gtest=res://test/unit/test_scoring.gd -gexit
# Run tests matching a pattern
godot -d -s --path "$PWD" addons/gut/gut_cmdln.gd -gdir=res://test/unit -gselect=weekly -gexit
测试内容
优先测试继承自 RefCounted 或 Resource 的纯逻辑类:
- 游戏规则和计分
- 卡牌/牌组/手牌管理
- 地图生成(验证属性,而非精确输出)
- 状态快照/恢复
- 升级/进度计算
避免在单元测试中测试依赖场景树的代码(渲染、UI、输入处理)。
常见问题与解决方案
问题 1:在 .tres 文件中使用 GDScript 语法
问题:
# ❌ WRONG
script = preload("res://script.gd")
var items = [1, 2, 3]
解决方案:
# ✅ CORRECT
[ext_resource type="Script" path="res://script.gd" id="1"]
script = ExtResource("1")
items = Array[int]([1, 2, 3])
预防: 测试前运行验证脚本。
问题 2:缺少 ExtResource 声明
问题:
[resource]
script = ExtResource("1_script") # Not declared!
解决方案:
[ext_resource type="Script" path="res://script.gd" id="1_script"]
[resource]
script = ExtResource("1_script")
检测: 验证脚本会检测到此问题。
陷阱 3:编辑复杂的 .tscn 层级结构
问题: 修改实例化场景的子节点可能会在编辑器重新保存时出错。
解决方案:
- 只在 .tscn 文件中修改简单属性
- 复杂修改请使用 Godot 编辑器
- 文本编辑后立即测试
- 使用 git 跟踪更改,并在需要时还原
陷阱 4:.tres 文件中的未类型化数组
问题:
effects = [SubResource("Effect_1")] # Missing type
解决方案:
effects = Array[Resource]([SubResource("Effect_1")])
预防: 验证脚本会对此发出警告。
陷阱 5:忘记覆盖实例属性
问题: 实例化场景时,忘记覆盖子节点属性。实例会使用默认值(通常为 null),导致难以察觉的错误。
# level.tscn
[node name="KeyPickup" parent="." instance=ExtResource("6_pickup")]
# Oops! PickupInteraction.item_resource is null - pickup won't work!
解决方案: 始终使用 index 语法配置实例化场景的属性:
[node name="KeyPickup" parent="." instance=ExtResource("6_pickup")]
[node name="PickupInteraction" parent="KeyPickup" index="0"]
item_resource = ExtResource("7_key")
检测:
- 立即在游戏中测试该实例
- 阅读
references/file-formats.md中的“实例属性覆盖”部分,了解详情 - 创建场景实例时,先问自己:“此场景是否有需要设置属性的可配置组件?”
预防: 实例化任何带有可配置子节点(PickupInteraction、DoorInteraction 等)的场景后,始终确认关键属性已被覆盖。
陷阱 6:CPUParticles3D 的 color_ramp 不显示颜色
问题: 为 CPUParticles3D 设置了 color_ramp,但粒子仍呈白色或不显示渐变颜色。
[node name="CPUParticles3D" type="CPUParticles3D" parent="."]
mesh = SubResource("SphereMesh_1")
color_ramp = SubResource("Gradient_1") # Gradient is set but doesn't work!
根本原因: 网格需要使用 vertex_color_use_as_albedo = true 的材质,才能将粒子颜色应用到网格表面。
解决方案: 为网格添加启用了顶点颜色的 StandardMaterial3D:
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
vertex_color_use_as_albedo = true
[sub_resource type="SphereMesh" id="SphereMesh_1"]
material = SubResource("StandardMaterial3D_1")
radius = 0.12
height = 0.24
[node name="CPUParticles3D" type="CPUParticles3D" parent="."]
mesh = SubResource("SphereMesh_1")
color_ramp = SubResource("Gradient_1") # Now works!
预防: 创建带有 color 或 color_ramp 的 CPUParticles3D 时,始终为网格添加 vertex_color_use_as_albedo = true 的材质。
最佳实践
1. 查阅常见问题参考文档
遇到问题时,请查阅参考文档:
references/common-pitfalls.md - 常见的 Godot 易错点及解决方案:
- 初始化和 @onready 时序问题
- 节点引用和 get_node() 问题
- 信号连接问题
- 资源加载和修改
- CharacterBody3D 移动
- 变换和基向量混淆
- 输入处理
- 类型安全问题
- 场景实例化陷阱
- Tween 问题
references/godot4-physics-api.md - 物理 API 速查:
- 正确的射线检测 API(
PhysicsRayQueryParameters3D) - 形状查询和碰撞检测
- 碰撞层和遮罩
- Area3D、RigidBody3D 与 CharacterBody3D 的区别
- 常见物理模式
- 性能提示
遇到以下情况时,请加载这些文档:
- 出现空引用错误
- 实现物理/碰撞系统
- 调试 @onready 时序问题
- 使用 CharacterBody3D 移动
2. 编辑 .tres/.tscn 后务必验证
python3 scripts/validate_tres.py path/to/file.tres
python3 scripts/validate_tscn.py path/to/file.tscn
2. 使用模板作为起点
不要从头编写组件,而应改编模板:
cp assets/templates/component_template.gd src/my_component.gd
3. 查阅参考文档了解详细语法
不确定语法时,请加载参考文档:
Read references/file-formats.md
4. 遵循关注点分离
- 逻辑 → .gd 文件
- 数据 → .tres 文件
- 场景结构 → .tscn 文件(复杂修改优先使用编辑器)
5. 使用信号进行通信
优先使用信号,而不是直接调用方法:
# ✅ Good - Loose coupling
signal item_picked_up(item)
item_picked_up.emit(item)
# ❌ Avoid - Tight coupling
get_parent().get_parent().add_to_inventory(item)
6. 增量测试
每次更改后:
- 使用脚本验证
- 在 Godot 编辑器中测试
- 验证功能
- 提交到 git
7. 多使用导出变量
让配置清晰可见且可编辑:
@export_group("Movement")
@export var speed: float = 5.0
@export var jump_force: float = 10.0
@export_group("Combat")
@export var damage: int = 10
使用 Godot 命令行工具
可使用 godot 命令行工具运行游戏并执行各种操作,无需打开编辑器。
运行游戏
运行当前项目:
godot --path . --headless
运行指定场景:
godot --path . --scene scenes/main_menu.tscn
使用调试标志运行:
# Show collision shapes
godot --path . --debug-collisions
# Show navigation debug visuals
godot --path . --debug-navigation
# Show path lines
godot --path . --debug-paths
检查/验证代码
检查 GDScript 语法,但不运行:
godot --path . --check-only --script path/to/script.gd
运行无头测试(用于自动化测试):
godot --path . --headless --quit --script path/to/test_script.gd
两个看起来像真实错误的无头模式陷阱
新建的 class_name 在重新导入项目前无法通过 --check-only。 无头检查会从项目缓存的类列表中解析全局类,而该列表尚未包含你刚创建的脚本。表现出来的是一个看似确凿、实则错误的解析错误:
Parse Error: Identifier "MyNewClass" not declared in the current scope
修复一次,然后重新检查:
godot --path . --import --headless --quit
在充满 static func 工具类的代码库中,这个问题最棘手:新类型会同时在多个文件中被引用,错误看起来就像确实缺少依赖项。
沙盒化 Agent shell 中的无头 Godot 崩溃或挂起。 如果进程无法写入 user://logs/...,就会因 handle_crash: Program crashed with signal 11 退出,或因 XPC Connection Invalid 而挂起——测试运行器设置的超时会将其变成空输出和非零退出码。这两种情况看起来都像被测代码中的真实缺陷,也会按真实缺陷来调试;但问题其实只是文件系统访问被拒。应在首次启动时就禁用沙盒运行 Godot,而不是等出现令人困惑的回溯后再处理;也要提前告知子 Agent——它们会各自独立遇到这个问题,每个都会因此浪费同样的半小时。
通过 CLI 执行编辑器操作
不打开编辑器导入资源:
godot --path . --import --headless --quit
导出项目:
# Export release build
godot --path . --export-release "Preset Name" builds/game.exe
# Export debug build
godot --path . --export-debug "Preset Name" builds/game_debug.exe
常见 CLI 工作流
工作流:快速运行测试
# Run the project and quit after testing
godot --path . --quit-after 300 # Runs for 300 frames then quits
工作流:自动导入资源
# Import all resources and exit (useful in CI/CD)
godot --path . --import --headless --quit
工作流:脚本验证
# Validate a GDScript file before committing
godot --path . --check-only --script src/player/player.gd
工作流:无头服务器
# Run as dedicated server (no rendering)
godot --path . --headless --scene scenes/multiplayer_server.tscn
CLI 使用技巧
- 从项目目录运行时,始终指定
--path .,确保 Godot 能找到project.godot - 在 CI/CD 和自动化测试中使用
--headless(不显示窗口、不渲染) - 使用
--quit或--quit-after N,在任务完成后自动退出 - 将
--check-only与--script搭配使用,快速验证 GDScript 语法 - 使用调试标志(
--debug-collisions、--debug-navigation),在开发时可视化系统 - 检查退出码——非零表示存在错误(对 CI/CD 脚本很有用)
示例:用于验证 GDScript 的提交前钩子
#!/bin/bash
# Validate all changed .gd files before committing
for file in $(git diff --cached --name-only --diff-filter=ACM | grep '\.gd$'); do
if ! godot --path . --check-only --script "$file" --headless --quit; then
echo "GDScript validation failed for $file"
exit 1
fi
done
快速参考
文件类型决策树
编写游戏逻辑? → 使用 .gd 文件
存储数据(物品属性、法术配置)? → 使用 .tres 文件
创建场景结构? → 使用 .tscn 文件(复杂结构优先使用 Godot 编辑器)
语法快速检查
在 .gd 文件中: 完整的 GDScript——var、func、preload() 等 ✅
在 .tres/.tscn 文件中:
preload()❌ → 使用ExtResource("id")✅var、const、func❌ → 仅使用属性值 ✅[1, 2, 3]❌ → 使用Array[int]([1, 2, 3])✅
各验证脚本的适用场景
validate_tres.py——用于资源文件:
- 物品、法术、技能
- 自定义资源数据
- 创建 .tres 文件后
validate_tscn.py——用于场景文件:
- 玩家、敌人、关卡
- UI 场景
- 编辑 .tscn 文件后
各参考文档的适用场景
file-formats.md——适用于:
- 创建或编辑 .tres/.tscn 文件
- 遇到“failed to load”错误
- 不确定语法规则
architecture-patterns.md——适用于:
- 实现新的游戏系统
- 规划组件结构
- 查找经过验证的模式
总结
通过以下方式高效处理 Godot 项目:
- 理解文件格式——.gd 是代码,.tres/.tscn 是遵循严格语法的数据
- 使用验证工具——在测试前发现错误
- 遵循模式——使用参考资料中的成熟架构
- 从模板开始——在现有基础上调整,而不是从头创建
- 增量测试——频繁验证、测试和提交
关键在于:只要遵循 GDScript 与资源序列化格式之间的语法差异,Godot 的基于文本的文件就很适合大模型处理。