Object类
参见
本页介绍了Godot中对象的C++实现.寻找Object类参考? 请看这里.
一般定义
Object 几乎是所有类的基类.Godot中的大多数类都直接或间接继承自它.Object对象提供反射和可编辑的属性,声明它们就像使用单个宏一样.
class CustomObject : public Object {
GDCLASS(CustomObject, Object); // this is required to inherit
};
这使得Objects获得了很多功能,例如
obj = memnew(CustomObject);
print_line("Object class: ", obj->get_class()); // print object class
obj2 = Object::cast_to<OtherClass>(obj); // converting between classes, this also works without RTTI enabled.
参考:
注册对象
ClassDB是一个静态类,其中包含从Object继承的所有已注册类的完整列表,以及对其所有方法属性和整数常量的动态绑定.
通过以下调用来注册类:
ClassDB::register_class<MyCustomClass>()
注册它将允许通过脚本、代码实例化类,或在反序列化时再次创建它们.
注册为虚拟是相同的,但它不能实例化.
ClassDB::register_virtual_class<MyCustomClass>()
Object派生类可以重写静态函数 static void _bind_methods()
.当一个类被注册时,将调用此静态函数来注册所有对象方法、属性、常量等.它只被调用一次.如果Object派生类已实例化但尚未注册,则它将自动注册为虚拟.
在 _bind_methods
里面,有几件事可以做.注册函数是一个:
ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name"), &MyCustomMethod);
参数的默认值可以按相反的顺序传递:
ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name"), &MyCustomType::method, DEFVAL(-1)); // default value for arg2name
D_METHOD
是一个宏,它将 methodname
转换为StringName以提高效率.参数名称用于自我检查,但在发布时进行编译时,宏会忽略它们,因此未使用字符串从而对其进行了优化.
有关更多示例,请查看Control或Object的 _bind_methods
.
如果只是添加不希望被彻底记录的模块和功能,可以安全地忽略 D_METHOD()
宏,并且为了简洁起见,可以传递传递名称的字符串.
参考:
常量
类通常有枚举,例如:
enum SomeMode {
MODE_FIRST,
MODE_SECOND
};
为了使这些在绑定到方法时起作用,枚举必须被声明为可转换为int,为此提供了一个宏:
VARIANT_ENUM_CAST(MyClass::SomeMode); // now functions that take SomeMode can be bound.
常量也可以绑定在 _bind_methods
中,通过使用:
BIND_CONSTANT(MODE_FIRST);
BIND_CONSTANT(MODE_SECOND);
属性(设置/获取)
对象导出属性,这些属性可用于以下用途:
序列化和反序列化对象.
为Object派生类创建可编辑值列表.
属性通常由PropertyInfo()类定义.通常构造为:
PropertyInfo(type, name, hint, hint_string, usage_flags)
例如:
PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "0,49,1", PROPERTY_USAGE_EDITOR)
这是一个整数属性,名为 amount
,``hint`` 是一个范围,范围从0到49,步长为1(整数).它仅适用于编辑器(可视化编辑值),但不会被序列化.
另一个示例:
PropertyInfo(Variant::STRING, "modes", PROPERTY_HINT_ENUM, "Enabled,Disabled,Turbo")
这是一个字符串属性,可以接受任何字符串,但编辑器只允许定义的提示字符串.由于未指定使用标志,因此默认值为 PROPERTY_USAGE_STORAGE
和 PROPERTY_USAGE_EDITOR
.
在object.h中有很多提示和用法标记,请对其进行检查.
属性也可以像C#属性一样工作,并且可以使用索引从脚本访问,但通常不鼓励这种用法,因为使用函数是易读性的首选.许多属性也与类别绑定,例如 动画/帧
,除非使用操作符 []
,否则也无法建立索引.
从 _bind_methods()
开始,只要存在set/get函数,就可以创建和绑定属性.例如:
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount"), "set_amount", "get_amount")
这将使用setter和getter创建属性.
使用 _set
/_get
/_get_property_list
绑定属性
当需要更大的灵活性时(即在上下文中添加或删除属性),存在另一种创建属性的方法.
可以在Object派生类中重写以下函数,它们不是虚拟的,不要将它们设置为虚拟,它们会在每次重写时调用,而之前的函数不会失效(多级调用).
protected:
void _get_property_list(List<PropertyInfo> *r_props) const; // return list of properties
bool _get(const StringName &p_property, Variant &r_value) const; // return true if property was found
bool _set(const StringName &p_property, const Variant &p_value); // return true if property was found
由于 p_property
必须按顺序与所需的名称进行比较,因此效率也较低.
动态转型
Godot在Object派生类之间提供动态转换,例如:
void somefunc(Object *some_obj) {
Button *button = Object::cast_to<Button>(some_obj);
}
如果强制转换失败,则返回NULL.这个系统使用RTTI,但是当RTTI被禁用时它也可以正常工作(虽然有点慢).这在二进制大小较小的平台上非常有用,例如HTML5或游戏主机(具有较小的内存占用).
信号
对象可以定义一组信号(类似于其他语言的代理).连接它们很容易:
obj->connect(<signal>, target_instance, target_method)
// for example:
obj->connect("enter_tree", this, "_node_entered_tree")
_node_entered_tree
方法必须使用 ClassDB::bind_method
(前面解释过)注册到类.
使用 ADD_SIGNAL
宏在 _bind_methods
中添加信号到类中,例如:
ADD_SIGNAL(MethodInfo("been_killed"))
参考
Reference 继承自Object并保存引用计数.它是引用计数对象类型的基础.必须使用Ref<>模板来声明它们.例如:
class MyReference: public Reference {
GDCLASS(MyReference, Reference);
};
Ref<MyReference> myref(memnew(MyReference));
myref
是引用计数.当没有更多Ref<>模板指向它时,它将被释放.
参考:
资源:
Resource 继承自Reference,因此所有资源都被引用计数.资源可以选择包含引用磁盘上文件的路径.这可以用 resource.set_path(path)
设置.这通常由资源加载器完成.没有两个不同的资源可以具有相同的路径,尝试这样做会导致错误.
资源也可以没有路径.
参考:
资源加载
可以使用ResourceLoader API加载资源,如下所示:
Ref<Resource> res = ResourceLoader::load("res://someresource.res")
如果先前已加载对该资源的引用并且该引用在内存中,则资源加载器将返回该引用.这意味着只能同时从磁盘上引用的文件加载一个资源.
- resourceinteractiveloader(TODO)
参考:
资源保存
可以使用资源保存器API保存资源:
ResourceSaver::save("res://someresource.res", instance)
实例将被保存.具有文件路径的子资源将被保存为对该资源的引用.没有路径的子资源将与保存的资源和分配的子ID捆绑在一起,例如 res://someresource.res::1
.这也有助于在加载时缓存它们.