关于 gdextension
面向通过 GDExtension 添加原生 C++ 或 Rust 代码的 Godot 开发者,无需重新编译引擎。内容涵盖类绑定、共享库构建,以及从 GDScript 和 C# 使用扩展。
主要功能
- 01原生 C++ 或 Rust 共享库
- 02绑定方法、属性和信号
- 03GDExtension 构建与入口设置
- 04引擎版本兼容性指引
- 05GDScript 和 C# 使用模式
适用场景
- 01优化经过性能分析的关键代码
- 02调用现有 C/C++ 库
- 03为 Godot 创建语言绑定
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill gdextension安装后在 Claude Code 中输入/gdextension确认已加载。
附带文件references/debugging-native.mdreferences/rust-gdext.md
详细介绍
GDExtension
在 Godot 中以共享库的形式运行原生 C++(或 Rust),无需重新编译引擎。可用于性能关键型代码、封装现有 C/C++ 库,或实现语言绑定。
相关技能: 如果 C# 已足够,请参阅 csharp-godot;先了解 GDScript 性能惯用法,请参阅 gdscript-advanced;在使用原生代码前进行性能分析,请参阅 godot-optimization;分发成果,请参阅 addon-development;发布二进制文件,请参阅 export-pipeline。
1. 何时使用 GDExtension
几乎所有游戏逻辑都应使用 GDScript 或 C#。只有确实需要时才选择 GDExtension:
- 在 GDScript/C# 无法胜任的热点循环中实现原生速度(先进行性能分析——参见 godot-optimization)。
- 封装必须直接调用的 C/C++ 库。
- 构建语言绑定。
与之相对的是 C++ 模块:它们会被编译进引擎,因此需要发布自定义引擎二进制文件。GDExtension 的主要优势在于,它能在标准版 Godot 上运行——你只需分发一个共享库。它“比 GDScript 和 C# 更复杂”,因此不要默认选择它。
⚠️ Godot 4.7 中的变更: 引擎内置的文本服务器(
text_server_adv、text_server_fb)不再能构建为 GDExtension——它们的gdextension_build/脚本已被移除。通过继承TextServerExtension编写自己的 GDExtension 文本服务器不受影响。参见 GH-117056。
2. 项目与构建设置
mkdir gdextension_example && cd gdextension_example
git init
# IMPORTANT: use the godot-cpp branch matching your target engine version (e.g. 4.3),
# not the literal "4.x".
git submodule add -b 4.3 https://github.com/godotengine/godot-cpp
cd godot-cpp && git submodule update --init && cd ..
目录结构:
gdextension_example/
├── project/ # demo project to test the extension
│ └── bin/example.gdextension
├── godot-cpp/ # C++ bindings (submodule)
└── src/
├── register_types.{h,cpp}
└── gdexample.{h,cpp}
使用 scons platform=<platform> 进行构建(省略平台即可面向当前平台;默认构建为调试版)。官方 SConstruct 是可从 C++ 教程下载的文件,而非在此手动编写——请遵循 godot-cpp 的构建文档。SCons 是官方推荐方式;godot-cpp 也支持 CMake。
Godot 4.7+: 上游参考 GDExtension 接口文件(例如
gdextension_interface.h)现在位于 godot-headers 仓库中,而不再位于 godot-cpp(GH-115401)。godot-cpp 会从该仓库使用这些文件,因此上述子模块工作流保持不变——只有在直接引入原始接口头文件时(例如用于自定义语言绑定)才需要关注这一点。
3. 绑定类(C++)
头文件(gdexample.h):
#pragma once
#include <godot_cpp/classes/sprite2d.hpp>
namespace godot {
class GDExample : public Sprite2D {
GDCLASS(GDExample, Sprite2D)
private:
double time_passed = 0.0;
double amplitude = 10.0;
double speed = 1.0;
protected:
static void _bind_methods();
public:
void _process(double delta) override;
void set_amplitude(double p_amplitude);
double get_amplitude() const;
void set_speed(double p_speed);
double get_speed() const;
};
}
绑定(gdexample.cpp — _bind_methods):
void GDExample::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");
ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"),
"set_speed", "get_speed");
ADD_SIGNAL(MethodInfo("position_changed",
PropertyInfo(Variant::OBJECT, "node"),
PropertyInfo(Variant::VECTOR2, "new_pos")));
}
相关模式:
GDCLASS(Class, Parent)— 每个原生类主体的首行;将类型接入 Godot 的ClassDB。ClassDB::bind_method(D_METHOD("name", "arg"), &Class::method)— 暴露方法(并命名其参数),以便 GDScript/C#/编辑器调用。ADD_PROPERTY(PropertyInfo(...), setter, getter)— 注册 Inspector 属性;先绑定 getter 和 setter,再在此处按名称引用它们。PROPERTY_HINT_RANGE配合"0,20,0.01"可将 Inspector 字段变为滑块(最小值、最大值、步长)。ADD_SIGNAL(MethodInfo("name", PropertyInfo(...), ...))— 声明带类型参数的信号;在代码中使用emit_signal("position_changed", this, new_pos)发出信号。
⚠️ Godot 4.7 中的变更: GDExtension 接口函数
object_cast_to和classdb_get_class_tag已弃用,推荐改用基于is_class的类型转换。godot-cpp 等绑定库会在内部处理此事,但直接调用这些接口函数的原生代码应迁移其类型转换路径。参见 GH-119254。
4. 入口点与 .gdextension 文件
入口点(register_types.cpp):
void initialize_example_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
GDREGISTER_CLASS(GDExample);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
}
extern "C" {
GDExtensionBool GDE_EXPORT example_library_init(
GDExtensionInterfaceGetProcAddress p_get_proc_address,
const GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_example_module);
init_obj.register_terminator(uninitialize_example_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}
.gdextension 文件(project/bin/example.gdextension):
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.3"
reloadable = true
[libraries]
macos.debug = "res://bin/libgdexample.macos.template_debug.dylib"
macos.release = "res://bin/libgdexample.macos.template_release.dylib"
windows.debug.x86_64 = "res://bin/gdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/gdexample.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
导出的 extern "C" 符号名必须与 entry_symbol 相同,否则扩展将无法加载。使用 GDREGISTER_CLASS 注册类,并确保其受 MODULE_INITIALIZATION_LEVEL_SCENE 限制。[libraries] 的键是 platform.feature.arch 标签;template_debug / template_release 用于区分构建配置。可选部分:[icons](每个节点的编辑器图标)和 [dependencies](导出时复制的额外库)。
**Godot 4.7+:**原始 GDExtension 接口新增了支持引用计数的构造和注册入口——
classdb_construct_object3和classdb_register_extension_class6(GH-118214)。使用 4.7 头文件构建的绑定库会自动使用这些入口;它们仅与直接调用该接口的代码有关。
5. 兼容性规则
向前兼容,但不向后兼容。针对 4.2 的扩展可在 4.3 中运行,但针对 4.3 的扩展无法在 4.2 中加载。**例外:**针对 4.0 的扩展无法在 4.1 及更高版本中运行。
- godot-cpp 分支必须与构建所针对的引擎版本匹配。
reloadable = true热重载仅在编辑器中有效——导出的游戏永远不会重新加载。- 必须设置
compatibility_minimum:将其设为你实际支持的最低引擎版本。较旧的引擎会拒绝加载该扩展,低于4.1的值也会被拒绝。 - 导出的游戏必须包含匹配的
template_release二进制文件,否则运行时将不存在该原生节点类型。
⚠️ Godot 4.7 中的变更:
Object.is_class()的class参数类型从String改为StringName,以提升性能。GDScript 不受影响,C# 新增了兼容方法,但使用旧签名编译的 GDExtension 二进制文件依赖引擎的兼容性映射——更新到 4.7 时,请使用与目标版本匹配的绑定重新构建。详见 4.7 迁移指南。
6. 在 GDScript 和 C# 中使用
构建并放置 .gdextension 文件后,原生类会作为普通节点类型显示:绑定的属性会出现在检查器中(范围提示会显示为滑块),信号会出现在节点面板中。
GDScript
extends Node
func _ready():
var node := GDExample.new()
node.speed = 2.0
node.position_changed.connect(_on_position_changed)
add_child(node)
func _on_position_changed(node, new_pos):
print("%s is now at %s" % [node.get_class(), new_pos])
C# 等效代码
using Godot;
public partial class Demo : Node
{
public override void _Ready()
{
// No C# type exists for a GDExtension class: create it by name.
var node = ClassDB.Instantiate("GDExample").As<Node>();
node.Set("speed", 2.0);
node.Connect("position_changed", Callable.From<Node, Vector2>(OnPositionChanged));
AddChild(node);
}
private void OnPositionChanged(Node node, Vector2 newPos)
=> GD.Print($"{node.GetClass()} is now at {newPos}");
}
如需获得强类型的 C# 包装器,可以随扩展一起提供 C# 胶水类,但也可以通过上面展示的动态 Set / Connect / Call API 完整使用该扩展。
其他语言与调试:Rust (gdext) · 调试原生代码
实现检查清单
- 已确认确实需要原生代码(已进行性能分析;GDScript/C# 无法满足需求——参见 godot-optimization)
- godot-cpp 子模块位于与目标引擎版本匹配的分支
-
_bind_methods绑定了所有公开的方法/属性/信号 -
.gdextension中的entry_symbol与导出的extern "C"符号匹配 -
compatibility_minimum已设为支持的最低引擎版本 - [libraries] 为每个发布的平台/架构设置了正确路径(调试版 + 发布版)
- 发布导出包含
template_release二进制文件