Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Risorse

Nodi e risorse

Fino a questo tutorial, ci siamo concentrati sulla classe Node in Godot perché è quella che si usa per codificare il comportamento e la maggior parte delle funzionalità del motore si basano su di essa. C'è un altro tipo di dati che è altrettanto importante: Resource.

I Nodi danno funzionalità: disegnano sprite, modelli 3D, simulano la fisica, organizzano le interfacce utente, ecc. Le risorse sono contenitori di dati. Non fanno nulla da sole: invece, i nodi usano i dati contenuti nelle risorse.

Qualsiasi cosa che Godot salva o carica dal disco è una risorsa. Che sia una scena (un file .tscn o .scn), un'immagine, uno script... Ecco alcuni esempi di Resource:

Quando il motore carica una risorsa dal disco, la carica solo una volta. Se una copia di quella risorsa è già in memoria, provando a caricare di nuovo la risorsa sarà restituirà ogni volta la stessa copia. Poiché le risorse contengono solo dati, non c'è bisogno di duplicarle.

Ogni oggetto, che sia un nodo o una risorsa, può esportare proprietà. Ci sono molti tipi di proprietà, come String, intero, Vector2, ecc., e ognuno di questi tipi può diventare una risorsa. Ciò significa che sia i nodi sia le risorse possono contenere risorse come proprietà:

../../_images/nodes_resources.webp

Esterne vs integrate

Esistono due modi per salvare le risorse. Possono essere:

  1. Esterne a una scena, salvate sul disco come file individuali.

  2. Integrate, salvate all'interno del file .tscn o del file .scn a cui sono allegati.

Per essere più specifici, ecco una Texture2D in un nodo Sprite2D:

../../_images/spriteprop.webp

Cliccando sull'anteprima della risorsa ci consente di visualizzare le proprietà della risorsa.

../../_images/resourcerobi.webp

La proprietà "path" ci dice da dove proviene la risorsa. In questo caso, proviene da un'immagine PNG chiamata robi.png. Quando la risorsa proviene da un file come questo, è una risorsa esterna. Se si cancella il percorso o questo percorso è vuoto, diventa una risorsa integrata.

Il passaggio tra risorse integrate ed esterne avviene quando salvi la scena. Nell'esempio sopra, se si cancella il percorso res://robi.png" e si salva, Godot salverà l'immagine all'interno del file di scena .tscn.

Nota

Anche se si salva una risorsa integrata, quando si istanzia una scena più volte, il motore ne caricherà solo una copia.

Caricare risorse tramite codice

Ci sono due modi per caricare risorse tramite codice. Innanzitutto, si può usare la funzione load() in qualsiasi momento:

func _ready():
    # Godot loads the Resource when it reads this very line.
    var imported_resource = load("res://robi.png")
    $sprite.texture = imported_resource

Le risorse si possono anche precaricare (preload). A differenza di load, questa funzione leggerà il file dal disco e lo caricherà a tempo di compilazione. Di conseguenza, non è possibile chiamare preload con un percorso variabile: è necessario specificare una stringa costante.

func _ready():
    # Godot loads the resource at compile-time
    var imported_resource = preload("res://robi.png")
    get_node("sprite").texture = imported_resource

Caricamento delle scene

Anche le scene sono risorse, ma c'è un problema. Le scene salvate su disco sono risorse di tipo PackedScene. La scena è impacchettata dentro una risorsa (Resource).

Per ottenere un'istanza della scena, è necessario usare il metodo PackedScene.instantiate().

func _on_shoot():
        var bullet = preload("res://bullet.tscn").instantiate()
        add_child(bullet)

Questo metodo crea i nodi nella gerarchia della scena, li configura e restituisce il nodo radice della scena. Lo si può poi aggiungere come figlio di qualsiasi altro nodo.

L'approccio ha diversi vantaggi. Poiché la funzione PackedScene.instantiate() è veloce, è possibile creare nuovi nemici, proiettili, effetti, ecc. senza doverli caricare di nuovo dal disco ogni volta. Vale ricordare che, come sempre, le immagini, le mesh, ecc. sono tutte condivise tra le istanze della scena.

Liberare le risorse

Quando una Resource non è più in uso, si libera automaticamente. Poiché, nella maggior parte dei casi, le risorse sono contenute nei nodi, quando si libera un nodo, il motore libera anche tutte le risorse che possiede se nessun altro nodo le usa.

Creare le proprie risorse

Come ogni oggetto in Godot, gli utenti possono anche allegare script alle risorse. Gli script delle risorse ereditano la capacità di tradurre liberamente tra le proprietà dell'oggetto e il testo serializzato o i dati binari (*.tres, *.res). Ereditano anche la gestione della memoria per il conteggio dei riferimenti dal tipo RefCounted.

