Imparare C#Principianti

Approfondimento sulle Variabili

Approfondiamo un po’ la questione sulle variabili e sulla loro dichiarazione.
Come già detto, C# è un linguaggio fortemente tipizzato. Ogni variabile è di un certo tipo. Ovvero ogni variabile appartiene è di una certa tipologia, numero intero, numero con virgola, stringa di testo ecc…

Il compilatore usa le informazioni sul tipo anche per assicurarsi che tutte le operazioni eseguite nel codice siano fattibili. Se ad esempio si dichiara una variabile di tipo int (numero intero), il compilatore consente di usare questa variabile in operazioni di addizione e sottrazione. Se si provasse ad eseguire le stesse operazioni su una variabile di tipo bool (valore true o false), il compilatore genererebbe un errore, come illustrato nell’esempio seguente:

int a = 5; //Numero interno             
int b = 2;  //Numero intero
bool c = true; //Variabile bool

 //OK
int sum= a +b;

// Errore, non si può sommare un valore di tipo int e un valore di tipo bool
int sum2 = a + test;

Non volgio tediarvi troppo su questioni che al momento potrebbero solo confondervi le idee, dunque parleremo solo lo stretto necessario dei:

I modificatori d’accesso

Quando dichiariamo una variabile possiamo stabilire il suo “livello di accessibilità”, che controlla se potrà essere usata da altro codice. Per il momento a noi interessano solo i modificatori d’accesso public e private.
In realtà private non lo useremo mai, perché già nel momento in cui non specificheremo nessun modificatore d’accesso, avremmo sottinteso che esso è private e dunque sarà visibile e accessibile solo nella sua classe di appartenenza.

Concentriamoci dunque sul modificatore public.

Se provassimo a dichiarare due variabili così:

int test1;
public int test2;

avremmo dichiarato due normalissime variabili del tipo int, solo che test sarà private, cioè sarà accessibile solo all’interno della classe in cui è stata dichiarata, mentre test2, volendo, si potrà leggere, scrivere e modificare a piacimento anche da altri scripts.

La cosa più importante per noi che lavoriamo su Unity, sta nel fatto che una variabile pubblica potrà sarà visibile anche nell’inspector di Unity. A differenza di una variabile non pubblica.

 

Il modificatore static.

Questo modificatore sarà molto importante in futuro. Siamo in questa lezione proprio per approfondire e spiegare l’uso di questa parolina! Perché è leggermente più complicato capire il suo uso rispetto ai modificatori d’accesso che abbiamo trattato in poche righe qui sopra.
static non è un modificatore di accesso, infatti esso può essere specificato anche insieme ad un modificatore d’accesso, tipo:

pulic static int miaVariabile;

In questo modo abbiamo dichiarato una variabile che è pubblica, statica e di tipo int.

A cosa serve static?

static è un modificatore per dichiarare una variabile che appartenga alla classe invece che a un oggetto specifico. Ovvero, una variabile che non cambierà tra un oggetto e un altro ma sarà sempre lo stessa, con un valore unico, in comune a tutti gli oggetti di quella classe. E che dunque, quando cambierà, cambierà per tutti gli oggetti di quella classe.

Possiamo dire che una variabile statica è una variabile di classe e non di oggetto.


Facciamo chiarezza e approfondiamo sulla situazione.
Ogni volta che dichiariamo una variabile sappiamo che stiamo creando “una certa proprietà” a quella classe che sarà modificabile a piacimento per ogni oggetto di quella classe.

Riprendiamo l’esempio della palla fatta nella lezione sulle classi e sui metodi.
Avevamo dichiarato due variabili così che  oggetto della classe palla che avremmo creato, avrebbe potuto avere un determinato valore di peso e di attrito.
Dunque, ogni palla potrà avere un suo peso e un suo valore di attrito unici.
Rivediamo quell’esempio:

Questa volta però creiamo due sfere, con lo stesso script Palla attaccato.

public class Palla: MonoBehaviour  {

    public int pesoPalla;
    public int attritoPalla;
    

	void Rimbalzo () {
		//dai una spinta verso l'alto di 100 - pesoPalla
	}
	
	void Rotolamento () {
		//dai una spinta di rotazione alla palla di 10 - attritoPalla
	}
}

Lasciamo da parte i due metodi che avevamo inserito per fare l’esempio sui metodi e concentriamoci sulle variabili e la loro dichiarazione.

Notiamo che su ogni Palla abbiamo le due variabili visibili sull’inspector, perché appunto sono due variabili pubbliche.
Dall’inspector possiamo impostare i valori di rimbalzo e attrito come vogliamo.
Su una sfera possiamo mettere per esempio

peso = 2 e attrito = 10

e su l’altra

peso = 5 e attrito = 15


Ottimo, abbiamo due sfere differenti, in pratica due gameObject con delle caratteristiche differenti.

Proviamo ora ad aggiungere una variabile statica.
Pensiamo ad una caratteristica da assegnare ad una palla, per esempio la sua scala, di tipo float. Rendiamola sia pubblica che statica.

public class Palla: MonoBehaviour  {

    public int pesoPalla;
    public int attritoPalla;
    public static float scalaPalla;

	void Rimbalzo () {
		//dai una spinta verso l'alto di 100 - pesoPalla
	}
	
	void Rotolamento () {
		//dai una spinta di rotazione alla palla di 10 - attritoPalla
	}
}


Dov’è la variabile della scala? Eppure è pubblica! Perché non è visibile nell’inspector?

Tutto, nella norma, lo deve fare.
Per capire il perché di questa situazione, assegniamo davvero la scala alle sfere in base alla variabile scala che avviamo creato.
Per farlo dobbiamo moltiplicare la scala attuale del transform per la variabile scala.
Così:

