gdextension について
エンジンを再ビルドせずにGDExtensionでネイティブC++またはRustコードを追加するGodot開発者向けスキルです。クラスのバインド、共有ライブラリのビルド、GDScriptやC#からの利用を扱います。
主な機能
- 01ネイティブC++またはRustの共有ライブラリ
- 02メソッド、プロパティ、シグナルのバインド
- 03GDExtensionのビルドとエントリーポイント設定
- 04エンジンバージョンの互換性指針
- 05GDScriptとC#からの利用パターン
活用シーン
- 01性能計測済みの重要コードの高速化
- 02既存のC/C++ライブラリの呼び出し
- 03Godot向け言語バインディングの作成
インストール
コマンドをコピーしてターミナルで実行します。
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> でビルドします(現在のプラットフォームを対象にする場合はプラットフォームを省略します。デフォルトのビルドは debug です)。公式の SConstruct はここで手作業で作成するものではなく、C++チュートリアルからダウンロードできるファイルです。godot-cppのビルドドキュメントに従ってください。公式の方法はSConsですが、godot-cppはCMakeにも対応しています。
Godot 4.7以降: アップストリームのGDExtensionインターフェースのリファレンスファイル(例:
gdextension_interface.h)は、godot-cppではなくgodot-headersリポジトリに置かれるようになりました(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 と完全に一致する必要があります。一致しないと、拡張機能は読み込まれません。クラスは MODULE_INITIALIZATION_LEVEL_SCENE の条件下で GDREGISTER_CLASS を使って登録します。[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バイナリが含まれている