Класс Object

См.также

This page describes the C++ implementation of objects in Godot. Looking for the Object class reference? Have a look here.

Общее определение

:ref:`Object <class_object>`это базовый класс почти для всего. Большинство классов в Godot наследуется от него напрямую или косвенно. Объекты предоставляют рефлексию и редактируемые свойства, а также их объявление важно для использования простых макросов как этот.

class CustomObject : public Object {

    GDCLASS(CustomObject, Object); // this is required to inherit
};

Это делает Объекты многофункциональными, например

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.

Источники:

Регистрация Object

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 для большей эффективности. Имена аргументов используются для интроспекции, но во время компиляции для релиза, макрос игнорирует их, так что эти строки будут не использованы и выброшены при оптимизации.

Смотрите _bind_methods для Control или Object для подробных примеров.

Если просто добавить модули и функциональность которую не нужно добавлять в документацию, макрос D_METHOD() можно спокойно проигнорировать и строка с именем может быть использована для краткости.

Источники:

Константы

Классы часто содержат перечисления такие как:

enum SomeMode {
   MODE_FIRST,
   MODE_SECOND
};

For these to work when binding to methods, the enum must be declared convertible to int, for this a macro is provided:

VARIANT_ENUM_CAST(MyClass::SomeMode); // now functions that take SomeMode can be bound.

The constants can also be bound inside _bind_methods, by using:

BIND_CONSTANT(MODE_FIRST);
BIND_CONSTANT(MODE_SECOND);

Свойства (set/get)

Объекты экспортируют свойства, которые полезны для следующего:

  • Сериализации и десирализации объекта.

  • Создание списка редактируемых значений для наследуемых от 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")

Это строковое свойство, может брать любую строку но редактор будет разрешать только определённые подсказанные(hint). Так как не определенно флагов использования, по умолчанию это PROPERTY_USAGE_STORAGE и PROPERTY_USAGE_EDITOR.

Существует много подсказок и флагов использования доступные в object.h, проверьте их.

Свойства могут также работать как свойства C# и могут быть доступные из скрипта через индексирование, но это их использование в целом не приветствуется, так использования функций предпочтительнее для понятности. Многие свойства также разбиты на категории, такие как "animation/frame" которые делают индексирование невозможным разве что с использованием оператора [].

Из _bind_methods(), свойства могут быть созданы и связаны с соответствующими существующими функциями set/get. Например:

ADD_PROPERTY(PropertyInfo(Variant::INT, "amount"), "set_amount", "get_amount")

Это создаёт свойство использующее сеттер и геттер.

Связывание свойств через _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")

The method _node_entered_tree must be registered to the class using ClassDB::bind_method (explained before).

Добавление сигналов в класс делается в _bind_methods, через использование макроса ADD_SIGNAL например:

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)

Instance will be saved. Sub resources that have a path to a file will be saved as a reference to that resource. Sub resources without a path will be bundled with the saved resource and assigned sub-IDs, like res://someresource.res::1. This also helps to cache them when loaded.

Источники: