Scripting

Introduzione

Prima di Godot 3.0, l'unico modo per scriptare un gioco era usare il GDScript. Oggi, Godot ha quattro (esatto, quattro!) linguaggi di programmazione ufficiali, e la possibilità di aggiungerne altri dinamicamente!

Questo è fantastico, soprattutto a causa della grande flessibilità fornita, ma rende anche il nostro lavoro per supportare i linguaggi più complicato.

I linguaggi "principali" in Godot, comunque, sono GDScript e VisualScript. Il motivo principale per sceglierli è il loro livello di integrazione con Godot, in quanto ciò rende l'esperienza più fluida: entrambi hanno una brillante integrazione con l'editor, mentre C# e C++ hanno bisogno di un IDE esterno. Se sei un sostenitore dei linguaggi staticamente tipati, prosegui con C# e C++.

GDScript

Il GDScript è, come menzionato sopra, il linguaggio principalmente usato in Godot. Utilizzarlo ha alcuni vantaggi rispetto ad altri linguaggi, data la sua forte integrazione con Godot:

  • É semplice, elegante, e progettato per essere familiare agli utenti di altri linguaggi quali Lua, Python, Squirrel, ecc.
  • Ha un tempo di caricamento e di compilazione estremamente veloce.
  • L'editor integrato è piacevole da utilizzare, grazie al completamento del codice per nodi, segnali, e molti altri strumenti pertinenti alle scene in via di modifica.
  • Offre nativamente diversi tipi di Vettori (come Vettori, trasformazioni, ecc.), rendendolo efficace nei calcoli complessi di algebra lineare.
  • Supporta thread multipli efficientemente quanto i linguaggi staticamente tipati - una delle limitazioni che ci ha fatto evitare l'uso di VM come Lua, Squirrel, ecc.
  • Non utilizza un gargabe collector, quindi baratta una piccola parte di automazione (la maggior parte degli oggetti sono a riferimenti contati in ogni caso), per il determinismo.
  • La sua natura dinamica rende semplice ottimizzare sezioni di codice in C++ (attraverso GDNative) se sono richieste performance più elevate, il tutto senza ricompilare il motore di gioco.

Se sei indeciso e hai già esperienza con la programmazione, specialmente con linguaggi a tipizzazione dinamica, ti consiglio di usare GDScript!

VisualScript

Partendo dalla versione 3.0, Godot offre Visual Scripting. Essa è una tipica implementazione di un linguaggio basato su un sistema a "blocchi e connessioni", ma adattato alle funzionalità di Godot.

Il VisualScript è ottimo per coloro che non sono in grado di programmare, ma anche per sviluppatori esperti che vogliono rendere parte del proprio codice più accessibile agli altri, come ad esempio game designer o artisti.

Può anche essere usato dai programmatori per costruire una macchina a stati (state machine) o semplicemente avere un workflow basato sulla visualizzazione di nodi - ad esempio, un sistema di dialoghi.

.NET / C#

Dato che il C# di Microsoft è una preferenza per molti sviluppatori di videogiochi, abbiamo aggiunto il suo supporto ufficiale. Il C# è un linguaggio maturo con un'enorme quantità di codice già scritto, e il suo supporto è stato aggiunto grazie a una generosa donazione da Microsoft.

E' un ottimo compromesso tra performance e facilità di utilizzo, tuttavia bisogna essere consapevoli della sua gestione della memoria.

Siccome Godot usa il Mono .NET runtime, in teoria ogni libreria .NET o framework di terze parti può essere usata per lo scripting in Godot, così come qualsiasi linguaggio di programmazione CLI, come F#, Boo o ClojureCLR. In pratica, tuttavia, il C# è l'unica opzione .NET ufficialmente supportata.

GDNative / C++

Finalmente, una delle più grandi implementazioni per il rilascio della versione 3.0: GDNative permette la scrittura in C++ senza dover ricompilare (o anche riavviare) Godot.

Qualsiasi versione di C++ può essere usata, e mescolare diversi compilatori e versioni di questi per le librerie generate funziona perfettamente, grazie all'utilizzo interno di un API bridge in C.

Questo linguaggio è la scelta migliore in quanto a performance e non deve essere per forza utilizzato in tutto il gioco, in quanto altre parti possono essere scritte in GDScript o Visual Script. In ogni caso l'API è chiara e semplice da usare in quanto somiglia, per lo più, all'effettiva API C++ di Godot.

Possono essere resi disponibili altri tipi di linguaggi nell'interfaccia di GDNatice, ma ricorda che non ne offriamo il supporto ufficiale.

Scripting di una scena

Per il resto di questo tutorial, creeremo un'interfaccia grafica (GUI), costituita da un pulsante e da un'etichetta, dove premendo il primo si aggiornerà il contenuto della seconda. Questo dimostrerà:

  • Scrivere uno script e allegarlo a un nodo.
  • Connettere gli elementi dell'interfaccia utente (UI) attraverso i segnali.
  • Scrivere uno script che può accedere agli altri nodi della scena.

Before continuing, make sure to skim and bookmark the GDScript reference. It's a language designed to be simple, and the reference is structured into sections to make it easier to get an overview of the concepts.

Impostazione della scena

If you still have the "instancing" project open from the previous tutorial, then close that out (Project -> Quit to Project List) and create a New Project.

Usa "Aggiungi un nodo figlio" dalla tab della Scena (o premendo Ctrl+A) per creare una gerarchia con i seguenti nodi:

  • Pannello
    • Etichetta
    • Pulsante

L'albero della scena dovrebbe essere simile a questo:

../../_images/scripting_scene_tree.png

Usa l'editor 2d per posizionare e ridimensionare il Pulsante e l'Etichetta così che possano assomigliare all'immagine qui sotto. Puoi impostare il testo dalla tab Inspector.

../../_images/label_button_example.png

Infine, salva la scena con un nome come sayhello.tscn.

Aggiungi uno script

Clicca con il tasto destro sul nodo Pannello, quindi seleziona "Attacca Script" dal menù contestuale:

../../_images/add_script.png

Apparirà la finestra di creazione dello script. Questa finestra ti permette di impostare il linguaggio dello script, il nome della classe e altre opzioni relative.

Con GDScript, il file stesso rappresenta la classe, quindi il campo del nome della classe non è modificabile.

Il nodo al quale stiamo attaccando lo script è un pannello, quindi il campo Eredita si riempirà automaticamente con "Pannello". Questo è quello che vogliamo, dato che l'obiettivo dello script è quello di estendere le funzionalità del nostro nodo.

Infine, inserisci un percorso per lo script e seleziona Crea:

../../_images/script_create.png

Lo script verrà quindi creato e aggiunto al nodo. Puoi vederlo rappresentato come un'icona "Apri Script" affianco al nodo nella tab "Scene", così come nelle proprietà dello script in Inspector:

../../_images/script_added.png

Per modificare lo script, seleziona uno dei pulsanti evidenziati nell'immagine qua sopra. Questo ti porterà all'Editor dello Script, che includerà un modello predefinito:

../../_images/script_template.png

Non c'è molto qui. La funzione _ready() viene chiamata quando il nodo, e tutti i suoi figli, entrano nella scena attiva. Nota: _ready() non è il costruttore; il costruttore è, invece, _init().

Il ruolo dello script

Uno script aggiunge un behavior (comportamento) ad un nodo. Viene usato per controllare come funziona il nodo e come interagisce con altri nodi: child, parent, sibling e così via. Il mirino locale dello script è il nodo. In altre parole, lo script eredita le funzioni passate (o fornite) dal nodo.

../../_images/brainslug.jpg

Gestire un segnale

I segnali sono "emessi" quando avviene qualche tipo specifico di azione, e possono essere associati ad ogni funzione di ogni script istanziato. I segnali sono usati per lo più per i nodi di interfaccia utente (GUI), sebbene possano essere usati anche per altri nodi e potete persino definire dei segnali personalizzati nei vostri script.

