Creare un gioco 2D con Unity 4.3 - Introduzione

In questo corso impareremo come realizzare un piccolo 'shoot'em up' utilizzando le nuove funzionalità 2D di Unity 4.3.
Realizzeremo uno shut em up a scorrimento orizzontale, ma le nozioni apprese potranno essere utilizzate anche per altri generi di gioco.

Se non siete già in possesso di un Unity 3D nella versione 4.3 è possibile scaricarla liberamente dal sito ufficiale. Per comodità riportiamo il link di seguito:


Una volta terminato il download basterà lanciare l'installazione e scegliere 'Activate the free version of Unity' nella finestra di registrazione.

Insieme con Unity verrà installato MonoDevelop che ci aiuterà nella stesura degli script di gioco.
Terminata l'installazione di Unity avviando Unity ci verrà mostarta la finestra di creazione di un nuovo progetto. In alternativa se abbiamo Unity già installato possiamo utilizzare la voce di menù File->New Project.

Selezioniamo nel menù a tendina in basso 2D, e lasciamo tutte le caselle di scelta dei package deselezionate. Per il momento non ne abbiamo bisogno, e se dovesse essercene bisogno è possibile importare un package in un secondo momento.



Il nome della cartella scelta  non ha niente a che vedere con il nome che daremo al gioco, questo infatti verrà impostato nelle proprietà di progetto. Quindi siamo liberi di  scegliere la cartella che più ci fa comodo.

Dopo aver confermato il tutto con il bottone Create ci viene presentata l'interfaccia di default di Unity.



Il layout di Unity è liberamente configurabile. Tramite il menù in alto a destra è possibile scegliere tra varie configurazioni predefinite, o salvare la disposizione dello schermo che ci siamo costruiti trascinando i vari pannelli nelle posizioni più comode.

In questo tutorial utilizzeremo il layout predefinito 2 by 3 che si presenta come nella figura seguente.


A questo punto prima, di iniziare a creare il nostro gioco, diamo una piccola pre organizzazione al progetto.

Prima di tutto creiamo delle cartelle per organizzare meglio tutte le risorse che andremo a realizzare o da importare nel gioco. Premiamo il tasto destro del mouse sulla cartella Assets e selezioniamo Create->Folder e rinominiamo la cartella creata in Prefabs.



Ripetiamo l'operazione per più volte fino ad ottenere la seguente struttura di cartelle (Prefabs,Scenes,Scripts,Sounds,Textures).



NB Le cartelle che abbiamo creato all'interno di Unity, corrispondono a delle cartelle reali all'interno della directory scelta in fase di creazione del progetto.

Vediamo quindi come organizzeremo i nostri files in queste cartelle.

In Prefabs andremo a salvare tutti i modelli di oggetti riutilizzabili all'interno del gioco, i cosidetti prefab.  Un prefab, in pratica, è un template  di cui è possibile crearne innumerevoli copie da utilizzare nelle scene di gioco. Per fare un paragone in termini informatici, un prefab è una classe di cui se ne possono creare delle istanze.

In Scenes andremo a salvare le scene di gioco. Una scena è in Unity un  livello o un menu.

Contrariamente agli altri oggetti creati nel riquadro "Project", le scene vengono utilizzando il menu "File". Se si desidera creare una scena, cliccare sul sottomenu "New Scene". Non dimenticate di salvarlo nella cartella "Scene".

NB Le scene in Unity devono essere salvate manualmente. E' un errore classico quando si  usa Unity di dimenticarsi di salvare le modifiche ad una scena ed a i suoi elementi .

La cartella Sounds non necessita spiegazioni, in essa ovviamente verranno salvati tutti i file degli effetti sonori.

Analogamente la cartella Scripts conterrà tutti i file di programma in C#, UnityScript e Boo.

Infine la cartella Texture  contiene tutti i file di grafica (sprite e immagini) del gioco. E' importante nominare questa cartella Texture poichè Unity automatizza molte funzioni in base al nome di questa cartella.

A questo punto siamo pronti per la prossima lezione: Creazione della prima scena di gioco

Creare un gioco 2D con Unity 4.3 - La scena di gioco

Tutti gli oggetti di una scena di gioco sono gestibili all'interno del pannello 'Hierarchy'. Gli oggetti, che in Unity si chiamano 'game object' possono essere organizzati in maniera gerarchica, in una struttura ad albero.
Ciascun oggetto può essere creato o direttamente nella radice scena o come figlio di un altro oggetto. Questo modo di lavorare consente una migliore organizzazione degli oggetti di  gioco e in un qualsiasi momento è possibile trascinare un oggetto da un nodo ad un altro portandosi dietro tutti i nodi figlio.
Unity permette di creare, tra i vari oggetti di gioco, anche degli oggetti vuoti. Questi oggetti possono essere utilizzati alla stregua di cartelle o contenitori per raggruppare gli elementi in maniera logica. Ad esempio possiamo creare un oggetto vuoto, chiamiamolo ad esempio Enemies, e aggiungere come figli di questo nodo tutti i nemici e mostri che abbiamo a disposizione nel nostro gioco. In termini di risultato di gioco finale non c'è nessuna differenza tra l'aggiungere i nemici direttamente nella radice  della scena o come figli del nodo Enemies. Tuttavia nel secondo caso lo  sviluppo è più ordinato e chiaro.

Dopo questa premessa andiamo quindi a creare tutti gli oggetti di gioco vuoti che avranno la funzione di cartelle atte a ordinare tutti gli oggetti reali che visualizzeremo nella scena.

Unity, crea ogni scena con un oggetto Camera di default. Creiamo quindi un oggetto vuoto, con funzione di cartella,e nominiamolo Render.
Per creare un oggetto vuoto ,occorre selezionare del menù in alto GameObject -> Create Empty.


Una volta creato trasciniamo l'oggetto Camera al suo interno. Per il momento questo nodo conterrà solo la videocamera di gioco, ma è qui che andremo ad aggiungere in futuro anche le luci.

Ripetiamo l'operazione creando altri due oggetti: Scripts e Level.
In Script aggiungeremo gli script di gioco che non sono strettamente legati ad un oggetto in particolare. Ad esempio potremmo inserire in questo nodo uno script che fa da manager a tutto il gioco.

Level conterrà invece tutti gli oggetti visibili nella scena. In particolare gli oggetti dello sfondo (background), gli oggetti in primo piano (foreground) come giocatore e nemici, e gli oggetti nel  mezzo (middleground) tra il giocatore e lo sfondo come alberi e case.
Visto che già sappiamo cosa conterrà il Level, creiamo in esso i tre nodi appena descritti. Ripetiamo la creazione dei seguenti tre oggetti vuoti e posizioniamoli all'interno di Level: Background, Middleground, Foreground.

La struttura finale sarà:


 




Creare un gioco 2D con Unity 4.3 - Lo sfondo di gioco

In questa lezione vedremo come realizzare lo sfondo del nostro gioco ed inizieremo a prendere confidenza con il concetto di sprite.
Per prima cosa procuriamoci la grafica. Visto che il nostro gioco è uno sparatutto orizzontale una fantastica ambientazione stellare interplanetaria è decisamente adeguata.



Salviamo l'immagine di sopra in una cartella del nostro hard disk (tasto desto del mouse sull'immagine e Salva Immagine Come).
Dopo aver salvato l'immagine torniamo ad Unity e selezioniamo la cartella Assets-Textures e con il  tasto destro del mouse "Import New Asset". Ricerchiamo il file appena scaricato e importiamolo.




In alternativa possiamo trascinare direttamente il file da esplora risorse del computer nella cartella Textures di Unity.

Dal menù Game Object -> Create Other -> Create Sprite creiamo uno sprite e nominiamolo Space.

Uno Sprite, nella terminologia dei videogiochi, è una immagine, statica o in movimento, visualizzata all'interno della scena di gioco. Realizzare un  gioco quindi non è altro che gestire un insieme di sprites che interagiscono tra di loro.

Assegniamo quindi l'immagine importata in Textures allo sprite appena creato. Per fare questo facciamo click sul simbolo cerchiato di rosso dell'immagine di sotto e scegliamo l'unica immagine che compare.


La nostra scena di gioco apparrà popolata da un fantasticocielo stellato. Lo sprite appena creato è stato posizionato in automatico nella radice della scenadi gioco. Provvediamo a fare un po' di ordine trascinandolo nella cartella Background.



 Aggiungiamo ora qualche pianetino.

Ripetiamo l'operazione precedente con l'immagine di sopra. Come avrete notato questa volta l'immagine contiene più sprite. Vediamo quindi come estrarre i singoli sprite uno per uno. Nel pannello Inspector della texture, impostiamo lo Sprite Mode a multiple. Apparirà un pulsante con scritto Sprite Editor.


Nella finestra che appare impostiamo il Type ad automatic e la Minimum Size a 32, quindi premiamo il pulsante Slice .


Unity dovrebbe dividere in automatico i singoli sprite. Se così non fosse, impostate la modalita Type a Manual e ritagliate manualmente i singoli pianeti.
Terminato il lavoro premete il tasto Apply e vi ritroverete tutti gli sprite creati in automatico.
Divertitevi a trascinarli  nella scena di gioco, posizionandoli nel nodo Middleground, per creare un' ambientazione spaziale realistica.


A questo punto cerchiamo di capire il perchè dei tre livelli Background, Middleground e Foreground.
Affinchè la scena venga rappresenatata in maniera corretta è necessario che lo sfondo (background) venga disegnato per primo, seguito dagli oggetti del middleground ed alla fine dagli oggetti in primo piano(foreground). Questo fa si che lo sfondo non copra mai i pianeti e che l'astroname e i nemici, che andremo a posizionare nel foreground, non vengano mai coperti dai pianeti. 
Per fare questo si usa la coordinata Z (z-order) che virtualmente è l'asse perpendicolare allo schermo con verso positivo all'interno del dispositivo e negativo in direzione dell'osservatore.
Per capire di cosa stimo parlando passiamo alla modalità di visualizzaione 3d, cliccando sul pulsante 2D in alto nel pannello Scene.
  

Andiamo quindi ad impostare le coordinate z dei tre livelli in maniera da garantire una visione corretta degli elementi della scena.





Background : 0
Middleground: -5
Foreground: -10

A questo punto il nostro sfondo di gioco è terminato.

Creare un gioco 2D con Unity 4.3 - I Prefabs

Interrompiamo temporaneamente, con questa lezione, la creazione del nostro gioco, per descrivere una funzionalità particolarmente importante di Unity 3D: i Prefabs.
Un Prefabs è un tipo di GameObject ruiutilizzabile memorizzato nel Progetto.I prefabs possono essere inseriti in un qualsiasi numero di scene e  più volte nella stessa scena.
Un Prefab è un modello di oggetto. Quando si aggiunge un prefab ad una scena, si crea un'istanza di esso. Tutte le istanze sono collegate all'originale e sono essenzialmente cloni di essa. Non importa quante istanze esistono nel progetto, quando si apporta una modifica ad un Prefab  il cambiamento viene applicato automaticamente ed in cascata a tutte le istanze.

Creazione di un Prefab

Per creare un prefabbricato, è sufficiente trascinare un GameObject, precedentemente creato, dalla scena alla finestra di progetto. Il nome del GameObject diventerà blu per indicare che si tratta di un prefabbricato. Dopo averlo creato è possibile rinominare il nuovo prefab.

Dopo aver eseguito questi passaggi, il GameObject e tutti i suoi figli sono divenuti un prefab e il prefab può essere riutilizzato in più istanze.
Il GameObject originale nella pannello Hierarchy è ormai diventato un'istanza del Prefab.

 Istanze dei Prefab

Per creare un'istanza di Prefab nella scena attuale basta trascinare il Prefab dalla finestra di progetto nella scena o nella Hierarchy View. Questa istanza è legata al Prefab, come visualizzato dal testo blu utilizzato per il nome nella visualizzazione Gerarchia.



Una volta selezionata una istanza di prefab, se si vuole fare una modifica che interessa tutte le istanze, è possibile utilizzare il pulsante Select che appare nel pannello Inspector.

Ereditarietà

Ereditarietà significa che quando il prefab cambua, tali modifiche vengono applicate a tutte le istanze  collegate.  Ad esempio, se si aggiunge un nuovo script ad un prefab, tutti i GameObjects collegati conterranno lo stesso script.
Tuttavia, è possibile modificare le proprietà di una singola istanza mantenendo il collegamento intatto. Basta cambiare qualsiasi proprietà di un'istanza per notare che il nome  della variabile diventa in grassetto.
L'ereditarietà di questa variabile verrà  ora ignorata. Tutte le proprietà sovrascritte non saranno influenzate dai cambiamenti della fonte Prefab.

Questo ci  consente di modificare le istanze dei prefabs per renderli unici  senza interrompere il collegamento con il prefab origine.

Se si desidera aggiornare il Prefab e tutte le istanze, includendo anche le variabili sovrascritte, è possibile utilizzare  il pulsante Apply della barra Prefab.




Si noti che premendo il pulsante Apply la posizione e la rotazione di tutte le istanze viene modificata. Questo fa si che tutte le istanze vengano posizionate nello stesso punto. Tuttavia la posizione e la rotazione di eventuali figli delle istanze saranno calcolate sempre in relazione  alla radice della trasformazione.
Se si desidera eliminare tutte le sostituzioni, è possibile fare clic sul pulsante Revert.




Creare un gioco 2D con Unity 4.3 - Creazione del Player

In questa lezione impareremo a creare l'elemento fondamentale di ogni gioco: il player.
Per prima cosa ci occorre uno sprite. Come abbiamo già fatto nelle lezioni precedenti salviamo l'immagine seguente e importiamola negli Assets del nostro progetto Unity.

Come per i pianetini, scegliamo la Sprite Mode multiple ed effettuiamo lo Splice automatico.
Il risultato finale sarà il seguente.


Trasciniamo lo sprite arcadia_0 appena creato nella scena di gioco e dopo averlo rinominato Arcadia  modifichiamo il parametro Scale per ridurne le dimensioni.



Abbiamo creato nella scena di gioco la nostra astronave, vediamo quindi quali sono le funzionalità messe a disposizione da Unity per renderla un elemento di gioco e farla interagire con gli altri oggetti della scena.

Per prima cosa, in ogni gioco che si rispetti, il Player deve evitare di urtare gli oggetti pericolosi o i nemici in generale.
Per determinare se uno sprite  entra in collisione con un altro, la prima cosa da fare è definirne i contorni. Questa operazione può essere effettuata in diversi modi, alcuni più precisi altri un po' meno. Ovviamente il vantaggio dei metodi meno precisi è che risultano elaborativamente più efficaci.
In questi ultimi in  generale l'immagine viene approssimata ad un rettangolo o ad un cerchio circosritto od inscritto. Invece di verificare la collisione in maniera precisa (pixel per pixel), la collisione viene riscontrata solo se il rettangoli o i cerchi di collisione entrano in contatto. Questo modo di operare è molto efficiente, ma può dar luogo a sfioramenti tra sprite senza generazione di una collisione o viceversa a collisioni senza che vi sia un contatto. Nell'immagine seguente è mostrato il problema appena esposto. Utilizzando il rettangolo in blue come rettangolo di collisione, i due aerei sulla destra risultano toccarsi anche se distanti l'uno dall'altro.



Unity consente di definire tre tipi di collider: box collider, circle collider e polygon collider. I primi due sono dei collider approssimati, mentre il terzo crea una serie di poligoni che si avvicinano di molto alla forma esatta dello sprite.

Per aggiungere un collider alla nostra astronave premiamo il bottone Add Component del pannello Inspector, quindi Physics 2d -> Polygon Collider 2D.




Nell'immagine vediamo il risultato ottenuto. Le linee sottili verdi rappresentano i poligoni calcolati da Unity per calcolare le collisioni. Come possiamo vedere il risultato è molto accurato, anche se sarà particolarmente oneroso in termini di performance. Per il momento però non preoccupiamocene anche perché il tutto dipenderà da quanti oggetti di gioco entreranno a far parte della nostra scena. 


Il  Poligono Collider è un collider utilizzabile con la fisica 2D . La forma del collider è definita da un bordo a forma libera fatta di segmenti di linea , in modo da potersi adattare dello Sprite con grande precisione. Si noti che il bordo di questo collider deve racchiudere completamente un'area ( a differenza dell' Edge Collider 2D ) .
  • Material -  Specifica un materiale 2D. Il  motore di  fisica utilizza proprietà come l'attrito e il rimbalzo per calcolare gli effetti  delle collisioni.
  • Is Trigger -  Se selezionato esclude la gestione delle collisioni dal motore di fisica e permette di gestirle tramite script.
Il collider può essere modificato manualmente, ma spesso è più conveniente lasciare che Unity determini automaticamente la forma.
È possibile modificare la forma del poligono direttamente tenendo premuto il tasto shift mentre si sposta il mouse su un bordo o vertice nella vista scena . È possibile spostare un vertice esistente facendo shift-click quando il mouse si trova sopra di esso. Se si effettua questa operazione non su un vertice, ne verrà creato uno in automatico. È possibile rimuovere un vertice tenendo premuto il ctrl/cmd e cliccando su di esso .

Il nostro Player adesso è in grado di urtate ed essere colpito dagli altri oggetti di gioco.  Per completare il suo comportamento occorre quindi porlo sotto il controllo del motore di fisica aggiungendo il componente Rigidbody 2D.


Un componente Rigidbody 2D mette un oggetto sotto il controllo del motore fisico.

Masss - Massa del rigidbody .Linear Drag - Coefficiente di resistenza che si oppone al movimento lineareAngular Drag - Coefficiente di resistenza che si oppone al movimento di rotazione .Gravity Scale - L'accelerazione gravitazionale che agisce sul corpo. Il valore 1 è pari alla forza di gravità terrestre.Fixed Angle -  Può il rigidbody ruotare quando si applicano forze?Is Kinematic -  Può il rigidbody essere mosso dalle collisioni?Interpolate - Come interpolare il movimento dell'oggetto  (utile quando il movimento tende ad essere a scatti ) Sleeping Mode - Permette di risparmiare potenza di calcolo quando l'oggetto è a riposo 
Collision Detection -  Come vengono rilevate le collisioni con altri oggetti.
  1. Discrete Una collisione viene registrata solo se il collider dell'oggetto è in contatto con un altro durante un aggiornamento fisica.
  2. Continua Una collisione viene registrata se collider dell'oggetto sembra aver contattato un altro tra gli aggiornamenti .
L'aggiunta di un Rigidbody 2D permette ad uno sprite di spostarsi in un modo fisicamente convincente applicando delle forze tramite scripting. Quando il componente collider appropriato è anche collegato all'oggetto sprite, esso viene influenzato dalle collisioni con gli altri oggetti in movimento. L'utilizzo della fisica semplifica molte meccaniche di gioco e permette al gioco di essere realistico.
L'impostazione  cinematica spegne il comportamento fisico del Rigidbody 2D in modo che non reagisca alla gravità e alle collisioni. Questo è in genere utilizzato per mantenere un oggetto sotto il controllo degli  script non fisici per la maggior parte del tempo, per poi passare alla fisica in una particolare situazione. 


Ed ora aggiungiamo l'ultimo componente. Utilizzando il tasto destro sulla cartella Scripts selezioniamo Create -> C# Script.
Nominiamo lo Script in PlayerScript e con un doppio click aprimao l'editor MonoDevelop e incolliamo il codice seguente.
Salviamo tutto e aggiungiamo lo Script appena creato all'astronave Arcadia.


using UnityEngine;

/// /// Controllo del Giocatore
/// public class PlayerScript : MonoBehaviour
{
 ///  /// La velocita' del Player
 ///  public Vector2 speed = new Vector2(10, 10);
 
 // Spostamento del Player
 private Vector2 movement;

 // Larghezza ed altezza del Player
 private float spriteWidth ;
 private float spriteHeight ;


 void Awake()
 {
  // Calcolo della larghezza e l'altezza dell'astronave
  spriteWidth = renderer.bounds.max.x - renderer.bounds.min.x;
  spriteHeight = renderer.bounds.max.y - renderer.bounds.min.y;
 }

 void Update()
 {
  // Lettura del valore dei pulsanti di controllo del player
  float inputX = Input.GetAxis("Horizontal");
  float inputY = Input.GetAxis("Vertical");
  
  // Calcolo del vettore della velocita'  
  movement = new Vector2(
   speed.x * inputX,
   speed.y * inputY);

  // Limitazione della posizione del Player all'interno dei limiti dello schermo (Camera)
  var dist = (transform.position - Camera.main.transform.position).z;
  
  var leftBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(0, 0, dist)
   ).x;
  
  var rightBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(1, 0, dist)
   ).x;
  
  var topBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(0, 0, dist)
   ).y;
  
  var bottomBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(0, 1, dist)
   ).y;
  
  transform.position = new Vector3(
   Mathf.Clamp(transform.position.x, leftBorder + (spriteWidth/2), rightBorder - (spriteWidth/2)),
   Mathf.Clamp(transform.position.y, topBorder + (spriteHeight/2),  bottomBorder - (spriteHeight/2)),
   transform.position.z
   );
  
 }
 
 void FixedUpdate()
 {
  // Spostamento del Player
  rigidbody2D.velocity = movement;
 }
}


A questo punto lanciamo il gioco in esecuzione e facciamo un po' di pratica di pilotaggio.

Creare un gioco 2D con Unity 4.3 - Le Animazioni

Se abbiamo fatto un po' di pratica di volo con l'Arcadia, abbiamo sicuramente notato che i motori non emettono le tipiche fiamme classiche delle astronavi  dei videogiochi.
Andiamo quindi in questa lezione ad animare la nostra astronave.
Se vi ricordate, la texture era composta da tre sprite differenti, di cui noi abbiamo utilizzato solo il primo.
Bene, trascianiamo i due sprite arcadia_1 e arcadia_2 dagli asset, nel pannello Hierarchy come nodi figlio dell astronave.
Rinominiamo i due sprite nella scena in JetSmoke_1 e JetSmoke_2. Il risultato finale sarà quello della figura seguente.





Ora posizioniamo entrambi gli sprite direttamente dietro i motori dell'astronave, ottenendo qualcosa di simile alla seguente.



Dopo averli posizionati nascondiamone la visualizzazione deselezionando la casella di spunta alla sinistra della scritta Sprite Renderer.



A questo punto andiamo a creare la nostra animazione, che consisterà nell'alternare in rapida successione le visualizzazione delle due immagini nascoste.
Dal menù Windows apriamo la finestra Animation. 



Con la finestra animation visualizzata,, andiamo a selezionare la nostra astronave all'interno della scena. E' possibile creare un animazione agendo soolo su oggetti della scena. Soltanto dopo è possibile salvarli come Prefabs.
Una volta selezionata l'astronave creiamo una nuova animazione con la voce New Clip. Salviamo il Clip in una nuova cartella dentro Assets che chiameremo Animations e




A questo punto andiamo a creare un Key Frame cliccando nella finestra temporale (1) e abilitiamo la visualizzazione del JetSmoke_1 agendo sulla casella di spunta.


Noteremo che nella finestra Animation viene registrata l'operazione effettuata. 
Continuiamo quindi con un secondo Key Frame.


In questo secondo Frame andremo a nasconder JetSmoke_1 e a visualizzare JetSmoke_2 ripetendo le operazioni in maniera analoga al passaggio precedente.


Quindi, creiamo un ultimo Key Frame identico al primo.


Per vedere se l'animazione è venuta come desideravamo, mandiamola in esecuzione con il tasto play (il triangolino nero in alto a sinistra).

Per poter animare la nostra astronave è richiesto ancora un ulteriore passaggio.
Chiudiamo la finestra Animation e, sempre con la nostra astronave selezionata, verifichiamo che nel pannello Inspector sia apparso un nuovo componente: Animator. 
Rinominiamo il Controller che è stato creato in automatico in ArcadiaAnimator.



Per ora limitiamoci a verificare che, selezionando il rettangolo Idle, l'animazione (parametro Motion) è correttamente impostata ad ArcadiaAnimation. In seguito capiremo come creare animazioni complesse e con più stati.

Lanciamo il gioco in esecuzione, e se tutto è stato fatto in maniera corretta, la nostra astronave dovrebbe volare con dei motori fiammeggianti.





Creare un gioco 2D con Unity 4.3 - Missili e raggi laser

Ora che la nostra astronave è in grado di volare,dotiamola di un po'di armamenti.
Se avete seguito il corso sino ad ora, dovreste essere in grado di realizzare autonomamente un Prefab di un missile animato utilizzando l'immagine seguente.



Le operazioni da effettuare sono le stesse che abbiamo seguito per la realizzazione dell'animazione dell'astronave. L'unica differenza e che questa volta, al termine delle operazioni, trascineremo il missile dalla scena nella cartella Prefabs. Riassumendo in breve:
  1. Importiamo la texture ed effettuiamone lo splice
  2. Creiamo un nuovo sprite nella scena ed associamogli la texture del missile
  3. Creiamo una animazione  utilizzando le altre due immagini così come abbiamo fatto per i motori dell'astronave
  4. Aggiungiamo allo sprite un Rigid Body 2D con Gravity Scale impostato a 0 e Fixed Angles selezionato
  5. Aggiungiamo un Box Collider 2D dimenzionandolo opportunamente
  6. Trasciniamo lo sprite nei Prefabs e rinominiamolo in Missile
Nel Box Collider ricordiamoci di selezionare la casella di spunta IsTrigger. Così facendo si indica al motore di fisica 2D di ignorare la gestione delle collisioni, e di chiamare generare l'evento OnTriggerEnter2D dell'oggetto colpito. Questo eviterà al nostro  proiettile di rimbalzare semplicemente contro le cose, e ci consentirà di gestire l'evento da codice. Potremo quindi decidere se distruggere gli oggetti colpiti o se diminuirne il livello di energia.

Il Prefab è quasi completo.  Occorre solo aggiungerci gli script per la gestione.
Il primo è uno script generico che riutilizzeremo anche per altri oggetti,e che serve a far muovere in maniera lineare le cose. Notiamo che la velocità può essere impostata tramite la proprietà Speed.


using UnityEngine;

/// 
/// Simply moves the current game object
/// 
public class MoveScript : MonoBehaviour
{
 // 1 - Designer variables
 
 /// 
 /// Object speed
 /// 
 public Vector2 speed = new Vector2(25, 25);
 
 /// 
 /// Moving direction
 /// 
 public Vector2 direction = new Vector2(-1, 0);

 public Vector2 hotSpot = new Vector2(1, 0);
 


 private Vector2 movement;
 
 void Update()
 {
  // 2 - Movement
  movement = new Vector2(
   speed.x * direction.x,
   speed.y * direction.y);
 }
 
 void FixedUpdate()
 {
  // Apply movement to the rigidbody
  rigidbody2D.velocity = movement;
 }
}

Il secondo invece fa in modo che il missile si autodistrugga una volta fuoriuscito dalla visuale di gioco,evitando che i missili continuino il loro viaggio all'interno della scena di gioco ancora non visibile. 


using UnityEngine;

/// 
/// Projectile behavior
/// 
public class ShotScript : MonoBehaviour
{
 // 1 - Designer variables
 
 /// 
 /// Damage inflicted
 /// 
 public int damage = 1;
 
 /// 
 /// Projectile damage player or enemies?
 /// 
 public bool isEnemyShot = false;
 
 void Start()
 {
  // 2 - Limited time to live to avoid any leak
  Destroy(gameObject, 5);
 }

 void Update()
 {
  // Limitazione della posizione del Player all'interno dei limiti dello schermo (Camera)
  var dist = (transform.position - Camera.main.transform.position).z;
  
  var rightBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(1, 0, dist)
   ).x;

  if (transform.position.x > rightBorder)
  {
   Destroy(gameObject);
  }

  var leftBorder = Camera.main.ViewportToWorldPoint(
   new Vector3(0, 0, dist)
   ).x;

  if (transform.position.x < leftBorder)
  {
   Destroy(gameObject);
  }
 }
}

Aggiungiamo questi due nuovi script al nostro Prefab Missile, che sarà quindi pronto per essere sparato.
Per poterlo fare occorre creare una istanza del Prefab all'interno della scena di gioco giusto davanti alla nostra astronave.
Creiamo quindi il seguente WeaponScript.


using UnityEngine;

/// 
/// Launch projectile
/// 
public class WeaponScript : MonoBehaviour
{
 //--------------------------------
 // 1 - Designer variables
 //--------------------------------
 
 /// 
 /// Projectile prefab for shooting
 /// 
 public Transform shotPrefab;
 
 /// 
 /// Cooldown in seconds between two shots
 /// 
 public float shootingRate = 0.25f;
 
 /// 
 /// The hot spot
 /// 
 public Vector3 hotSpot = new Vector3(0, 0,0);

 //--------------------------------
 // 2 - Cooldown
 //--------------------------------
 
 private float shootCooldown;
 
 void Start()
 {
  shootCooldown = 0f;
 }
 
 void Update()
 {
  if (shootCooldown > 0)
  {
   shootCooldown -= Time.deltaTime;
  }
 }
 
 //--------------------------------
 // 3 - Shooting from another script
 //--------------------------------
 
 /// 
 /// Create a new projectile if possible
 /// 
 public void Attack(bool isEnemy)
 {
  if (CanAttack)
  {
   shootCooldown = shootingRate;
   
   // Create a new shot
   var shotTransform = Instantiate(shotPrefab) as Transform;
   
   // Assign position
   shotTransform.position = transform.position + hotSpot ;


   // The is enemy property
   ShotScript shot = shotTransform.gameObject.GetComponent();
   if (shot != null)
   {
    shot.isEnemyShot = isEnemy;
   }
   
   // Make the weapon shot always towards it
   //MoveScript move = shotTransform.gameObject.GetComponent();
   //if (move != null)
   //{
   // move.direction = this.transform.right; // towards in 2D space is the right of the sprite
   //}
  }
 }
 
 /// 
 /// Is the weapon ready to create a new projectile?
 /// 
 public bool CanAttack
 {
  get
  {
   return shootCooldown <= 0f;
  }
 }
}

Questo script ha tre proprietà: il Prefab da utilizzare come sprite da sparare, il tempo minimo da rispettare tra il lancio di un missile ed un altro, e la posizione relativa da dove far partire il missile.
Infine un ultimo passaggio. Modifichiamolo script PlayerScript aggiungendo il seguente codice alla fine del metodo Update.



//5 - Shooting
bool shoot = Input.GetButtonDown("Fire1");
shoot |= Input.GetButtonDown("Fire2");
// Careful: For Mac users, ctrl + arrow is a bad idea
  
if (shoot)
{
 WeaponScript weapon = GetComponent();
 if (weapon != null)
 {
  // false because the player is not an enemy
  weapon.Attack(false);
 }
}

Aggiungiamo i due script alla nostra astronave e settiamo le  proprietà a nostro piacimento. Lanciando il gioco in esecuzione, la nostra astronave sarà ora in grado di lanciare missili a volontà.