Godot 4 GDExtension 入門 — C++ でネイティブ拡張を作る
Godot 4 の GDExtension を使うと、C++ で書いたコードをそのままエンジンに組み込んで GDScript や C# から呼び出せます。この記事では godot-cpp のセットアップから簡単な拡張の作成まで、実際の手順を解説します。
GDExtension とは
GDExtension は Godot 4 で導入されたネイティブ拡張の仕組みです。C++ や Rust などのネイティブ言語で書いたコードを共有ライブラリ(.dll / .so / .dylib)としてビルドし、Godot に読み込ませることができます。
GDNative(Godot 3)との違い
| 項目 | GDNative(Godot 3) | GDExtension(Godot 4) |
|---|---|---|
| バインディング方法 | 関数ポインタ経由 | 直接 C++ クラスとして登録 |
| エンジン再コンパイル | 不要 | 不要 |
| API 安定性 | 低い | 高い(GDEXTENSION_COMPATIBILITY_MINIMUM で制御) |
| ホットリロード | 限定的 | より安定したホットリロード対応 |
| godot-cpp | 必要(別リポジトリ) | 同梱・サブモジュールで管理 |
| C++ クラスの書き方 | マクロ多用 | より直感的な記述 |
GDNative では GDNATIVE_INIT などのマクロを多用していましたが、GDExtension ではより C++ らしいクラス記述になっています。
GDExtension を使うべき場面
- パフォーマンスが必要な処理: 物理演算・画像処理・AI 推論など
- 既存の C/C++ ライブラリを Godot から使いたい: OpenCV・Box2D・独自エンジンなど
- GDScript では表現しにくいロジック: メモリ管理が重要なシステム
- プラットフォーム固有の API を叩く: Windows API・Apple API など
必要なもの
- Godot 4.x(最新安定版推奨)
- C++ コンパイラ(Windows: MSVC or MinGW、Linux: GCC or Clang、macOS: Clang)
- SCons(ビルドツール)
- Git
# SCons のインストール
pip install scons
# バージョン確認
scons --version
プロジェクト構成
my_extension/
├── godot-cpp/ ← サブモジュール
├── src/
│ ├── register_types.cpp
│ ├── register_types.h
│ ├── my_node.cpp
│ └── my_node.h
├── demo/ ← Godot プロジェクト(テスト用)
│ ├── project.godot
│ └── bin/ ← ビルドした .dll/.so が入る
├── SConstruct
└── my_extension.gdextension
セットアップ手順
1. godot-cpp をサブモジュールとして追加
mkdir my_extension && cd my_extension
git init
git submodule add -b 4.x https://github.com/godotengine/godot-cpp
git submodule update --init --recursive
2. SConstruct ファイルを作成
# SConstruct
#!/usr/bin/env python
import os
import sys
env = SConscript("godot-cpp/SConstruct")
# ヘッダーのインクルードパスを追加
env.Append(CPPPATH=["src/"])
# ソースファイルを収集
sources = Glob("src/*.cpp")
# 共有ライブラリをビルド
if env["target"] in ["editor", "template_debug"]:
doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
sources.append(doc_data)
library = env.SharedLibrary(
"demo/bin/libmy_extension{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)
3. .gdextension ファイルを作成
# my_extension.gdextension
[configuration]
entry_symbol = "my_extension_init"
compatibility_minimum = "4.1"
[libraries]
macos.debug = "res://bin/libmy_extension.macos.template_debug.framework"
macos.release = "res://bin/libmy_extension.macos.template_release.framework"
windows.debug.x86_64 = "res://bin/libmy_extension.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libmy_extension.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libmy_extension.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libmy_extension.linux.template_release.x86_64.so"
C++ コードを書く
カスタムノードクラスの定義
// src/my_node.h
#pragma once
#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/core/binder_common.hpp>
namespace godot {
class MyNode : public Node {
GDCLASS(MyNode, Node)
private:
double speed = 100.0;
protected:
static void _bind_methods();
public:
MyNode();
~MyNode();
void _process(double delta) override;
void set_speed(double p_speed);
double get_speed() const;
};
} // namespace godot
// src/my_node.cpp
#include "my_node.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void MyNode::_bind_methods() {
// プロパティをバインド
ClassDB::bind_method(D_METHOD("set_speed", "speed"), &MyNode::set_speed);
ClassDB::bind_method(D_METHOD("get_speed"), &MyNode::get_speed);
ADD_PROPERTY(
PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,1000,1"),
"set_speed",
"get_speed"
);
}
MyNode::MyNode() : speed(100.0) {}
MyNode::~MyNode() {}
void MyNode::_process(double delta) {
// UtilityFunctions::print はデバッグログ出力
// 実際の処理をここに書く
}
void MyNode::set_speed(double p_speed) {
speed = p_speed;
}
double MyNode::get_speed() const {
return speed;
}
エントリーポイントの登録
// src/register_types.h
#pragma once
#include <godot_cpp/core/class_db.hpp>
void initialize_my_extension_module(godot::ModuleInitializationLevel p_level);
void uninitialize_my_extension_module(godot::ModuleInitializationLevel p_level);
// src/register_types.cpp
#include "register_types.h"
#include "my_node.h"
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
using namespace godot;
void initialize_my_extension_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
ClassDB::register_class<MyNode>();
}
void uninitialize_my_extension_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
}
extern "C" {
GDExtensionBool GDE_EXPORT my_extension_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_my_extension_module);
init_obj.register_terminator(uninitialize_my_extension_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}
ビルド
# デバッグビルド(エディタ用)
scons platform=windows target=template_debug
# Linux の場合
scons platform=linux target=template_debug
# macOS の場合
scons platform=macos target=template_debug
# リリースビルド
scons platform=windows target=template_release
ビルドが成功すると demo/bin/ に .dll(Windows)/ .so(Linux)/ .dylib(macOS)が生成されます。
Godot エディタから使う
demo/フォルダを Godot で開くmy_extension.gdextensionをdemo/ルートに配置- Godot を再起動(または「プロジェクト」→「プロジェクト設定」→「プラグイン」から読み込む)
- シーンに
MyNodeが追加できるようになる
GDScript からは通常のノードと同様に使えます。
# demo/test.gd
extends Node
func _ready():
var my_node = MyNode.new()
my_node.speed = 200.0
print(my_node.get_speed()) # 200.0
add_child(my_node)
ハマりやすいポイント
godot-cpp のブランチを Godot バージョンに合わせる
godot-cpp のブランチは Godot のバージョンに対応しています。バージョンが合わないとコンパイルエラーになります。
# Godot 4.3 を使う場合
git submodule add -b 4.3 https://github.com/godotengine/godot-cpp
# main ブランチは最新開発版(安定版には 4.x を推奨)
git submodule add -b 4.x https://github.com/godotengine/godot-cpp
Windows で MSVC を使う場合の注意
Developer Command Prompt または Developer PowerShell から SCons を実行する必要があります。通常の PowerShell では cl.exe が見つからずエラーになります。
# Visual Studio 2022 の Developer Command Prompt で実行
scons platform=windows target=template_debug
.gdextension のパスが間違っているとクラッシュする
.gdextension ファイルの [libraries] に書くパスは res:// から始まる Godot プロジェクト相対パスです。ファイルシステムの絶対パスを書いてもエラーになります。
# NG
windows.debug.x86_64 = "C:/my_extension/demo/bin/libmy_extension.dll"
# OK
windows.debug.x86_64 = "res://bin/libmy_extension.windows.template_debug.x86_64.dll"
ホットリロードが効かないファイル
GDExtension はエディタ実行中にホットリロードをサポートしていますが、エディタ自体が使用しているクラス(EditorPlugin など)はホットリロードできません。その場合はエディタを再起動してください。
実際のユースケース
高速な数値計算
// 大量のベクター演算を C++ で処理
void MyProcessor::process_particles(PackedVector2Array &positions, double delta) {
for (int i = 0; i < positions.size(); i++) {
Vector2 pos = positions[i];
// 複雑な物理演算...
positions.set(i, pos + Vector2(0, 9.8 * delta));
}
}
既存 C ライブラリの Godot ラッパー
既存の C ライブラリ(例: SQLite、OpenCV)を godot-cpp でラップして GDScript から使えるようにするのが典型的なユースケースです。
// SQLite ラッパーの例(概念コード)
class SQLiteDB : public RefCounted {
GDCLASS(SQLiteDB, RefCounted)
private:
sqlite3 *db = nullptr;
public:
bool open(String path);
Array query(String sql);
void close();
};
まとめ
- GDExtension は Godot 4 のネイティブ拡張の仕組みで、GDNative より安全・安定した API を提供する
- godot-cpp をサブモジュールとして使い、SCons でビルドするのが標準的な構成
GDCLASSマクロでクラスを定義し、_bind_methodsでプロパティ・メソッドを登録する- ビルドした共有ライブラリは
.gdextensionファイルで Godot に読み込ませる - C++ ライブラリの Godot ラッパーや高速な数値処理に特に有効