In questo passaggio, collegheremo il segnale "pressed" a una funzione personalizzata. Formare connessioni è la prima parte e la definizione della funzione personalizzata è la seconda parte. Per la prima parte, Godot fornisce due modi per creare connessioni: attraverso una interfaccia visuale fornita dall'editor o attraverso il codice.

Anche se useremo il metodo del codice per il resto di questa serie di tutorial, diamo un'occhiata a come funziona l'interfaccia dell'editor come riferimento per il futuro.

Seleziona il nodo "Button" nell'albero della scena e quindi seleziona la scheda "Node". Successivamente, assicurati di avere selezionato "Signals".

../../_images/signals.png

Se poi selezioni "pressed()" sotto "BaseButton" e premi il bottone "Connect..." in basso a destra, aprirai la finestra per la creazione delle connessioni.

../../_images/connect_dialogue.png

La parte superiore della finestra di dialogo visualizza una lista dei nodi della scena, con il nodo che emette il segnale evidenziato in blu. Seleziona il nodo "Panel".

In fondo alla finestra viene visualizzato il nome del metodo che verrà creato. Se non specificato, il nome del metodo conterrà il nome del nodo che emette il segnale ("Button" in questo caso), quindi il metodo diventa _on_[NomeNodo]_[nome_segnale].

E questo conclude la guida su come usare l'interfaccia grafica. Comunque, questo è un tutorial sulla codifica, quindi, per l'amore dell'imparare, approfondiamo il processo manuale!

Per fare questo, introdurremo una funzione, probabilmente la più utilizzata dai programmatori di Godot: Node.get_node(). Questa funzione utilizza i percorsi per prendere nodi da qualsiasi posto nella scena, relativa al nodo proprietario dello script.

Per convenienza, cancella tutto quanto sotto extends Panel. Riepirai il resto dello script manualmente.

Perché il Button e Label sono entrambi figli di Panel, dove lo script si trova, puoi prendere il Button scrivendo il seguente sotto la funzione _ready():

func _ready():
    get_node("Button")
public override void _Ready()
{
    GetNode("Button");
}

Poi, scrivi una funzione che sarà chiamata quando il bottone sarà premuto:

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
public void _OnButtonPressed()
{
    GetNode<Label>("Label").Text = "HELLO!";
}

Infine, connetti il segnale "pressed" del bottone a _ready(), usando Object.connect().

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")
public override void _Ready()
{
    GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
}

Lo script finito dovrebbe essere così:

extends Panel

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
using Godot;

// IMPORTANT: the name of the class MUST match the filename exactly.
// this is case sensitive!
public class sayhello : Panel
{
    public override void _Ready()
    {
        GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
    }

    public void _OnButtonPressed()
    {
        GetNode<Label>("Label").Text = "HELLO!";
    }
}

Esegui la scena e premi il pulsante. Dovresti avere il seguente risultato:

../../_images/scripting_hello.png

Why, hello there! Congratulations on scripting your first scene.

Nota

Una comune incomprensione riguardante questo tutorial è come get_node(path) funzioni. Per un nodo dato, get_node(path) ricerca il proprio figlio immediato. Nel codice soprastante, questo significa che Button deve essere un figlio di Panel. Se Button invece fosse stato figlio di Label, il codice ottenuto sarebbe stato così:

# Not for this case,
# but just in case.
get_node("Label/Button")
// Not for this case,
// but just in case.
GetNode("Label/Button")

Inoltre, ricorda che i nodi sono ottenibili dal loro nome, non dal loro tipo.

Nota

The 'advanced' panel of the connect dialogue is for binding specific values to the connected function's parameters. You can add and remove values of different types.

L'approccio attraverso il codice permette inoltre l'utilizzo di un quarto parametro di tipo Array``che di default è vuoto. Sentiti libero di leggere il metodo `` Object.connect per maggiori informazioni.