Clase Object

Ver también

Esta página describe la implementación en C++ de los objetos en Godot. ¿Buscas la referencia de la clase Object? Échale un vistazo aquí.

Definición General

Object es la clase base para casi todo. La mayoría de las clases en Godot heredan directa o indirectamente de ella. Los objetos proporcionan reflexión y propiedades editables, y declararlos es cuestión de usar una sola macro como esta.

class CustomObject : public Object {

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

Esto hace que los objetos adquieran muchas funcionalidades, como por ejemplo

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.

Referencias:

Registrando un Object

ClassDB es una clase estática que contiene la lista completa de clases registradas que heredan de Object, así como enlaces dinámicos a todos sus métodos, propiedades y constantes enteras.

Las clases se registran llamando a:

ClassDB::register_class<MyCustomClass>()

Registrarla permitirá que la clase se instancie mediante scripts, código o al crearlos nuevamente al deserializar.

Registrarla como virtual es lo mismo, pero no se puede instanciar.

ClassDB::register_virtual_class<MyCustomClass>()

Las clases derivadas de Object pueden sobrescribir la función estática static void _bind_methods(). Cuando se registra una clase, esta función estática se llama para registrar todos los métodos, propiedades, constantes, etc., del objeto. Solo se llama una vez. Si se instancia una clase derivada de Object pero no se ha registrado, se registrará automáticamente como virtual.

Dentro de _bind_methods, hay algunas cosas que se pueden hacer. Una de ellas es registrar funciones:

ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name"), &MyCustomMethod);

Los valores predeterminados para los argumentos se pueden pasar en orden inverso:

ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name"), &MyCustomType::method, DEFVAL(-1)); // default value for arg2name

D_METHOD es una macro que convierte "methodname" en un StringName para mejorar la eficiencia. Los nombres de los argumentos se utilizan para la introspección, pero al compilar en modo de lanzamiento, la macro los ignora, por lo que las cadenas no se utilizan y se optimizan para que desaparezcan.

Puedes revisar el método _bind_methods de las clases Control u Object para ver más ejemplos.

Si solo estás agregando módulos y funcionalidades que no se espera que estén documentadas en detalle, el macro D_METHOD() puede ser ignorado de forma segura y simplemente puedes pasar un string con el nombre del método para mayor concisión.

Referencias:

Constantes

Las clases a menudo tienen enumeraciones como esta:

enum SomeMode {
   MODE_FIRST,
   MODE_SECOND
};

Para que estas enumeraciones funcionen al vincularse a métodos, la enumeración debe declararse convertible a int, para esto se proporciona una macro:

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

Las constantes también se pueden vincular dentro de _bind_methods, usando:

BIND_CONSTANT(MODE_FIRST);
BIND_CONSTANT(MODE_SECOND);

Propiedades (set/get)

Los objetos exportan propiedades, las propiedades son útiles para lo siguiente:

  • Serializar y deserializar el objeto.

  • Crear una lista de valores editables para la clase derivada de Object.

Las propiedades se definen utilizando la clase PropertyInfo(). Por lo general, se construyen de la siguiente manera:

PropertyInfo(type, name, hint, hint_string, usage_flags)

Por ejemplo:

PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "0,49,1", PROPERTY_USAGE_EDITOR)

Esta es una propiedad de tipo entero llamada "amount". El "hint" (pista) especifica un rango, que va de 0 a 49 en pasos de 1 (enteros). Esta propiedad solo se puede usar en el editor (editar valor visualmente) pero no se serializará.

Otro ejemplo:

PropertyInfo(Variant::STRING, "modes", PROPERTY_HINT_ENUM, "Enabled,Disabled,Turbo")

Esta es una propiedad de string, puede tomar cualquier string pero el editor sólo permitirá los que estén definidos como hint. Puesto que no se especificó ningún indicador de uso, los valores por defecto son PROPERTY_USAGE_STORAGE y PROPERTY_USAGE_EDITOR.

Hay muchas sugerencias (hints) y banderas de uso disponibles en "object.h", dales una revisión.

