Imparare C#Imparare UnityPrincipianti

Panoramica su uno script in Unity

 Abbiamo già accennato al fatto che gli scripts potranno essere "attaccati" ai gameObject presenti nella nostra scena di Unity. Perché appunto, un componente non è altro che uno script di qualche genere.
Su tutte le guide che troverete per la rete, compresa quella ufficiale di Unity, viene usato il termine "attaccare" per dire di aggiungere un componente/script ad un gameObject.
Una volta attaccato uno script ad un gameObject esso sarà a tutti gli effetti un componente (component) di quel gameObject.
Vediamo come fare in questo brevissimo video.

Creiamo un nuovo gameObject (una sfera) e aggiungiamo un nuovo script sul gameObject appena creato .

I componets (componenti) sono gli elementi alla base del funzionamento di Unity e saranno visibili sull'inspector del gameObject selezionato.

Creare un nuovo gameObject è stato davvero facile, dal menu principale abbiamo scelto la voce "GameObject", si è scelto "3DObject" e poi abbiamo scelto di creare una sfera.
Per creare un nuovo script su di esso siamo andati sul suo inspector e abbiamo premuto il pulsante "Add Component". Questo a rimarcare che uno script è anch'esso un component.
"Add Component"
signiica Aggiungi componente.

Per fare la stessa operazione si sarebbe potuto creare uno script nella finestra Project e poi trascinarlo sull'inspector del gameObject a cui volevamo assegnarlo, oppure una volta premuto "Add Component" scegliere lo script precedentemente creato.

Fino a questo momento abbiamo parlato di codice in forma teorica e non funzionale.
E' finalmente giunto il momento di esaminare nel dettaglio uno script di Unity e vedere come si comporta concretamente allo start delle scena.

Dopo aver creato un nuovo script ci troveremo di fronte a questo codice.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NuovoScript : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

Se non avete saltato nessuna lezione precedente, avrete tutte le nozioni necessarie per comprendere questo script.

  1. Abbiamo le prime tre righe che sono degli "using" ovvero delle integrazioni di Namespace.
  2. Alla riga 5 abbiamo l'apertura della nostra classe. Ricordiamoci che creando un nuovo script abbiamo creato una nuova classe, in questo caso, chiamata NuovoScript. Il nome della classe è infatti uguale a quello assegnato allo script nel momento in cui lo creiamo.
  3. All'interno della nostra classe troviamo due metodi con dei commenti sopra.


Per ora la nostra nuova classe non possiede variabili.

Dunque, fin qui abbiamo tutti elementi già trattati nelle precedenti lezioni e che dovreste aver assimilato.
Potete sempre andarvi a riguardare la descrizione di  ogni elemento da queste scorciatoie:

Ma perché ci sono dei metodi già presenti nella nostra classe?
Semplicemente perché essi sono due metodi essenziali di una classe di Unity (infatti essi appartengono al Namespace UnityEngine e derivano dalla classe MonoBehaviour che altro non è che la classe dei componenti di Unity).
Tali metodi sono già lì perché Unity ci suggerisce di iniziare da uno script strutturato in quel modo. Potremmo anche liberamente cancellarli.
Esistono moltissimi altri metodi proprietari di UnityEngine, ma questi due (Start e Update) sono praticamente essenziali e per questo vengono inseriti sin da subito su uno script appena creato.

Start()

Come specificato dalle loro descrizioni nei commenti, il metodo Start viene eseguito all'inizio, si tratta praticamente di un metodo che viene eseguito automaticamente al primo fotogramma della scena in cui si trova questo script e viene eseguito solo una volta.
Capirete da soli quanto sia utile avere un metodo che viene eseguito all'inizio della scena. Potrete inizializzarci le variabili,  fare calcoli che impostino una determinata variabile all'inizio della scena, caricare materiale e tutto ciò che vi occorre che venga fatto allo start, che venga fatto in quel preciso istante e una sola volta.

Update()

Il metodo Update invece viene eseguito ad ogni fotogramma della scena. Finché la scena sarà in esecuzione esso verrà ripetuto ininterrottamente decine di volte al secondo! Sarà qui dentro che andremo a far muovere gli oggetti, far "ragionare" le nostre AI, intercettare l'input del giocatore ecc...

Attenzione all'ottimizzazione del metodo Update

