Classe Object
Vedi anche
This page describes the C++ implementation of objects in Godot. Looking for the Object class reference? Have a look here.
Definizione generale
Object è la classe base per quasi tutto. La maggior parte delle classi in Godot eredita direttamente o indirettamente da essa. Gli oggetti forniscono riflessione e proprietà modificabili, e dichiararle è questione di utilizzare una singola macro come questa:
class CustomObject : public Object {
GDCLASS(CustomObject, Object); // this is required to inherit
};
Questo aggiunge molte funzionalità agli Object. Per esempio:
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.
Riferimenti:
Registrare un Object
ClassDB è una classe statica che contiene la lista completa delle classi registrate che ereditano da Object, nonché vincoli dinamici a tutti i loro metodi, proprietà e costanti di tipo intero.
Le classi si registrano chiamando:
ClassDB::register_class<MyCustomClass>()
La registrazione consentirà di creare istanze della classe tramite script, codice o di ricrearle alla deserializzazione.
La registrazione come virtuale è la stessa cosa, ma non è possibile istanziare la classe.
ClassDB::register_virtual_class<MyCustomClass>()
Le classi derivate da oggetti possono sovrascrivere la funzione statica static void _bind_methods(). Quando una classe viene registrata, questa funzione statica viene chiamata per registrare tutti i metodi, le proprietà, le costanti, ecc. dell'oggetto. Viene chiamata una sola volta. Se una classe derivata da Object viene istanziata ma non è stata registrata, viene registrata automaticamente come virtuale.
All'interno di _bind_methods, ci sono un paio di cose che si possono fare. Una di queste è registrare funzioni:
ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name", "arg3name"), &MyCustomType::method);
I valori predefiniti per gli argomenti si possono passare come parametri alla fine:
ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name", "arg3name"), &MyCustomType::method, DEFVAL(-1), DEFVAL(-2)); // Default values for arg2name (-1) and arg3name (-2).
I valori predefiniti si devono fornire nello stesso ordine in cui sono dichiarati, saltando gli argomenti obbligatori e fornendo i valori predefiniti per quelli facoltativi. Questa sintassi corrisponde a quella usata per dichiarare i metodi in C++.
D_METHOD è una macro che converte "methodname" in StringName per una più efficienza. I nomi degli argomenti sono utilizzati per l'introspezione, ma quando si compila un rilascio, la macro li ignora, quindi le stringhe rimangono inutilizzate e vengono rimosse come misura di ottimizzazione.
Dare un occhiata al metodo _bind_methods di Control o Object per più esempi.
If just adding modules and functionality that is not expected to be
documented as thoroughly, the D_METHOD() macro can safely be ignored and a
string passing the name can be passed for brevity.
Riferimenti:
Costanti
Le classi spesso hanno enumerazioni come:
enum SomeMode {
MODE_FIRST,
MODE_SECOND
};
For these to work when binding to methods, the enum must be declared convertible to int. A macro is provided to help with this:
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);
Proprietà (set/get)
Objects export properties, properties are useful for the following:
Serializzare e deserializzare l'oggetto.
Creare di una lista di valori modificabili per la classe derivata da Object.
Le proprietà sono solitamente definite dalla classe PropertyInfo() e costruite come:
PropertyInfo(type, name, hint, hint_string, usage_flags)
Per esempio:
PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "0,49,1", PROPERTY_USAGE_EDITOR)
Questa è una proprietà di tipo intero denominata "amount". L'indicazione è un intervallo, che va da 0 a 49 con incrementi di 1 (interi). È utilizzabile solo per l'editor (modificare visivamente il valore), ma non sarà serializzato.
Un altro esempio:
PropertyInfo(Variant::STRING, "modes", PROPERTY_HINT_ENUM, "Enabled,Disabled,Turbo")
Questa è una proprietà stringa, può accettare qualsiasi stringa, ma l'editor accetterà solo quelle definite come indicazione. Poiché non sono stati specificati flag di utilizzo, quelli predefiniti sono PROPERTY_USAGE_STORAGE e PROPERTY_USAGE_EDITOR.
Esistono numerose indicazioni e flag di utilizzo disponibili in object.h, vale la pena dargli un'occhiata.
Le proprietà possono anche funzionare come proprietà di C# ed essere accessibili da script tramite indicizzazione, ma questo utilizzo è generalmente sconsigliato, poiché l'uso di funzioni è preferibile per motivi di leggibilità. Molte proprietà sono inoltre vincolate a categorie, come "animation/frame", che rendono impossibile l'indicizzazione a meno che non si utilizzi l'operatore [].
Da _bind_methods(), le proprietà si possono creare e vincolare purché esistano funzioni set/get. Esempio:
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount"), "set_amount", "get_amount")
In questo modo la proprietà viene creata, utilizzando il setter e il getter.
Vincolare proprietà tramite _set/_get/_get_property_list
Esiste un metodo aggiuntivo per creare proprietà quando si desidera più flessibilità (ad esempio aggiungendo o rimuovendo proprietà in base al contesto).
Le seguenti funzioni si possono sovrascrivere in una classe derivata da Object, NON sono virtuali, NON renderle virtuali, vengono chiamate a ogni sovrascrittura e le quelle precedenti non vengono invalidate (chiamata multilivello).
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
Questa soluzione è anche un po' meno efficiente, poiché p_property deve essere confrontato con i nomi desiderati in ordine seriale.
Dynamic casting
Godot provides dynamic casting between Object-derived classes, for example:
void somefunc(Object *some_obj) {
Button *button = Object::cast_to<Button>(some_obj);
}
Se il cast fallisce, viene restituito NULL. Questo sistema utilizza RTTI, ma funziona bene (anche se un po' più lentamente) anche quando RTTI è disabilitato. Ciò è utile su piattaforme in cui è ideale una dimensione binaria ridotta, come HTML5 o console (con un basso consumo di memoria).
Segnali
Gli oggetti possono avere una serie di segnali definiti (simili ai delegati in altri linguaggi). Questo esempio mostra come connettersi a essi:
obj->connect(<signal>, target_instance, target_method)
// for example:
obj->connect("enter_tree", this, "_node_entered_tree")
Il metodo _node_entered_tree deve essere registrato nella classe attraverso ClassDB::bind_method (spiegato in precedenza).
L'aggiunta di segnali a una classe è effettuata in _bind_methods, attraverso la macro ADD_SIGNAL, ad esempio:
ADD_SIGNAL(MethodInfo("been_killed"))
Notifiche
Tutti gli oggetti in Godot hanno un metodo _notification che consente di rispondere ai callback a livello di motore che potrebbero riguardarli. Ulteriori informazioni sono disponibili nella pagina Notifiche di Godot.
Riferimenti
RefCounted eredita da Object e contiene un conteggio di riferimenti. È la base per i tipi di oggetto i quali riferimenti sono conteggiati. La loro dichiarazione si deve effettuare attraverso il template Ref<>. Ad esempio:
class MyReference: public RefCounted {
GDCLASS(MyReference, RefCounted);
};
Ref<MyReference> myref(memnew(MyReference));
myref è conteggiato per riferimento. Verrà liberato quando nessun altro template Ref<> vi punterà.
Riferimenti:
Risorse
Resource eredita da RefCounted, quindi tutte le risorse sono conteggiate per riferimento. Le risorse possono facoltativamente contenere un percorso, che fa riferimento a un file su disco. Questo si può impostare con resource.set_path(path), sebbene ciò sia normalmente effettuato dal caricatore di risorse. Due risorse diverse non possono avere lo stesso percorso; tentare di fare ciò causerà un errore.
Anche le risorse senza un percorso sono permesse.
Riferimenti:
Caricamento delle risorse
Le risorse si possono caricare con l'API di ResourceLoader, in questo modo:
Ref<Resource> res = ResourceLoader::load("res://someresource.res")
Se un riferimento a una risorsa è stato caricato in precedenza ed è presente in memoria, il caricatore di risorse restituirà tale riferimento. Ciò significa che può essere caricata una sola risorsa alla volta da un file referenziato su disco.
resourceinteractiveloader (TODO)
Riferimenti:
Salvataggio delle risorse
È possibile salvare una risorsa tramite l'API del salvatore di risorse:
ResourceSaver::save("res://someresource.res", instance)
L'istanza sarà salvata. Le sotto-risorse che hanno un percorso a un file saranno salvate come riferimento a quella risorsa. Le sotto-risorse senza un percorso saranno raggruppate con la risorsa salvata e vi saranno assegnati dei sub-ID, come res://someresource.res::1. Questo aiuta anche a memorizzarle nella cache quando vengono caricate.