GDExtension Signal Connecting

Godot Version

4.3

Question

In my extensions below, what is the correct way to connect the signal emitted from MyButton to SpriteMoving? Seems like it should be simple, what am I missing?
I’ve exhausted what documentation is available, pored over implementation in the source code, tried with singletons, etc.

As a side-note:
Are the variant/type constants in GDScript part of its syntax, or literals attached to variables/enums in the source code? ex: myVector = Vector2.UP or PI.
I’d like to write something like myVector = godot::Vector2::UP; instead of myVector = godot::Vector2(0, -1); in my extensions, without needing to define my own constants.
In the Godot Engine source code, I’ve viewed the implementation of: vector, input_enums, vector2, etc. But I didn’t find any constant variables/enums.

Thank you for your time.

[sprite_moving.h]

#pragma once

#include <godot_cpp/classes/sprite2d.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

namespace g = godot;
namespace Movement
{


class SpriteMoving: public g::Sprite2D
{
    GDCLASS(SpriteMoving, g::Sprite2D)
public:
    SpriteMoving()
    {
        connect("my_signal", g::Callable(this, "helloThere"));
    }
    ~SpriteMoving()
    {}
    void _process(double delta) override;
    void helloThere() const { g::UtilityFunctions::print("Hello there!"); }

    double getFactor() const { return factor; }
    void setFactor(const double p_speed) { factor = p_speed; }

protected:
    static void _bind_methods();  // Required.

private:
    double factor{1.0};  // Speed factor.
    double speed{100.0};
    double angularSpeed{3.141592653589793};
    int direction{};
    g::Vector2 velocity{};
};


}

[sprite_moving.cpp]

#include "sprite_moving.h"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/core/class_db.hpp>

#include <godot_cpp/classes/input.hpp>

namespace g = godot;
namespace Movement
{


void SpriteMoving::_bind_methods()  // Required.
{
    g::ClassDB::bind_method(g::D_METHOD("getFactor"), &SpriteMoving::getFactor);
	g::ClassDB::bind_method(g::D_METHOD("setFactor", "p_speed"), &SpriteMoving::setFactor);
	ADD_PROPERTY(g::PropertyInfo(g::Variant::FLOAT, "speed", g::PROPERTY_HINT_RANGE, "0,10,0.01"), "setFactor", "getFactor");

	g::ClassDB::bind_method(g::D_METHOD("helloThere"), &SpriteMoving::helloThere);  // Needed for signal?
}


void SpriteMoving::_process(double delta)
{
    if (!g::Engine::get_singleton()->is_editor_hint())  // So code doesn't run in editor.
    {
        direction = 0;
        if (g::Input::get_singleton()->is_action_pressed("ui_left"))  { direction = -1; }
        if (g::Input::get_singleton()->is_action_pressed("ui_right")) { direction = 1; }
        rotate(angularSpeed*direction*delta);

        velocity = g::Vector2(0, 0);
        if (g::Input::get_singleton()->is_action_pressed("ui_up")) { velocity = g::Vector2(0, -1).rotated(get_rotation())*(speed*factor); }
        translate(velocity*delta);
    }
}


}

[my_button.h]

#pragma once

#include <godot_cpp/classes/button.hpp>

namespace g = godot;
namespace Movement
{


class MyButton: public g::Button
{
    GDCLASS(MyButton, g::Button)
public:
    MyButton()
    {
        //connect("my_signal", g::Callable(this, "helloThere"));
    }
    ~MyButton()
    {}
    void _pressed() override;

protected:
    static void _bind_methods();  // Required.

private:

};


}

[my_button.cpp]

#include "my_button.h"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/core/class_db.hpp>

namespace g = godot;
namespace Movement
{


void MyButton::_bind_methods()  // Required.
{
    ADD_SIGNAL(g::MethodInfo("my_signal"));
}


void MyButton::_pressed()
{
    //g::UtilityFunctions::print("Hello there!");
    emit_signal("my_signal");
}


}

You need the reference to a button.

mybuttoninstance.connect("my_signal", g::Callable(this, "helloThere"));

you are probably right.

the documentation provides an example

some_other_node->connect("the_signal", Callable(this, "my_method"));

1 Like

These constants are actually registered under core/variant/variant_call.cpp and not part of the class. It is actually a feature of the gdscript.

1 Like