Essendo eseguito decine di volte al secondo (update significa appunto, aggiornare) questo metodo diventa importante tanto quanto "delicato". Per esempio non è consigliato fare operazioni troppo pesanti all'interno di questo metodo perché è proprio qui che si genera il famigerato LAG (oltre che nel calcolo dei poligoni). Inserire operazioni come il caricamento di oggetti da hard disk o l'istanziamento di oggetti al suo interno, rallenterebbe l'esecuzione del gioco.
Pensate infatti che, prima di passare al frame (fotogramma) successivo, il metodo update deve aver effettuato tutte le operazioni al suo interno e via di seguito al fotogramma successivo, per ogni fotogramma, per tutta l'esecuzione del programma.
Facciamo un esempio. Mettiamo che dovete modificare una variabile di un altro componente presente su questo gameObject.
Come sappiamo, nel codice il componente si "prende" con l'istruzione GetComponet<TipoComponente>()

Facciamo l'esempio in cui, da uno certo script vogliamo verificare una variabile su un altro script.
In questo esempio, dallo script GestioneEnergia (qui sotto) voglio andare a leggere la variabile energia presente sullo script Nemico e fare in modo che quando tale variabile diventa uguale a zero, fare qualcosa (il nemico muore).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GestioneEnergia : MonoBehaviour {


	
	void Start () {
		
	}
	

	void Update () {
	    
	    //Se la variabile energia del componente Nemico su questo gameObject è uguale a zero
	    if( getConmponent<Nemico>().energia == 0)
	    {
	    //nemico muore
	    }

	}
	    
	
}

Questo però comporta un getComponent dentro al metodo Update, ovvero, ad ogni fotogramma lo script andrà a cercare il componente Nemico sul gameObject, praticamente farà getComponent decine di volte al secondo. Operazione dispendiosa e inutile visto che basterebbe andarlo a cercare una volta sola.
Potremmo ovviare questo problema così:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NuovoScript : MonoBehaviour {


	//Dichiariamo subito che useremo una variabile di tipo Nemico
	Nemico scriptNemico;
	
	void Start () {
	    //Facciamo il getComponent nello Start, una volta sola.
	    //In questo modo avremo inizializzato scriptNemico e lo avremo
	    //sempre a disposizione in tutta la classe
		scriptNemico=getConmponent<Nemico>();
	}
	

	void Update () {
	    
	    //Se il la variabile del componente preso in precedenza diventa 0
	    if(scriptNemico.energia == 0)
	    { 
	   //Nemico muore
    	}
	    
	    
	}
}

In questo modo il metodo getComponent verrà eseguito una volta sola allo Start della scena e noi potremmo operare sulla variabile scriptNemico tutte le volte che vorremo, senza andare a ricercare ogni volta il componente sul gameObject.

Cosa differenzia questi metodi da eventuali metodi che scriveremo noi?
Strutturalmente, nulla. Sono normalissimi metodi. La differenza sostanziale sta nel fatto che essi verranno eseguiti da Unity senza che noi li dovremo richiamare mai.

Alla partenza di una scena in Unity, tutti i metodi con il nome di "Start" presenti in ogni script della scena, verranno eseguiti automaticamente e contemporaneamente.

Tra qualche lezione vedremo le classi più usate in Unity, i vector2 (punti in una spazio 2D) i vector3 (punti in uno spazio 3D) e molti altri. Vedremo che quando dovremmo creare un nuovo oggetto di una determinata classe, dovremmo usare la parola chiave  new. Tutte queste classi fanno parte della classe base di Unity, il MonoBehaviour.

Il MonoBehaviour

Come avrete già notato, ogni classe di Unity deriva da una classe particolare che si chiama MonoBehaviour. Non ce ne siamo curati prima perché in fin dei conti potremmo anche soprassedere su questo aspetto, almeno agli inizi, poco ce ne importa. Ma vi sarete sicuramente chiesti il perché di quella parolina dopo il nome di ogni classe appena creata in Unity.

public class NuovoScript : MonoBehaviour {
    
    .....
    
}

MonoBehaviour è la classe che identifica un componente (o script) di Unity.

MonoBehaviour è la classe base da cui derivano tutti gli scripts di Unity. Behaviour significa appunto "comportamento generico". E' grazie ad essa che avremo a disposizione i metodi:

  • Awake()
  • OnEnable()
  • OnDisable()
  • Start()
  • Update()
  • OnCollisionEnter()
  • OnTriggerEnter()

