介绍
godot 4.0引入了全新的native扩展系统,具体的可以翻阅官方介绍https://godotengine.org/article/introducing-gd-extensions。
这里主要讲下GDExtension的环境搭建和调试。我本地的环境是Windows+VSCode+CMake+XMake+Godot 4.0 Alpha4。
搭建环境
编译godot-cpp
编译之前需要提前安装CMake和VSCode的CMake Tools插件
克隆godot-cpp的master分支到本地。
根据编译Debug或者Release静态库配置CMake参数-DCMAKE_BUILD_TYPE=Debug或者-DCMAKE_BUILD_TYPE=Release

编译生成godot-cpp.windows.debug.64.lib或者godot-cpp.windows.release.64.lib
生成动态库
创建我们自己的动态扩展库工程,将我们的扩展代码导出。
这里我创建了MyNode2D继承自Node2D做测试,并且有一个Print方法。
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/variant/string.hpp>
using namespace godot;
class MyNode2D : public Node2D
{
GDCLASS(MyNode2D, Node2D)
public:
MyNode2D() {};
~MyNode2D() {};
void Print();
protected:
static void _bind_methods();
};
#include "MyNode2D.h"
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void MyNode2D::_bind_methods()
{
UtilityFunctions::print("_bind_methods");
ClassDB::bind_method(D_METHOD("Print"), &MyNode2D::Print);
}
void MyNode2D::Print()
{
UtilityFunctions::print("Print");
}
_bind_methods静态方法是用来注册需要导出方法的地方,由引擎调用。这里我导出了Print方法,更多的方法类型可以参考godot-cpp中的test。
最后就是将我们自定义的MyNode2D导出。
//Binding.cpp
#include "godot/gdnative_interface.h"
#include "godot_cpp/core/class_db.hpp"
#include "godot_cpp/core/defs.hpp"
#include "godot_cpp/godot.hpp"
#include "MyNode2D.h"
void RegisterCoreTypes()
{
ClassDB::register_class<MyNode2D>();
}
void UnregisterCoreTypes()
{
}
extern "C"
{
GDNativeBool GDN_EXPORT gamecore_library_init(const GDNativeInterface* p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization* r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_scene_initializer(RegisterCoreTypes);
init_obj.register_scene_terminator(UnregisterCoreTypes);
return init_obj.init();
}
}
最后就是将动态库生成到godot工程中,我这里是生成在工程的Bin目录。构建系统我使用的XMake,使用CMake和SCons和参照godot-cpp中的test。
local godotHeaderPath = "../godot-cpp/godot-headers/"
local godotBindingPath = "../godot-cpp/include/"
local godotEngineHeaderPath = "../godot-cpp/build/gen/include/"
add_rules("mode.debug", "mode.release")
target("GDExtensionTest")
set_kind("shared")
set_targetdir("../Project/Bin/")
add_includedirs(
godotHeaderPath,
godotBindingPath,
godotEngineHeaderPath)
add_files("src/**.cpp")
add_defines("TYPED_METHOD_BIND")
if is_mode("debug") then
add_cxxflags("/MDd")
set_basename("GDExtensionTest.Debug")
add_links("../godot-cpp/build/bin/godot-cpp.windows.debug.64")
else
add_cxxflags("/MD", "/O2")
set_basename("GDExtensionTest.Release")
add_links("../godot-cpp/build/bin/godot-cpp.windows.release.64")
end
在引擎中使用GDExtension
首先创建godot工程,将在工程中创建一个GDExtension配置文件XXX.gdextension
[configuration]
entry_symbol = "gamecore_library_init"
[libraries]
windows.64.debug = "/Bin/GDExtensionTest.Debug.dll"
windows.64.release = "/Bin/GDExtensionTest.Release.dll"
entry_symbol表明动态库入口
另外需要说明的是编辑器中引擎和导出项目为调试版本时将会使用的当前平台Debug版本动态库,导出项目为发布版本时使用的当前平台Debug版本动态库
打开编辑器后,在创建Node中我们就能看到动态库中导出的类。给节点添加gd脚本也能看到我们导出的方法了。


调试
调试我们将利用VSCode的C/C++插件调试。调试分为编辑器调试和运行时调试。
编辑器调试
编辑器调试只能调试导出的代码,例如上面的Binding.cpp和MyNode2D中的_bind_methods方法。
在动态扩展库工程中添加调试配置
//launch.json
"version": "0.2.0",
"configurations": [
{
"name": "editor",
"type": "cppvsdbg",
"request": "launch",
"program": "D:\\Godot_v4.0\\Godot_v4.0-alpha4_win64.exe",
"args": ["-e"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\..\\Project",
"environment": [],
"console": "integratedTerminal",
}
]
program设置Godot引擎路径
args设置引擎参数,-e运行编辑器
cwd设置要调试的工程路径
MyNode2D::_bind_methods方法中设置好断点

F5调试运行,编辑器启动后就行命中断点了。

运行时调试
假如需要调试我们的导出方法Print,这时就需要运行时调试。
同样加入调试配置
//launch.json
"version": "0.2.0",
"configurations": [
{
"name": "runtime",
"type": "cppvsdbg",
"request": "launch",
"program": "D:\\Godot_v4.0\\Godot_v4.0-alpha4_win64.exe",
"args": ["F:\\GDExtension\\Godot4\\Project\\my_node_2d.tscn"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\..\\Project",
"environment": [],
"console": "integratedTerminal",
}
]
这时args参数就变成了需要运行的场景文件路径。
F5调试运行,场景启动后就行命中断点了。