transform.localScale *= scalaPalla;

In questo modo tutte e tre le componenti X,Y,Z saranno moltiplicate per il float scala.
Lo faremo dentro il metodo Start, così che l’operazione avvenga una sola volta e all’inizio dell’esecuzione della scena.

using UnityEngine;

public class Palla : MonoBehaviour
{

    public int pesoPalla;
    public int attritoPalla;
    public static float scalaPalla=2;

    void Start() {

        //Moltiplico la scala dell'oggetto per la variabile scala
        //con l'operatore *= è come se avessi scritto 
        //transform.localScale = transform.localScale * scala;
        transform.localScale *= scalaPalla; 

    }

    void Rimbalzo()
    {
        //dai una spinta verso l'alto di 100 - pesoPalla
    }

    void Rotolamento()
    {
        //dai una spinta di rotazione alla palla di 10 - attritoPalla
    }
}

Come abbiamo visto, per semplicità abbiamo usato l’operatore *=
Come descritto nel commento, con l’operatore *= è come se avessimo scritto:
” poni la scala attuale dell’oggetto uguale alla scala attuale dell’oggetto moltiplicato per la variabile scala”.

Ma torniamo alla questione del modificatore static.
Mandiamo in esecuzione la scena.

E si, a questo punto avremo due sfere belle grosse! :mrgreen: 
Come avevamo previsto, entrambe le sfere ora hanno la scala moltiplicata per 2f. Questo ci chiarisce l’utilità della parolina static.
La variabile statica scala è una proprietà della classe in cui l’abbiamo scritta, non degli oggetti specifici che poi andremo a creare. In questo caso tutti gli oggetti della classe palla, avranno la scala che gli abbiamo impostato.
Per questo motivo non può apparire nell’inspector di un singolo oggetto!

Che ce ne facciamo?

Di solito, quando si impara una cosa nuova, il pensiero va subito a “dove poter usare” la nuova nozione appresa. Non so a voi ma a me succede così. 😉 
E dove possiamo usare questa nozione nello sviluppo di un videogioco? A prima vista sembra quasi inutile.

Ma soffermatevi un attimo a pensare alla logica d’esecuzione di un gioco nel suo insieme.
Ci saranno gli oggetti, personaggi, edifici, ambiente e quant’altro. Tutti oggetti con le loro caratteristiche che renderemo uniche proprio per renderli differenti gli uni dagli altri.
Ma ci saranno delle variabili che dovranno essere uniche e persistenti per tutta la durata del gioco, dei valori che ci dovremmo portare tra le scene e che non dipenderanno da un oggetto specifico.
Prendiamo per esempio il punteggio del giocatore, oppure la sua energia, lo stato del gioco, se in pausa o no… e millemila altre cose. Queste variabili le potremmo impostare su static, perchè punteremo sempre allo stesso valore, unico per tutto il gioco.

L’importanza delle variabili statiche in Unity

Impereremo presto che, nel momento in cui ci sarà un passaggio di scena (per esempio tra un livello e l’altro), tutti i gameObjects nella scena verranno letteralmente distrutti. Cancellati per sempre. Non ne avremo più traccia nella scena appena caricata. Ed insieme a loro, saranno distrutte tutte le caratteristiche che avevano assunto durante la scena!
Ma le variabili statiche rimarranno inalterate perché appunto, non sono elementi applicati ai gameObjects che andranno distrutti al cambio di scena.
Vedremo in seguito che in gioco sarà sempre buona prassi creare un GameManager. Ovvero un normale gameObject che chiameremo GameManager su cui applicheremo uno script chiamato allo stesso modo, GameManager.cs.
Questo gameObject sarà sempre presente dall’inizio alla fine dell’esecuzione del gioco, sarà sempre lo stesso, con lo stesso script attaccato, pieno di variabili statiche. Anche al cambio di scena, esso rimarrà invariato e non verrà mai distrutto.
Dentro allo script GameManager.cs potrai inserire tutte quelle variabili (statiche) che ti potranno servire in ogni momento del gioco, a prescindere dalla scena in cui ti trovi. In pratica avrai dei dati sempre disponibili che non varieranno al caricamento di un’altra scena ma che potrai incrementare, variare, leggere ecc… come qualsiasi altra variabile.
E potrai leggerle e scriverle semplicemente con la riga GameManager.miaVariabile.

Per leggere una variabile statica non avremo bisogno dunque di “cercarla” in un singolo oggetto, ma la troveremo direttamente nella classe.

Esempio:

public class Giocatore: MonoBehaviour
{

public int miaVariabile1;

public static int miaVariabile2;

….

Abbiamo due variabili nella classe Giocatore, una statica e una no.
Per impostare per esempio un punteggio uguale a miaVariabile1, dovremmo andare su un oggetto della classe Giocatore.
Tipo:

public Giocatore oggetto = new Giocatore();

punteggio=oggetto.miaVariabile1;

dunque avremmo dovuto prima cercare un oggetto di classe Giocatore e di conseguenza andremo a leggere la variabile di quello specifico oggetto.
Per la variabile statica invece dovremmo semplicemente richiamarla così:

punteggio=Giocatore.miaVariabile2;

cioè richiamarla direttamente da Giocatore perché la variabile è parte della classe.

3 pensieri su “Approfondimento sulle Variabili

    1. Ciao Eden,
      non so quale siano le tue necessità nello specifico, ma sappi che una costante (const) è sempre statica e non è necessario definirla come static.
      Essendo una costante non modificabile essa sarà sempre fissa e uguale per ogni oggetto della classe.

Lascia un commento

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