Game as c++ engine module? Node inheritance and lifecycle

Godot Version

4.2.2

Question

Documentation says that if you want you can make your game as engine module. And I’ve tried to convert my game to module. But inheriting from Node in engine breaks things. Because engine Node classes don’t have standard nodes lifecycle functions like _ready _entered_tree _exited_tree and etc.

So what is approach here? How to properly inherit Node in modules to have proper nodes lifecycle functions?

You should place a GDCLASS macro in your class definition as follows:

class MyNode : Node
{
    GDCLASS(MyNode, Node)
    // The rest of the code goes the same
}

Godot’s node lifecycle didn’t depend on inheritance but on macro, it’s a way to avoid vtbl for performance and code complexity considerations.

Check out the following documentation for a guide, Godot’s docs are quite straightforward for developers.

Consider using GDExtension instead to improve productivity since you only have to compile the engine code once:

I’ve created this little test:

class GameTestNode : public Node{
    GDCLASS(GameTestNode , Node)
    public:
    void _bind_functions(){}

    void _ready() override;

    void _exit_tree();
};

And compiler prints this error:

error C3668: ‘GameTestNode::_ready’: method with override specifier ‘override’ did not override any base class methods

Which means this function does not exists.
If i remove ‘override’ keyword the function is not being called.
Cant find anything in documentation about that.

and godot_cpp has this code that somehow registers virtuals:

template <class T, class B>
static void register_virtuals() {
Object::register_virtuals<T, B>();
if constexpr (!std::is_same_v<decltype(&B::_process),decltype(&T::_process)>) {
BIND_VIRTUAL_METHOD(T, _process);
}
if constexpr (!std::is_same_v<decltype(&B::_physics_process),decltype(&T::_physics_process)>) {
BIND_VIRTUAL_METHOD(T, _physics_process);
}
if constexpr (!std::is_same_v<decltype(&B::_enter_tree),decltype(&T::_enter_tree)>) {
BIND_VIRTUAL_METHOD(T, _enter_tree);
}
if constexpr (!std::is_same_v<decltype(&B::_exit_tree),decltype(&T::_exit_tree)>) {
BIND_VIRTUAL_METHOD(T, _exit_tree);
}
if constexpr (!std::is_same_v<decltype(&B::_ready),decltype(&T::_ready)>) {
BIND_VIRTUAL_METHOD(T, _ready);
}
if constexpr (!std::is_same_v<decltype(&B::_get_configuration_warnings),decltype(&T::_get_configuration_warnings)>) {
BIND_VIRTUAL_METHOD(T, _get_configuration_warnings);
}
if constexpr (!std::is_same_v<decltype(&B::_input),decltype(&T::_input)>) {
BIND_VIRTUAL_METHOD(T, _input);
}
if constexpr (!std::is_same_v<decltype(&B::_shortcut_input),decltype(&T::_shortcut_input)>) {
BIND_VIRTUAL_METHOD(T, _shortcut_input);
}
if constexpr (!std::is_same_v<decltype(&B::_unhandled_input),decltype(&T::_unhandled_input)>) {
BIND_VIRTUAL_METHOD(T, _unhandled_input);
}
if constexpr (!std::is_same_v<decltype(&B::_unhandled_key_input),decltype(&T::_unhandled_key_input)>) {
BIND_VIRTUAL_METHOD(T, _unhandled_key_input);
}
}

I am using GDEXtension. The problem of extension is that it has chain of function class that are executed for every simple functions. Every simple ‘get_global_position()’ results in 5 functions calls with some pointers manipulation. That seems a bit expedience when you have 1000s nodes.

1 Like

Would the _bind_functions be the problem? for it’s _bind_metheds in the documentation, this might cause some sneaky errors in the GDCLASS macro.