Thank you for your response.
The implementation compiled as it is here, provides the following error in the Godot Editor: In Object of type 'SpriteMoving': Attempt to connect nonexistent signal 'my_signal' to callable 'SpriteMoving::helloThere'.
I’ve viewed the documentation, as my post says, but it’s not too clear on the usage of the arrow operator-> in its example.

It seems to me like I should call connect on my class SpriteMoving from my other class MyButton. When compiled that way, I get this error: Signal 'my_signal' is already connected to given callable 'MyButton::helloThere' in that object.
I’ve tried to #include my classes with each other and call like: SpriteMoving::connect(... from MyButton with no success. Calling them as a singleton from their object inheritance didn’t compile.

Thank you for your response.
In my response to @jesusemora, I described a couple of my unsuccessful attempts at this. The closest to what seems should be correct being: SpriteMoving::connect(... or maybe MyButton::get_singleton()->connect(....

What would be the exact line I need in this scenario? mybuttoninstance.connect(... looks to be GDScript?

Gotcha. And I didn’t see any in the godot-cpp/src or the .hpps either.
All is well, I can define these constants in my extensions with handy reference to variant_call.cpp now.
Thank you.

C++, and many programming languages, have a concept of memory pointers and -> is the syntactical sugar in c++ to access, or dereference, the class in memory they may point to.

Your problem is that you need a pointer to an instance of your button class to dereference the signal that exists underneath. You can do this in several ways, but in general you need to

// In sprite_moving.h, this may have bugs 
MyButton * mybutton_ptr = memnew(MyButton);
mybutton_ptr->connect("my_signal", g::Callable(this, "helloThere"));
add_child(*mybutton_ptr);

I doubt you may want the button as a child but this is what generally needs to happen. Create a class instance, or get a reference to an existing instance, that has a signal you want to connect to.

Just like in gdscript you need to access the node that has a signal to connect the signal. The same applies here.

https://cplusplus.com/doc/tutorial/pointers/

P.s. I know c++ but have limited experience with Godot’s native API. So take my code examples with a little grain of salt and follow examples in the source.

If you want to think about the -> a little different you can imagine these connect lines are the same.

MyButton mybutton = memnew(MyButton);
MyButton* mybutton_ptr;
mybutton_ptr = &mybutton;

// These all do the same thing with a single instance
mybutton.connect(...)
mybutton_ptr->connect(...);
( *mybutton_ptr ).connect(...);

The * is syntax for dereferencing a pointer too(as well as declaring a pointer type). The parentheses are forcing an order of operations, as you need to dereference before you call methods. You can see the last way is tedious so that is why the -> was introduced.

The & is syntax to get the memory reference.

Same boat here, I’m experienced with C++ (embedded R&D junior engineer), but I’m very green when it comes to the Godot API and GDScript/Godot Editor (as you could probably infer lol).
I’d like to use C++ as much as I can for my Godot projects. And I do feel a bit silly for asking something that seems so trivial.

I figured that’s what you meant, and it’s my bad for not clearly expressing the complete scenario.
I’ve instantiated a MyButton in the Godot editor (adding a node to a scene), and I’d like to connect to that instance.
Is there a way to create a pointer to existing nodes (instances) that are created in the Godot editor?

The same way with all nodes? Export and get_child()?

You can always just look at the godot source code, it’s all C++ and mostly extremely simple.

If you can’t C++ just use gdscript, you are limiting yourself with having to compile the code and risking serious problems when the only reasons to work in that layer are accessing methods and properties not available to gdscript and extreme performance, which you don’t need to make most games or something this simple.

At least write gdscript code for prototyping, you can easily translate it to C++ once it’s working.

1 Like

If you want to do it in c++ it puts you in. Peculiar scenario because you can only do it programmatically, and you will have to decide on the level of coupling. You should use get_node, but this should, in good practice, only be for static scenes.

You need to write your scene with all the nodes created in code, with minimal use of the editor.

The editor can also connect them if you just want to write fundamental node classes, and just use the editor compose them.

Ah gotcha, understood. I’ll see to writing my scenes through the API, as well as just using the editor to connect to my own methods (which I thought would probably be the answer anyway lol).
Thank you for the constructive feedback.

Are you alright?
I’m not sure why you’re getting defensive and writing distasteful, unfounded comments that don’t contribute to the discussion.

Btw I will say I knew someone who was doing this same thing in c#. They had one main node in the editor and everything was written in c#. So I assume they had some systems to manage the nodes programmatically. Unfortunately they left Godot forum, otherwise I would have elicited their experience with the approach.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.