GDExtension中注册信号函数遇到的问题

使用GDExtension定义了一个状态机,头文件card_state.h完整内容如下:

#ifndef CARD_STATE_H
#define CARD_STATE_H

#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/classes/input_event.hpp>

namespace godot {

class CardState : public Node {
    GDCLASS(CardState, Node)

protected:
	static void _bind_methods();
public:
    enum State {
        BASE,
        CLICKED,
        DRAGGING,
        AIMING,
        RELEASED
    };
    void enter();
    void exit();
    void on_input(InputEvent *_event);
    void on_gui_input(InputEvent *_event);
    void on_mouse_entered();
    void on_mouse_exited();
};

}

VARIANT_ENUM_CAST(CardState::State);

#endif

注意到代码中定义一个public的枚举成员State,并且使用了VARIANT_ENUM_CAST(CardState::State);将其注册。
VARIANT_ENUM_CAST宏在godot_cpp\core\binder_common.hpp源代码中的定义如下:

#define VARIANT_ENUM_CAST(m_enum)                                      \
	namespace godot {                                                  \
	MAKE_ENUM_TYPE_INFO(m_enum)                                        \
	template <>                                                        \
	struct VariantCaster<m_enum> {                                     \
		static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) {  \
			return (m_enum)p_variant.operator int64_t();               \
		}                                                              \
	};                                                                 \
	template <>                                                        \
	struct PtrToArg<m_enum> {                                          \
		_FORCE_INLINE_ static m_enum convert(const void *p_ptr) {      \
			return m_enum(*reinterpret_cast<const int64_t *>(p_ptr));  \
		}                                                              \
		typedef int64_t EncodeT;                                       \
		_FORCE_INLINE_ static void encode(m_enum p_val, void *p_ptr) { \
			*reinterpret_cast<int64_t *>(p_ptr) = p_val;               \
		}                                                              \
	};                                                                 \
	}

这个宏其实是用结构体模板对c++中的enum进行封装。
之后在card_state.cpp中添加如下代码:

void CardState::_bind_methods() {
    BIND_ENUM_CONSTANT(BASE);
    BIND_ENUM_CONSTANT(CLICKED);
    BIND_ENUM_CONSTANT(DRAGGING);
    BIND_ENUM_CONSTANT(AIMING);
    BIND_ENUM_CONSTANT(RELEASED);

    ClassDB::bind_method(D_METHOD("enter"), &CardState::enter);
    ClassDB::bind_method(D_METHOD("exit"), &CardState::exit);
    ClassDB::bind_method(D_METHOD("on_input", "event"), &CardState::on_input);
    ClassDB::bind_method(D_METHOD("on_gui_input", "event"), &CardState::on_gui_input);
    ClassDB::bind_method(D_METHOD("on_mouse_entered"), &CardState::on_mouse_entered);
    ClassDB::bind_method(D_METHOD("on_mouse_exited"), &CardState::on_mouse_exited);

    ADD_SIGNAL(
        MethodInfo(
            "transition_requested", 
            PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "CardState"), 
            PropertyInfo(Variant::INT, "to", PROPERTY_HINT_ENUM, "BASE,CLICKED,DRAGGING,AIMING,RELEASED")
        )
    );
}

其中BIND_ENUM_CONSTANT宏在源代码godot_cpp\core\class_db.hpp中的定义为

#define BIND_ENUM_CONSTANT(m_constant) \
	::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);

bind_integer_constant方法完整的函数签名为:

static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);

可知在godot引擎中枚举的实现其实是将枚举字符串与整型常量绑定。
之后又使用

ADD_SIGNAL(
        MethodInfo(
            "transition_requested", 
            PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "CardState"), 
            PropertyInfo(Variant::INT, "to", PROPERTY_HINT_ENUM, "BASE,CLICKED,DRAGGING,AIMING,RELEASED")
        )
    );

注册了信号方法transition_requested(from:CardState, to:int),把枚举作为第二个参数的类型签名。但这么做有问题,导入到godot编辑器当中以后,界面提示的的信号方法第二个参数类型就是INT而非枚举类型。查阅了源代码之后发现PropertyInfo方法中的PROPERTY_HINT_ENUM参数只在注册属性的时候有具体实现,在注册信号时是没有具体实现的。在注册信号的方法的时候,只有当参数的类型签名是Object的时候才能自定义在编辑器中的提示。
但是这一需求在GDScript中却能够实现,只需要在脚本中添加以下代码即可:

enum  State {BASE, CLICKED, DRAGGING, AIMING, RELEASED}
signal transition_requested(from: CardState, to: State)
@export var state: State

编译器中能够将参数的类型签名提示为枚举类型
在GDExtension中定义参数类型签名为int时,虽然实参类型使用枚举也可以类型转换为整型,但是这样做没有对参数类型进行严格约束,不符合设计原则。目前笔者尚不知应该如何解决这个问题,特在此记录。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值