Ciò ha molti vantaggi rispetto a strutture di dati alternative, come JSON, CSV, o file TXT personalizzati. Gli utenti possono importare questi file solo come Dictionary (JSON) o come FileAccess da analizzare. Ciò che distingue le risorse è la loro eredità di Object, RefCounted, e Resource:

  • Possono definire costanti, quindi le costanti da altri campi di dati o oggetti non sono necessarie.

  • Possono definire metodi, inclusi metodi setter/getter per le proprietà. Ciò consente di astrarre e incapsulare i dati sottostanti. Se la struttura dello script di risorsa deve cambiare, non è necessario che cambi anche il gioco che usa la risorsa.

  • Possono definire segnali, in modo che le risorse possano innescare risposte ai cambiamenti nei dati che gestiscono.

  • Hanno proprietà definite, quindi gli utenti sanno al 100% che i loro dati esisteranno.

  • L'auto-serializzazione e deserializzazione delle risorse è una caratteristica integrata in Godot Engine. Gli utenti non hanno bisogno di implementare una logica personalizzata per importare/esportare i dati di un file di risorsa.

  • Le risorse possono persino serializzare le sotto-risorse in modo ricorsivo, il che significa che gli utenti possono progettare strutture di dati ancora più sofisticate.

  • Gli utenti possono salvare le risorse come file di testo adatti al controllo versione (*.tres). All'esportazione di un gioco, Godot serializza i file di risorse come file binari (*.res) per aumentare la velocità e la compressione.

  • L'Ispettore di Godot Engine rende e modifica i file risorse immediatamente. Pertanto, gli utenti spesso non hanno bisogno di implementare una logica personalizzata per visualizzare o modificare i loro dati. Per fare ciò, fai doppio clic sul file risorsa nel pannello FileSystem o clicca sull'icona della cartella nell'Ispettore e apri il file nella finestra di dialogo.

  • Possono estendere altri tipi di risorse, oltre alla risorsa base.

Godot rende facile creare risorse personalizzate nell'Ispettore.

  1. Creare un semplice oggetto Resource nell'Ispettore. Questo può anche essere un tipo che deriva da Resource, purché il proprio script estenda quel tipo.

  2. Imposta la proprietà script nell'Ispettore in modo che sia il proprio script.

The Inspector will now display your Resource script's custom properties. If one edits those values and saves the resource, the Inspector serializes the custom properties too! To save a resource from the Inspector, click the save icon at the top of the Inspector, and select "Save" or "Save As...".

Se il linguaggio dello script supporta classi di script, ciò semplifica il processo. Solo definendo un nome per il proprio script, sarà aggiunto al dialogo di creazione dell'Ispettore. Ciò aggiungerà automaticamente lo script all'oggetto Resource creato.

Vediamo alcuni esempi. Crea una Risorsa e chiamala bot_stats. Dovrebbe apparire nella scheda File con il nome completo bot_stats.tres. Senza uno script, è inutile, quindi diamogli un po' dati e logica! Allegagli uno script chiamato bot_stats.gd (oppure crea un nuovo script e trascinalo sopra).

Nota

Per far apparire la nuova classe risorsa nell'interfaccia grafica Crea risorsa, è necessario specificare un nome di classe per GDScript oppure utilizzare l'attributo [GlobalClass] in C#.

class_name BotStats
extends Resource

@export var health: int
@export var sub_resource: Resource
@export var strings: PackedStringArray

# Make sure that every parameter has a default value.
# Otherwise, there will be problems with creating and editing
# your resource via the inspector.
func _init(p_health = 0, p_sub_resource = null, p_strings = []):
    health = p_health
    sub_resource = p_sub_resource
    strings = p_strings

Ora, crea un CharacterBody3D, chiamalo Bot e allegagli il seguente script:

extends CharacterBody3D

@export var stats: Resource

func _ready():
    # Uses an implicit, duck-typed interface for any 'health'-compatible resources.
    if stats:
        stats.health = 10
        print(stats.health)
        # Prints "10"

Ora, seleziona il nodo CharacterBody3D che abbiamo chiamato bot e trascina la risorsa bot_stats.tres nell'Ispettore. Dovrebbe stampare 10! Ovviamente, questa configurazione si può usare per funzionalità più avanzate, ma finché capisci come funziona il tutto, dovresti riuscire a capire tutto il resto che riguarda le risorse.

Nota

Gli script delle risorse sono simili agli ScriptableObject di Unity. L'Ispettore fornisce un supporto integrato per le risorse personalizzate. Tuttavia, se lo si desidera, gli utenti possono anche progettare i propri script strumento (tool) basati su Control e combinarli con un EditorPlugin per creare visualizzazioni ed editor personalizzati per i loro dati.

Le DataTable e CurveTable di Unreal Engine 4 sono anche facili da ricreare con gli script Resource. Le DataTable sono una stringa mappata a una struct personalizzata, simile a un Dictionary che mappano una stringa a uno script Resource secondario personalizzato.

# bot_stats_table.gd
extends Resource

const BotStats = preload("bot_stats.gd")

var data = {
    "GodotBot": BotStats.new(10), # Creates instance with 10 health.
    "DifferentBot": BotStats.new(20) # A different one with 20 health.
}

func _init():
    print(data)

Invece di definire i valori del dizionario nel codice, si potrebbe anche, in alternativa:

  1. Importa una tabella di valori da un foglio di calcolo e genera queste coppie di chiave-valore.

  2. Progettare una visualizzazione all'interno dell'editor e creare una semplice estensione che la aggiunge all'Ispettore quando si aprono questi tipi di risorse.

Le CurveTable sono la stessa cosa, tranne che sono mappate su un array di valori float o su un oggetto risorsa Curve/Curve2D.

Avvertimento

Attenzione, i file di risorse (*.tres/*.res) memorizzano il percorso dello script che usano nel file. Quando vengono caricati, recuperano e caricano questo script come estensione del loro tipo. Ciò significa che cercare di assegnare una classe interna di uno script (ovvero tramite la parola chiave class in GDScript) non funzionerà. Godot non serializzerà correttamente le proprietà personalizzate sulla classe interna dello script.

Nell'esempio qui sotto, Godot caricherebbe lo script Node, noterebbe che non estende Resource, poi determinerebbe che lo script non è riuscito a caricarsi per l'oggetto Resource poiché i tipi sono incompatibili.

extends Node

class MyResource:
    extends Resource
    @export var value = 5

func _ready():
    var my_res = MyResource.new()

    # This will NOT serialize the 'value' property.
    ResourceSaver.save(my_res, "res://my_res.tres")