e altre decine di metodi.
Ognuno di questi metodi (così come ogni altro metodo) viene eseguito solo se lo script e il gameObject su cui è posizionato lo script sono attivi.


Ovviamente possiamo abilitare o disabilitare un gameObject o uno script anche da codice, con una grammatica leggermente diversa tra le due cose, impostando il bool enabled per gli scripts/componenti e usando il metodo SetActive() per i gameObject:

mioScript.enabled = false;  
questa riga disabilita il componete/script mioScript

gameObject.SetActive(false); 
questa riga disabilita il gameObject (e tutti i suoi script/componenti), rendendolo completamente inattivo ed invisibile nella scena.
Una volta disabilitato un gameObject, per riabilitarlo sarà necessario farlo da un altro script/gameObject, perché essendo disabilitato gli scripts su di esso non funzioneranno.

NOTA: Tenete presente che quando un gameObject è disabilitato, anche tutti gli scripts presenti su di esso non funzioneranno (anche se abilitati).
Dunque saranno sospesi tutti metodi di questi scripts, compresi Update(), Start() e tutti gli altri .
Sarà comunque possibile far eseguire i metodi di uno script disabilitato da una chamata esterna, da un altro script.

 



Vediamo più da vicino i principali metodi di uno script di Unity e il loro ordine d'esecuzione, abbiamo già visto Start e Update, ora vediamo:

Awake()

Questo è il primissimo metodo  che vine eseguito, poco prima che una scena venga eseguita. Se uno script possiede il metodo Awake, verrà eseguito prima del primo frame della scena, dunque prima dello Start().
Awake sta appunto per "risveglio". Anche questo metodo viene eseguito una singola volta.

OnEnable()

Anche questo metodo viene eseguito all'inizio della scena, una sola volta, appena dopo l'Awake. La differenza sostanziale con Start e Awake è che esso viene eseguito anche quando lo script viene disabilitato e poi riabilitato mentre i precedenti vengono eseguiti solo una volta, anche se lo script o il gameObject viene disabilitato e poi riabilitato. Pertanto, Awake () e Start () possono essere utilizzati per scopi di inizializzazione a differenza di OnEnable().

 
OnDisable()

Anche questo metodo viene eseguito una sola volta, un attimo prima e ogni qual volta che uno script (o un gameObject con questo script) venga disabilitato.

 
Start()

Abbiamo già spiegato questo metodo, ricordatevi che verrà eseguito dopo l'Awake e OnEnable (se presenti) sul primo frame effettivo del gioco e mai più.

 
Update()

C'è poco da aggiungere su questo metodo rispetto a quanto detto poco sopra.
Ricordatevi che il metodo Update viene aggiornato ad ogni frame, dunque se il vostro gioco lavora a 30fps, sarà aggiornato 30 volte al secondo, se lavora a 60fps, sarà aggiornato 60 volte al secondo... Essendo il framerate quasi mai costante, anche l'aggiornamento di questo metodo non sarà quasi mai costante.

 
OnCollisionEnter()

Esploriamo questo metodo in modo più approfondito in questa sessione, parlando dei colliders.
Questo metodo viene eseguito solo se su questo gameObject o su uno dei gameObject padri è presente un collider e solo nel momento in cui avvenga una collisione.

 
OnTriggerEnter()

Anche questo metodo è esplorato in maniera più esaustiva nella sessione dedicata ai colliders.
Anche OnTriggerEnter viene eseguito solo se su questo gameObject (o su uno dei gameObject padri) è presente un collider con la spunta "Is Trigger" e solo nel momento in cui avvenga una collisione.

Ovviamente esistono moltissimi altri metodi proprietari di uno script di Unity ma non potremmo vederli proprio tutti se non quelli più utili e usaati.
Potete trovare tutte le peculiarità del MonoBehaviour e dei suoi metodi su questa pagina ufficiale di Unity.

3 pensieri su “Panoramica su uno script in Unity

  1. Hey very nice site!! Man .. Beautiful .. Amazing .. I will bookmark your blog and take the feeds alsoI am happy to find a lot of useful info here in the post, we need work out more techniques in this regard, thanks for sharing. . . . . .

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *