Benvenuti nell'emozionante mondo della programmazione in C# per creare videogiochi e programmi vari con Unity! Sì, avete sentito bene, con questa nuova raccolta di articoli sarete in grado (forse) di creare i vostri giochi e sperimentare con la realtà virtuale!
Le bozze sono state scritte durante il lockdown, inizialmente consistevano in appunti personali presi durante i vari corsi affrontati per capire cosa si potesse fare per creare qualche giochino con il pc e mi permetto ora di pubblicarle, a distanza di tempo, con le idee più chiare e un po' di proggettini realizzati. Se quindi siete alla ricerca di un'attività divertente e creativa da fare in casa, avete trovato la soluzione perfetta. Imparare a programmare in C# con Unity vi darà la possibilità di esprimervi e di creare qualcosa di unico e speciale.
Quindi, se siete pronti a entrare nel mondo delle opportunità illimitate della programmazione in C# con Unity, prendete una bevanda calda, mettetevi comodi e preparatevi a divertirvi! Con un po' di studio e di applicazione, sarete in grado di creare giochi e altro.
Unity è un fantastico strumento vi darà la possibilità di creare qualsiasi cosa, dai giochi più complessi a delle semplici applicazioni in realtà virtuale. E il meglio di tutto è che non c'è bisogno di essere degli esperti programmatori per utilizzarlo. La licenza come uso personale o studente è gratuita e non è necessario pagare nulla finché si rimane nei $100.000 di fatturato annui.
E' possibile effettuare il download dal sito ufficiale: https://store.unity.com/#plans-individual
Si stima che ad oggi circa il 70% delle app su PlayStore usino come motore Unity che è veramente uno strumento eccezionale e modellabile alle proprie esigenze: tanto che si voglia fare un giochino in 2D o un gioco AAA, ci sono gli strumenti adatti e tanti plug-in eventualmente da aggiungere.
Dei tanti aspetti di Unity con questa raccolta di articoli vorrei coprire, almeno inizialmente, la creazione degli script che daranno vita agli oggetti di gioco. Unity utilizza ad oggi unicamente C# di Microsoft come linguaggio di programmazione (mentre quando avevo iniziato supportava ancora javascript) e offre una buona libreria di funzioni precompilate per vari aspetti del gioco come la fisica, le collisioni ecc.
Inoltre insieme al motore di Unity il programma permette di scaricare contemporaneamente Visual Studio Community 2019 e quindi vi ritroverete anche il programma Microsoft in licenza gratuita per scrivere il codice.
La difficoltà che ho incontrato da neofita sono state sicuramente legate al linguaggio di programmazione ed al fatto che nei vari corsi acquistati davano per scontato che lo studente avesse già una certa dimestichezza con il mezzo. Mi ha salvato santo youtube o meglio il santo Professor Camuso, non ricordo con precisione in quale liceo italiano insegni ma sono convinto che i suoi ragazzi siano veramente fortunati. Grazie davvero. In questi articoli allora vorrei aiutare chi come me non ha mai affrontato niente di simile. Allo stesso tempo, se masticate già pane e programmazione evitate di perdere tempo a leggere questi articoli, non fanno per voi.
Andiamo!
Due matematici, Jacopini e Bohm, hanno dimostrato che ogni linguaggio di programmazione per essere in grado di implementare ogni tipo di algoritmo deve dare la possibilità di organizzare le istruzioni secondo tre schemi, detti anche strutture:
1) Sequenziale
2) Selettiva
3) Iterativa
1) La struttura sequenziale è banale e prevede semplicemente che il flusso delle istruzioni proceda dall’alto verso il basso, in modo sequenziale, appunto, un istruzione dopo l’altra.
2) Una struttura selettiva, invece, consiste nel poter creare dei percorsi differenti da intraprendersi al verificarsi di diverse condizioni (in C# ciò si ottiene con le istruzioni if … else).
3) La struttura iterativa, o di ripetizione, infine, permette di ripetere delle istruzioni sfruttando la proprietà enumerativa (che si può contare) di una variabile dichiarata internamente per fare da contatore.
In C# e nei principali linguaggi di programmazione esiste un costrutto chiamato ciclo FOR (letteralmente ciclo PER): quindi per una variabile che inizia a contare da un minimo, si esegue una determinata istruzione a ripetizione, controllando prima di ripetere che la variabile non abbia raggiunto un massimo, potendo incrementare la varabile che funziona da contatore di una determinata quantità ad ogni iterazione.
es.
for (int i= 0; i< 10 ; i+= 1)1
{…}
diciamo che il ciclo for parte da una variabile i che rappresenta un numero intero, che parte da zero e si fermerà a 9 (i<10), ad ogni iterazione eseguirà l’istruzione sottostante o più istruzioni indicata nel blocco {} ed il for aggiungerà 1 unità alla variabile i, in modo che funzioni da contatore (volendo si può incrementare o diminuire il valore di i a proprio piacimento secondo la necessità di ciò che si vuole rappresentare).
(i += 1 è la stessa cosa che scrivere i = i + 1, è uno degli operatori logici.)
Si noti che la variabile l’abbiamo dichiarata all’interno del ciclo for in modo che sia valida solo all’interno di esso ed in tal modo non può interferire con altre variabile del programma. Non potrà quindi nemmeno interferire con la variabile i di un altro ciclo FOR. Volendo si può dichiarare la variabile anche esternamente ma bisognerà fare attenzione al codice per non avere poi comportamenti anomali in caso di altre istruzioni che vanno a modificare la variabile usata come contatore.
Il ciclo while
Il ciclo while è un altro costrutto iterativo ed esprime tutta la potenza dei calcolatori elettronici, infatti è possibile in poche righe di codice istruire il processore ad eseguire una moltitudine di calcoli fino a quando una condizione sia vera. Si definisce, infatti, come “struttura iterativa con controllo in testa con uscita per falso”.
While (espressione)
{
istruzione1;
istruzione2;
...altre…
}
Se volessimo replicare l’esempio fatto precedentemente per il ciclo for con il ciclo while, ciò sarebbe possibile: dovremmo dichiarare e inizializzare una variabile esternamente al ciclo while che funzioni da contatore ed immettere l’istruzione di incremento del contatore fino a quando questo sia inferiore a 10
int conta = 0;
while (conta<10)
conta++;
Notiamo come in questo caso il compilatore conti esattamente fino a 9 come con l’esempio fatto per il ciclo for, ma notiamo anche che:
la scrittura risulta meno compatta,
la variabile che funziona da contatore essendo esterna al ciclo può essere modificata anche da altre righe di codice.
L’ istruzione break
Si può uscire da un ciclo, for o while (ma anche do e foreach che vedremo in seguito) utilizzando l’istruzione break all’ avverarsi di una determinata condizione.
Basterà inserire una condizione selettiva di if(espressione) seguito dal comando break;
while (conta <= 10)
{
if (conta == 5)
{
break;
}
conta++;
}
Così facendo il ciclo si chiude a 5, anche se il ciclo while era stato istruito di arrivare fino a 10.
Il ciclo do...while
Si usa quando si vuole che una linea di comando o più linee vengano eseguite almeno una volta e ripetute poi fino a quando una condizione è vera con il ciclo while.
do
{
istruzione1;
istruzione2;
istruzione3
} while (espressione)
In questo caso il controllo non è più in testa come nel ciclo while semplice, ma alla fine. Lo trattiamo per in questo articolo perlo più per chiarezza, ed è importante conoscerlo per capire di cosa si tratta quando si incontra in script scritti da altri, in verità nulla vieterebbe di replicare il funzionamento del ciclo do while, semplicemente scrivendo il comando o i comandi che si vorrebbero eseguire almeno una volta e poi il ciclo while semplice con il controllo in testa.
Il comando continue
Se si volesse saltare parte del codice di un ciclo (do, while, for, foreach) all’avverarsi di una determinata condizione si può utilizzare il comando continue; dopo aver specificato quella condizione che si deve avverare con l’espressione selettiva if(espressione)
while (condizione)
{
istruzione1;
if(espressione)
continue;
istruzione2;
istruzione3;
}
In questo caso il ciclo while esegue sempre l’istruzione1 fino a compimento del ciclo, l’istruzione2 e l’istruzione3 vengono eseguite in tutti i casi tranne quando l’espressione if() è vera, in quel caso il continue fa saltare tutta quella parte di codice che lo segue e dopodiché il ciclo continua.
Il ciclo foreach
foreach (var nomevariabiledadichiarare in nomearray)
…
Va a compiere un istruzione o più istruzioni per ogni singola variabile contenuta in un array indicato.
Rispetto al ciclo for è più semplice da impostare ma soprattutto è più sicuro in quanto non si possono commettere errori. Infatti nel ciclo For per inesperienza si potrebbe sbagliare ad indicare il valore di partenza, ovvero che l’indice da utilizzare è 0 e non 1, oppure avere dubbi sulla condizione di terminazione se deve essere uguale o minore uguale, quanti sono gli elementi per impostare quella condizione o sbagliare l’incremento del contatore. Insomma tutti quei dubbi che possono venire a chi è alle prime armi.
In un articolo precedente (C# è un linguaggio orientato alle classi che descrivono oggetti ) abbiamo parlato di come sia possibile richiamare una variabile o un metodo da una classe ereditata oppure facente parte dello stesso namespace. Questo è sempre vero se indichiamo esplicitamente che essi siano pubblici , ovvero se indichiamo nella dichiarazione della variabile il livello di accesso public, altrimenti in C# il compilatore presume che il livello di accesso sia private, privato. Questa struttura dei livelli di accesso mette sulle classe una sorta di velo che le protegge e sta a noi dire esplicitamente quando alzare o meno il velo (ciò oltre a rendere più sicuro il codice fa risparmiare qualcosina in termini di performance).
Es.
public int a = 15
dichiariamo una variabile a di tipo intero che inizializziamo con il valore 15 e diciamo che può essere richiamata e modificata al di fuori della classe originale.
Ciò appena scritto con una variabile funziona, ma non è lo stato dell’arte in programmazione in quanto ci potrebbe esporre a possibili problemi futuri di malfunzionamento del codice nel caso che la variabile venisse modificata in un seconda classe, senza magari dei controlli preliminari necessari previsti nella classe originaria. Rendere publici metodi, invece, non presenta controindicazioni.
Per ovviare al problema ci vengono incontro le properties, ovvero delle variabili fantasma che possiamo rendere pubbliche e che vanno ad imitare le variabili vere e proprie che rimangono, invece, private.
Public int _a
{ get{ return a;}
set { (if value > 0 && value <100)
a = _a ;}
}
abbiamo quindi scritto una properties che imita la variabile a, che è pubblica e che ha due metodi, il metodo get che rende leggibile dall’esterno il valore di a (basterà richiamare _a che è pubblica che andrà a leggere il valore di a privata) ed un metodo set che invece permetterà di modificare dall’esterno il valore di a ma solo dopo un controllo (nel nostro esempio abbiamo chiesto che sia un numero intero positivo da 1 a 99).
E’ possibile scegliere un livello di accesso intermedio che nasconda lo stato interno di una classe all’esterno della classe ma che lo renda disponibile unicamente alle classi derivate dalla classe madre, ciò si indica con la parola protected
Esempio.
protected int a = 15;
in questo modo abbiamo dichiarato una variabile di nome a che rappresenta un numero intero, inizializzata con il valore 15 e che può essere letta e modificata da una classe figlia.
In una classe figlia si può dichiarare una variabile o un metodo con lo stesso nome di uno presente nella classe madre, in questo caso il compilatore di default fa riferimento a quella dichiarata nella classe figlia. Qualora si dovessero distinguere le due variabili con lo stesso nome, si può scrivendo this.nomeVariabile per indicare la variabile della classe figlia e base.nomeVariabile per indicare quella della classe madre.
Per creare un metodo in una classe ereditata con lo stesso nome di un metodo presente sulla classe madre è necessario indicare con la parola new che si va a sovrascrivere per quella classe il metodo che era presente sulla classe madre, nel caso fosse necessario richiamare il metodo della classe madre basta scrivere base.MetodoRichiesto().
La programmazione orientata agli oggetti (in inglese object-oriented programming, in acronimo OOP) caratteristica di C# si fonda su tre pilastri
L'erederietà in C# significa che una classe può lasciare una proprietà o una metodologia a una classe successiva. Questo consente agli utenti di creare delle classi simili alle proprie classe senza dover ricaricare il codice della classe originale. Ciò permette di “programmare per differenze”, utilizzando classi madre che raccolgano le proprietà e delle funzioni generali appartenente ad un tipo di oggetto e delle classi figlie per descrivere delle proprietà particolari che appartengono solo ad un oggetto specifico. Per esempio in un videogioco si potrebbe creare una classe che descriva gli umanoidi raccogliendo diverse proprietà e metodi due sottoclassi figlie “buoni” e “cattivi”. Così facendo senza dover replicare tutto il codice da zero per le varie proprietà (altezza, peso, colore capelli, divisa, ecc ecc), si va a pescare dalla classe madre (in modo tale che in caso di manutenzione del codice si andrà a modificare il codice una volta soltanto nella classe madre) e si programma per differenza solo dei comportamenti specifici che devono compiere tali personaggi.
Modularità & information hiding, nel caso di progetti grandi a più mani può essere indispensabile dividere il lavori in più parti, moduli, ed affidarli a diversi sviluppatori. Il singolo sviluppatore non può o non deve essere a conoscenza di ogni singola riga di codice dei moduli sviluppati dagli altri sviluppatori, ma egli vede solo il minimo ed indispensabile previsto dai colleghi. Infatti può essere pericoloso dare la possibilità di effettuare assegnamenti diretti ad un variabile da un altro modulo da parte di un soggetto che non ne conosce pienamente il funzionamento, bypassando eventuali controlli sui valori immessi, in questi contesti C# lavora egregiamente offrendo dei livelli di accesso alle singole variabili o metodi rendendoli accessibili oppure nascondendoli.
Il livello di protezione di una variabile in C# determina la visibilità e l'accessibilità della variabile all'interno del codice del programma. Ci sono tre livelli di protezione in C#: public, private e protected.
Public: Una variabile dichiarata come public è accessibile da qualsiasi parte del codice, che si trovi all'interno o all'esterno della classe che la contiene. Questo livello di protezione è utile per le variabili che devono essere condivise tra diverse parti del codice.
Private: Una variabile dichiarata come private è accessibile solo all'interno della classe che la contiene. Questo livello di protezione è utile per le variabili che non devono essere accessibili da altre parti del codice e che devono essere protette da modifiche indesiderate.
Protected: Una variabile dichiarata come protected è accessibile solo all'interno della classe che la contiene e dalle classi che ereditano da essa. Questo livello di protezione è utile per le variabili che devono essere condivise tra le classi ereditate, ma che non devono essere accessibili da altre parti del codice.
In generale, si consiglia di dichiarare le variabili private o protected se non sono necessari accessi esterni e di dichiarare le variabili public se è necessario condividerle con altre parti del codice. Questo aiuta a mantenere la sicurezza e l'integrità del codice, limitando l'accesso alle varibili.
In c# ogni istruzione deve terminare con il punto e virgola ; altrimenti il compilatore restituisce un errore.
Non c’è una regola precisa di scrittura per usare il minuscolo o maiuscolo, ma dobbiamo tener ben presente che vengono intese come lettere differenti (il linguaggio si dice case sensitive): allora la variabile Peso sarà diversa dalla variabile peso o dalla variabile peSo.
Un identificatore può contenere un numero all’interno del suo nome, ma è importante che questo non si trovi mai all’inizio della parola, altrimenti ciò genererebbe confusione per compilatore che si aspetterebbe di dover lavorare con un numero e non con una variabile dichiarata: quindi potremmo scrivere una variabile come posizioneNemico1 ma mai e poi mai 1nemicoPosizione.
Non si possono usare spazi o caratteri speciali usati come operatori per separare parole più lunghe, perché anche questo manderebbe in confusione il compilatore, allora per distinguere le parole o identificatori un po’ lunghi ci sono diverse tecniche, una che mi piace è quella di iniziare con la prima parola scritta in minuscolo e le successive con la prima lettera in maiuscolo, come abbiamo già scritto le variabiliPrecedenti. Unica eccezione di carattere speciale che si può usare è l’underscore, variabile_esempio, ma mai il trattino “ - ”che il compilatore interpreterebbe come operazione di sottrazione.
Esiste inoltre una convenzione accettata dagli sviluppatore di tutto il mondo di scrivere tutto in maiuscolo solo gli indicatori che rappresentano una costante e non una variabile, ovvero che non cambiano mai il proprio valore una volta inizializzato.
Altra convenzione generalmente accettata è quella di nominare le classi con con la prima lettera maiuscola e le parole separate da una lettera maiuscola: ClasseDiEsempi.
Scrivere codice ben strutturato e ben organizzato è importante per garantire la leggibilità e la manutenibilità del codice. In C#, ci sono alcune regole che possono aiutare a scrivere codice di qualità:
Utilizzare commenti: I commenti sono un'ottima risorsa per spiegare il codice e aiutare altri sviluppatori a capire ciò che il codice sta facendo. È importante utilizzare commenti adeguati per ogni metodo e sezione di codice. Un commento si introduce con i seguenti caratteri // .
Utilizzare metodi per la risoluzione dei problemi: I metodi sono un'ottima risorsa per rendere il codice più leggibile e manutenibile. È importante suddividere il codice in metodi separati per ogni compito principale.
Mantenere una buona struttura di codice: Mantenere una buona struttura di codice è importante per garantire la leggibilità e la manutenibilità del codice. Ad esempio, è importante utilizzare indentazione e spaziatura adeguata per rendere il codice più leggibile.
In generale, seguire queste regole di scrittura del codice aiuta a garantire che il codice sia ben strutturato, leggibile e manutenibile. Ciò rende più semplice per gli altri sviluppatori comprendere e modificare il codice in futuro. Inoltre, queste buone pratiche di codifica possono anche aiutare a prevenire errori e problemi di codice.
Le variabili determinano lo stato interno di un oggetto in una determinata classe, cioè le sue caratteristiche in quella classe. Prima di utilizzare una variabile è sempre necessario prima dichiararla, ovvero andare a specificare di che tipo è, diversamente il compilatore non potrebbe andare a controllare il tipo di utilizzo che faremmo con quel tipo di variabile. C# è infatti un linguaggio rigoroso, fortemente tipizzato, che, fortunatamente, non permette di commettere errori con i tipi di variabili, errori che altrimenti sarebbero difficili da trovare successivamente.
Per buona abitudine sarebbe sempre consigliabile inizializzare un variabile, ovvero dargli un valore, subito al momento della dichiarazione, perché non è detto che il compilatore gli attribuisca in automatico il valore 0, infatti, nulla vieta che possa attribuirgli di ufficio un valore random che potrebbe comportare funzionamenti anomali del nostro software.
Le variabili di tipo primitivo in C# sono una delle parti più fondamentali della programmazione in questo linguaggio. Come suggerisce il nome, questi tipi rappresentano i valori più semplici e comuni utilizzati nella programmazione. Ecco una panoramica approfondita delle variabili di tipo primitivo in C#.
int: Questo tipo rappresenta un intero a 32 bit, ovvero un numero intero senza decimali. Gli interi possono essere utilizzati per contare, calcolare e rappresentare valori quantitativi.
float: Questo tipo rappresenta un numero a virgola mobile a singola precisione, ovvero un numero con decimali. I numeri a virgola mobile sono utilizzati per rappresentare valori continui, come ad esempio la temperatura o la velocità.
double: Questo tipo è simile al tipo float, ma con una precisione doppia. I numeri double sono utilizzati per rappresentare valori continui con una maggiore precisione rispetto ai float.
char: Questo tipo rappresenta un singolo carattere, come ad esempio una lettera, un simbolo o un numero. I caratteri sono utilizzati per rappresentare valori alfabetici o simbolici.
bool: Questo tipo rappresenta un valore booleano, ovvero vero o falso. I valori booleani sono utilizzati per rappresentare condizioni in un programma, come ad esempio se un'operazione è stata eseguita con successo o no.
string: Questo tipo rappresenta una stringa di testo, ovvero una sequenza di caratteri. Le stringhe sono utilizzate per rappresentare testo, indirizzi e altri valori alfabetici.
In conclusione, le variabili di tipo primitivo in C# sono un elemento fondamentale per la programmazione in questo linguaggio. Ogni tipo primitivo ha le sue particolari caratteristiche e usi, e conoscerli a fondo è importante per sviluppare programmi efficienti e ben strutturati.
La classe è una delle strutture fondamentali in C#, un linguaggio di programmazione orientato agli oggetti. Una classe rappresenta un modello per gli oggetti che sono istanze di quel modello. Una classe descrive le proprietà e le metodologie specifiche per un determinato tipo di dati, "incapsulando" le caratteristiche descrittive degli oggetti della classe e i comandi che verranno utilizzati.
La classe quindi è una porzione di codice che descrive il comportamento di determinati oggetti software. Viceversa gli oggetti sono istanze del modello che chiamiamo classe.
Il concetto di classe fu introdotto nel linguaggio di programmazione C++ come evoluzione del linguaggio C, ed è ormai utilizzato dalla maggior parte dei linguaggi di alto livello poiché permette una più efficiente scrittura del codice (è una metodologia veloce in fase di scrittura ed il codice così generato è facilmente leggibile).
Grazie alla sua flessibilità e alla sua capacità di semplificare la scrittura del codice, le classi sono diventate una componente fondamentale della programmazione moderna.
E’ di cardinale importanza comprendere cosa siano le classi, inoltre, dal momento che le richiameremo in continuazione e ne creeremo di nuove ogni qual volta che scriveremo degli script per Unity. Tanto è vero che il linguaggio di programmazione che utilizziamo per compilare gli script, il C# , è un linguaggio orientato ad oggetti ma che potremmo benissimo definire come “un linguaggio orientato alle classi che descrivono oggetti”.
Per comprendere la funzione di una classe, immaginate di voler descrivere una famiglia in C#. Questa descrizione verrà inserita nella classe Famiglia, dove ogni membro della famiglia sarà rappresentato da un oggetto della classe. Variabili come nome, età, sesso, peso, e altezza verranno dichiarate per differenziare gli oggetti l'uno dall'altro, i membri della famiglia. Inoltre, nella classe potrete definire metodi per impartire comandi al microprocessore, come ad esempio stampare l'elenco di tutti i membri della famiglia o la scheda di ogni individuo.
La classe Famiglia potrebbe essere derivata da una classe più generica, come Persone, dalla quale potete richiamare metodi e variabili. A sua volta, una nuova classe Figli potrebbe essere derivata dalla classe Famiglia per descrivere aspetti unici degli oggetti Figli. In un altro script, potrete richiamare un oggetto della classe (ad esempio, un membro della famiglia) utilizzando il punto "." come carattere di accesso.
Bisogna, dopo essersi assicurati di avere i requisiti d’accesso a quella classe (si vedrà più avanti che una classe può bloccare o meno l’accesso dall’esterno della stessa a secondo che si siano dichiarate determinate proprietà), indicare il nome della classe seguito dal punto e poi dal nome dell’oggetto che vogliamo richiamare, in questo modo: nomedellaclasse.oggetto , allo stesso modo si potrebbe richiamare una singola variabile attribuita ad un determinato oggetto, es. famiglia.padre.peso . Così facendo è possibile risparmiare tantissimo tempo a riscrivere porzioni di codice già scritto e come ben si comprende tutto rimane organizzato e diviso nelle classi.
Basti pensare che stesso Unity offre utilissime classi precompilate per tantissimi aspetti del gioco, basterà richiamare nello script le namespace, ovvero le cartelle che contengono determinate classi, utilizzando la parolina using (direttive che vedremo più dettagliatamente in seguito) ciò permette di sfruttare subito un potentissimo motore di gioco senza averne la piena comprensione (il lavoro dietro l’engine è mastodontico) e di andare a richiamare e/o modificare solo quegli oggetti software che ci servono per il nostro gioco.
Quando andremo a creare uno script su Unity, in un file.cs, generalmente si andranno a richiamare i namespace delle classi preesistenti che ci serviranno per quella specifica situazione e si scriverà una e soltanto una nuova classe. Questo è soprattutto vero nella stragrande maggioranza dei casi in cui le nuovi classi sono derivate dalla classe originaria UnityEngine (come la usatissima classe MonoBehaviour) di Unity, in caso di due o più classi su un file si avrebbe un messaggio di errore nella compilazione. Unity, infatti, va a controllare la corrispondenza univoca tra il nome del file dello script ed il nome della classe (se modificate il nome di una classe ricordate sempre di modificare con lo stesso nome anche il nome del file *.cs). In altri ambiti nulla ci vieterebbe in verità di poter scrivere più classi in un singolo file di script. Ma questo non rappresenta un limite di Unity. Oltre ad una questione puramente tecnica, mantenendo gli script bene divisi e organizzati sarà più semplice andarli a ripescare in un secondo momento. O meglio, in caso di lavoro a più mani, chi dovrà interagire con il vostro lavoro sicuramente opererà in maniera più agevole se tutto è ben ordinato e a portata di mano. Ciò vale sia per gli script che per tutti i componenti di Unity: organizzare il lavoro in maniera ordinata Vi consentirà di risparmiare tempo e fatica nei momenti successivi.
Differenza tra gli object di C# e i game object di Unity
A scansi di futuri equivoci dobbiamo già da ora chiarire una cosa fondamentale: anche se il loro nome può creare confusione, gli oggetti in C# non sono la stessa cosa dei game object di Unity.
In C#, i namespace sono formati da un gruppo di classi e metodi che possono essere utilizzati in modo coordinato per gestire una particolare funzionalità.
Abbiamo già accennato ai namespace definendoli “cartelle”, senza essere ortodossi, infatti, il concetto è molto simile, si possono raggruppare diverse class sotto un determinato namespace, una sorta di contenitore (come fosse una cartella per i file del computer) in modo che i vari script contenuti in esso possano comunicare tra di loro. I namespace forniscono una struttura organizzativa che consente agli utenti di specificare la posizione dei loro elementi. Ad esempio, le classi in un progetto di programmazione possono facilmente essere raggruppate in namespace come "Modelli" o "Interfaccia Utente", in modo tale da indicare la loro posizione nell'applicazione. Questo permette che si possano caricare variabili e metodi da altre classi contenute nello stesso namespace, tenendo tutto ordinato e separato senza generare confusione tra gli script. Nei progetti più grandi, infatti, sono presenti tante classi che descrivono oggetti differenti ma che probabilmente contengono variabili con gli stessi nomi di altre variabili contenute in altre classi, cosa che potrebbe mandare in tilt il compilatore.
Per esempio immaginiamo di aver scritto uno script che indichi il movimento del giocatore, e aver replicato in larga parte il codice per indicare il movimento dei nemici. Se fosse tutto mischiato nello stesso namespace sarebbe impossibile richiamare una variabile che indichi la posizione iniziale (dichiarata in entrambi gli script come var posizioneIniziale), il compilatore non saprebbe se intendiamo la posizione iniziale del giocatore o del nemico. Dovremmo essere sicuri di usare per ogni script nomi diversi: cosa possibile nei progetti più piccoli, ma che diventa impossibile nei progetti più grandi; o semplicemente tenere tutto separato con namespace differenti.
Ogni variabile quindi è valida, fino ad indicazione contraria, solo nello scope nella classe in cui è dichiarata. Volendola caricare in un altro script si deve richiamare quella determinata class dichiarando di usare quel determinato namespace.
Per dichiarare che una classe faccia parte di un determinato namespace bisogna scriverlo prima di scrivere la class vera e propria:
Es.
namespace Nemico {
public class Controller1 : MonoBehaviour { ... }
}
Successivamente si può caricare in un altro script quel determinato namespace indicando ad inizio script la dicitura using nomeDelNamespace.
Es.
using Nemico;