mcpField
G
gdextension

gdextension

github.com/jame581开发889152 次安装4 天前更新
代码仓库

关于 gdextension

面向通过 GDExtension 添加原生 C++ 或 Rust 代码的 Godot 开发者,无需重新编译引擎。内容涵盖类绑定、共享库构建,以及从 GDScript 和 C# 使用扩展。

主要功能

  1. 01原生 C++ 或 Rust 共享库
  2. 02绑定方法、属性和信号
  3. 03GDExtension 构建与入口设置
  4. 04引擎版本兼容性指引
  5. 05GDScript 和 C# 使用模式

适用场景

  1. 01优化经过性能分析的关键代码
  2. 02调用现有 C/C++ 库
  3. 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 二进制文件

评论

支持 Markdown