Salve a tutti, cari FollowHz!
Stiamo sempre più entrando nel vivo dello sviluppo di videogiochi, come noterete. Piccola premessa sempre d’obbligo, se non l’avete ancora fatto, leggete l’articolo precedente qui per poter capire ciò che spiegherò in questo.
Dopo aver aperto Unity, create un oggetto col tasto destro sulla gerarchia ed approfittiamo di questo momento per vedere ciò che non abbiamo visto nello scorso tutorial:
L’Empty Object è un oggetto vuoto, di default invisibile e che in questo progetto non ci servirà;
3DObject ci creerà in scena un oggetto 3D a seconda di quel che sceglieremo (quello 2D crea altri oggetti, ma non ci interessa).
Le altre cose sono abbastanza intuibili, ma le approfondiremo a bisogno, specialmente per la UI.
Per ora, create un Cube scegliendo 3DObject e, tramite lo strumento in alto di Rect Tool, lo allungheremo con un certo buon senso, considerando che sarà il terreno su cui oscillerà il nostro secchiello. Dopodiché, per aiutarci, chiamate tale oggetto “Field” e, dopo aver cliccato su “Add Component”, cercate “Box Collider”. Dopo poche lettere, Unity dovrebbe avervi già trovato il componente scelto e cliccate su quello 3D (ovvero, quello dove non è specificato 2D). Automaticamente, essendo un oggetto nato da Unity su Unity, il collider, essendo un box, aderirà perfettamente alla forma rettangolare del nostro Field. Bene, per il terreno è tutto: ora, se l’altro oggetto con cui andrà in collisione non è triggerato (esattamente come il Field), l’altro oggetto non passerà.
Successivamente, create un altro cubo e, stavolta, non modificate la sua dimensione. Ma… un momento, tutto bianco così è un disastro, non si distinguono gli oggetti come in figura:
Diamogli un po’ di colore: tasto destro nella tab “Project” e scegliete material. Verrà creato un material che potete chiamare come vi pare: selezionatelo e affianco la parola Albedo, cliccate sul bianco e decidete il colore. Dopodiché, trascinate quel material nell’oggetto che volete. Per far prima, per il material dell’oggetto successivo, duplicate con Ctrl+D il material, cambiategli colore e trascinatelo sull’altro oggetto.
Dopodiché, potete creare altri due o più cubi sopra di esso: mi raccomando, per evitare problemi sulle collisioni, state attenti che tutti questi oggetti in scena siano sullo stesso asse Z (solitamente a 0, impostabile come abbiamo visto nello scorso tutorial). Questi cubi superiori saranno i nostri Galli, quindi potete già chiamarli Chicken, mentre il cubo centrale sarà il nostro Bucket che muoveremo in gioco per raccogliere le uova.
Ora, concentriamoci sul Bucket e aggiungete uno script che chiameremo banalmente “PlayerCtrl” sempre da Add Component. Appena avrete inserito lo script come spiegato nel precedente articolo, cliccate due volte su di esso da Project o nella parte centrale del suo componente script. Se è tutto settato correttamente, dovreste averlo aperto con successo in Visual Studio, o dal vostro compilatore di fiducia.
Ciò che vedrete, è più semplice di quel che sembra:
Prima di tutto, troviamo dei comandi che iniziano con “using” e rappresentano le librerie usate nello script, cioè, un vocabolario che fa capire al nostro compilatore cosa stiamo scrivendo ma, per ora, non ci interessano.
Subito dopo, troviamo la classe che è fondamentale abbia lo stesso nome dello script, altrimenti Unity collasserà finché i due nomi non corrispondono, ma se è tutto fatto correttamente, questo problema non dovrebbe esserci.
I cicli di vita, dei quali vedete di default due passaggi, li affronteremo nel dettaglio prossimamente. Per ora, vi basti sapere che tutto ciò che è scritto in Start avviene solo una volta, all’inizio della nascita di un oggetto (se l’oggetto è vivo all’avvio del gioco, si eseguirà immediatamente), mentre nel void Update, cioè il metodo Update, ci sono tutte quelle operazioni che, se non ci sono altre indicazioni, di default si susseguiranno per sempre per tutta la vita dell’oggetto.
Ed è qui che noi andremo ad operare con l’inserimento dell’input del nostro Player Bucket dato che l’input è forse l’evento più frequente che può accadere in un gioco. Quindi, per controllare che l’utente prema un input, per chi ha già avuto esperienza con linguaggi basati sul C sarà una passeggiata, perché scriveremo come vedete in figura:
Per chi legga degli incomprensibili geroglifici, invece, la spiegazione è presto detta: con la struttura if, noi stiamo chiedendo all’oggetto di controllare se si verifica una condizione qualsiasi che viene precisata all’interno di queste parentesi. Al loro interno, quindi, mettiamo ciò che vogliamo sapere, e qui non è più C# puro ma, grazie alla libreria richiamata nella riga “using UnityEngine”, il nostro compilatore di fiducia, capirà che Input.GetKey(KeyCode.A) sta a significare che l’oggetto che segue tale copione, eseguirà l’istruzione all’interno della condizione solo SE/FINCHE’ il giocatore premerà il pulsante A. Una forma equivalente è if(Input.GetKey(“a”)) che indica l’identica condizione. Ora, veniamo al suo interno: per muovere un oggetto in Unity, esistono tantissimi modi, ma per ora useremo il movimento tramite rigidbody poiché lo trovo uno dei più semplici e migliori poiché colliderà benissimo automaticamente senza troppe pretese. RB è il nome più mainstream usato per questa variabile, ma potete chiamarla come volete, basta che, come vedete, sia di tipo Rigidbody. Dopodiché, per questione di ottimizzazione, gli ho detto, nello Start, che quando esso prenderà vita, dovrà memorizzarsi tutti i metodi di Rigidbody, cioè MovePosition, nel nostro caso. L’ottimizzazione consiste nel dichiarare questo GetComponent all’interno dello Start cosicché quest’operazione la farà solo una volta, quando nasce e non ogni volta che si preme il pulsante. In questo modo, lui conosce il MovePosition e lo applicherà solo quando avrà ricevuto l’input, ma la fatica di aver controllato il Rigidbody l’ha già fatto appena nato.
All’interno di tale metodo, cioè nelle sue parentesi, mettiamo transform.position che sta a significare la sua posizione di partenza, ovvero, quella attuale (che ricava dalla componente transform che vi ho già spiegato nell’articolo precedente) e, mi raccomando, in questo caso, “transform” dovrà essere scritto in minuscolo sia perché C# è keysensitive, ovvero, che per lui una variabile scritta in maiuscola o minuscola sono due variabili diverse, sia perché per la libreria di UnityEngine, Transform e transform indicano due cose diverse. Successivamente, tale vettore transform (rappresentato dai 3 assi, come vi ricorderete), verrà sottratto al vettore “transform.right” che è uno dei tanti vettori settati di default che dovrebbe muovere l’oggetto a destra ma, dato che eseguiamo la sottrazione “transform.position-transform.right“, andrà dalla parte opposta, cioè a sinistra perché nel MovePosition non viene accettato transform.left, forse proprio perché per muovere a sinistra l’oggetto si sottrae semplicemente il suo movimento a destra. Nel caso in cui, come per me, la semplice forza con cui l’oggetto viene spostato a sinistra non ci basterà, moltiplicate come ho fatto io tale operazione a Speed, che è una variabile intera, ovvero un numero che mi sono inventato io sufficientemente alto ma non troppo che mi permette di muovere con abbastanza forza il player, ma la cosa importante è che moltiplichiate il tutto a Time.deltaTime. Questa variabile, standard della libreria, sta a significare che tutta questa operazione deve essere limitata, cioè sincronizzata, al tempo normale di gioco. Se la omettete, vedrete la magia di un oggetto sparato verso sinistra a tutta velocità.
La stessa cosa, come vedete, l’ho fatta per il movimento a destra, mettendo il “+” dato che ora vogliamo che l’oggetto si sposti a destra premendo D. L’unica differenza è Else If. Di if non c’è limite ed indicano molteplici condizioni che possono verificarsi anche assieme. Esiste, inoltre, l’Else che, al suo interno, non ha condizioni, poiché lui da solo sta a significare che se si verificano tutti gli altri casi, diversi dai casi precisati dentro ogni if, verrà eseguito il codice all’interno dell’Else.
Else If, come fa supporre il nome, è una fusione tra i due concetti, ovvero: viene precisata la condizione, come vedete nel mio script, ma escludendo l’avvenuta degli altri if: o una cosa o l’altra. In questo caso specifico, il risultato sarà che, se il giocatore tiene premuto A e D insieme, l’oggetto si muoverà a sinistra poiché prevale la prima condizione. Se mettete due semplici if, l’esito sarà del tutto imprevedibile, dato che entrambi gli if possono avvenire nello stesso momento.
Ultima cosa da fare se ancora non l’avete fatta: aggiungete all’oggetto “Bucket” un Box Collider non triggerato e un Rigidbody freezando tutte le posizioni (e le rotazioni), tranne la posizione sull’asse X, dato che sarà l’unico asse su cui si dovrà muovere il nostro “Bucket”, così da evitare deviazioni indesiderate da parte delle collisioni non triggerate.
Questo è quanto: in questo modo, il vostro cubo dovrebbe riuscire a muoversi a destra e a sinistra tranquillamente (ma non esagerate, perché ancora non l’abbiamo bloccato in un’area delimitata).