Las propiedades también pueden funcionar como propiedades de C# y accederse desde un script utilizando el indexado, pero este uso generalmente no se recomienda, ya que se prefiere usar funciones para mejorar la legibilidad. Muchas propiedades también están vinculadas con categorías, como por ejemplo "animation/frame", lo que también hace que el indexado sea imposible a menos que se utilice el operador [].

Desde _bind_methods(), las propiedades pueden ser creadas y enlazadas siempre y cuando existan funciones de configuración y obtención (set/get). Ejemplo:

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

Esto crea la propiedad utilizando el setter y el getter.

La vinculación de propiedades utilizando _set/_get/_get_property_list

Existe un método adicional para crear propiedades cuando se desea más flexibilidad (por ejemplo, agregar o eliminar propiedades en un contexto).

Las siguientes funciones pueden ser sobreescritas en una clase derivada de Object, NO las hagas virtuales, son llamadas para cada sobrescritura y las versiones anteriores no se invalidan (llamada multinivel).

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

Esto también es un poco menos eficiente ya que p_property debe ser comparado con los nombres deseados en orden serial.

Casteo dinámico

Godot proporciona el casteo dinámico entre clases derivadas de Object, por ejemplo:

void somefunc(Object *some_obj) {

     Button *button = Object::cast_to<Button>(some_obj);
}

Si el casteo falla, se devuelve NULL. Este sistema utiliza RTTI, pero también funciona bien (aunque un poco más lento) cuando RTTI está deshabilitado. Esto es útil en plataformas donde un tamaño binario pequeño es ideal, como HTML5 o consolas (con una huella de memoria baja).

Señales

Los objetos pueden tener un conjunto de señales definidas (similar a los delegados en otros lenguajes). Conectarse a ellas es bastante sencillo:

obj->connect(<signal>, target_instance, target_method)
// for example:
obj->connect("enter_tree", this, "_node_entered_tree")

El método _node_entered_tree debe ser registrado en la clase utilizando ClassDB::bind_method (explicado anteriormente).

Agregar señales a una clase se hace en _bind_methods, utilizando el macro ADD_SIGNAL, por ejemplo:

ADD_SIGNAL(MethodInfo("been_killed"))

Notificaciones

Todos los objetos en Godot tienen un método _notification que les permite responder a devoluciones de llamada a nivel del motor que puedan estar relacionadas con ellos. Se puede encontrar más información en la página Notificaciones en Godot.

Referencias

La clase Reference hereda de Object y mantiene un contador de referencias. Es la base para tipos de objetos con conteo de referencias. Declararlos debe hacerse utilizando la plantilla Ref<>. Por ejemplo:

class MyReference: public Reference {
    GDCLASS(MyReference, Reference);
};

Ref<MyReference> myref(memnew(MyReference));

myref es un objeto con conteo de referencias. Se liberará cuando ya no haya más plantillas Ref<> apuntando a él.

Referencias:

Recursos:

Resource hereda de Reference, por lo que todos los recursos tienen conteo de referencias. Los recursos opcionalmente pueden contener una ruta, que hace referencia a un archivo en el disco. Esto se puede establecer con resource.set_path(path). Sin embargo, normalmente el cargador de recursos se encarga de esto. No puede haber dos recursos diferentes con la misma ruta; intentar hacerlo resultará en un error.

Los recursos sin una ruta también son aceptables.

Referencias:

Cargando un recurso

Los recursos se pueden cargar con la API ResourceLoader, de esta manera:

Ref<Resource> res = ResourceLoader::load("res://someresource.res")

Si se ha cargado previamente una referencia a ese recurso y está en memoria, el cargador de recursos devolverá esa referencia. Esto significa que solo puede haber un recurso cargado desde un archivo referenciado en disco al mismo tiempo.

  • resourceinteractiveloader (TODO)

Referencias:

Guardando un recurso

Guardar un recurso se puede hacer utilizando la API del salvador de recursos:

ResourceSaver::save("res://someresource.res", instance)

La instancia se guardará. Los sub-recursos que tienen una ruta a un archivo se guardarán como una referencia a ese recurso. Los sub-recursos sin una ruta se incluirán con el recurso guardado y se les asignarán sub-ID, como res://somerecurso.res::1. Esto también ayuda a cachearlos al cargarlos.

Referencias: