Skip to main content

Create il vostro Infinite Scrolling Game per iPhone con Swift e SpriteKit

Questo tutorial è stato scritto per Xcode 6.3 e Swift 1.2

In questo articolo vedremo con sviluppare un videogioco a scorrimento per iPhone utilizzando Swift e SpriteKit (il framework per videogiochi 2D incluso in iOS).

Ogni passo viene spiegato nel dettaglio, tuttavia una qualche esperienza di programmazione (non necessariamente Swift e iOS) vi aiuterà a capire meglio. Non è necessaria alcuna esperienza nello sviluppo di videogiochi, anzi questo progetto potrebbe benissimo essere il vostro primo esperimento. Una volta terminato vi invito a modificarlo secondo le vostre idee in modo da farlo diventare il vostro prodotto.

Il gioco è molto semplice, abbiamo un Koala che deve saltare i piatti di formaggio che gli vengono incontro. Ogni volta che il giocatore tocca lo schermo dell’iPhone il Koala salta. Se il Koala viene colpito dal piatto di formaggio il gioco termina e viene mostrato un testo atto a sminuire l’autostima del giocatore. Il tutto avviene in una foresta di notte naturalmente.

Infinite Scrolling

Prerequisiti

Prima di iniziare accertatevi di avere Xcode 6.3 installato. Poi scaricate questi 2 pacchetti di grafica gratuiti (il sito vi chiederà una mail a cui vi sarà inviato il link per il download). Per avere la versione gratuita è sufficiente scegliere l’oziane IMAGES ONLY.

 

  1. Night Meadow Background – Repeatable – Parallax
  2. Koala

Update 20 Aprile 2015: come l’utente EDI fa giustamente notare manca l’immagine cheese.png necessaria più avanti. La potete scaricare da questo link: http://www.gameartguppy.com/shop/rocket-mouse-game-art-character/ L’immagine (sia la versione standard che quella @2x) è troppo grande quindi dovreste ridurla del 50% circa utilizzando Preview/Anteprima di OS X.

Iniziamo

Aprite Xcode e create un nuovo progetto basato su SpriteKit per iOS

File > New > Project…

spritekit project

Scegliete Next.

Nel pannello che appare, nel campo Organization Name inserite il vostro nome e in Organization Identifier una stringa che vi identifica. Per il resto popolatelo come mostrato nella figura seguente.

koala runner

 

Premete Next.

Sceglie una cartella in cui salvare il progetto e premete Create.

Ora vogliamo che il gioco funzioni con l’iPhone orientato in orizzontale quindi:

  1. selezionate la root del progetto dal pannello laterale sinistro
  2. scegliete il target KoalaRunner
  3. deselezionate la spunta dalla voce Portrait come mostrato in figura.

horizontal

 

Creare uno SpriteSheet per le immagini

Una delle risorse hardware più potenti a vostra disposizione è la GPU. Si tratta di una componente che riesce a disegnare contemporaneamente (grazie al paradigma SIMD: Single Instruction Multiple Data) molti pixel. Per ogni frame N la CPU applica la logica del gioco, la fisica, l’intelligenza artificiale e ottiene le informazioni relative a come devono essere disegnati gli oggetti. Poi passa queste informazioni alla GPU e, nel fotogramma successivo N+1, la GPU si occupa di disegnare sullo schermo queste informazioni. Nel frattempo la CPU si occupa di calcolare il nuovo frame N+1.

In un gioco che gira a 60 frame al secondo avete 16 millisecondi di tempo per renderizzare un fotogramma quindi, in questo contesto, bisogna ottimizzare tutto il possibile dato che un ritardo nei calcoli genera immediatamente un calo del framerate che si traduce in una cattiva esperienza per il giocatore.

Uno dei momenti più critici è quando la CPU deve passare le informazioni su come disegnare il frame alla GPU.

Immaginiamo di avere 10 spite da disegnare sullo schermo, per ognuna la CPU deve:

  • caricare l’immagine 1 sulla GPU
  • comunicare alla GPU alcuni parametri relativi a come disegnare l’immagine (posizione, rotazione, fattore di scala, etc..,)
  • caricare l’immagine 2 sulla GPU
  • comunicare alla GPU i parametri…
  • caricare l’immagine 10 sulla GPU
  • comunicare alla GPU i parametri…

Si tratta di una perdita di tempo molto importante che vanifica gli sforzi che avete eventualmente fatto per scrivere del codice efficiente e performante. Per fortuna esiste da anni una soluzione a questo problema e SpriteKit la gestisce nativamente: create uno SpriteSheet o Texture Atlas.

Un Texture Atlas è un’immagine contenente al suo interno una serie di immagini necessarie a renderizzare il frame.

Una volta creato uno Sprite Sheet (Texture Atlas) la CPU dovrà caricarlo sulla GPU una sola volta risparmiando così molto tempo prezioso.

Creare uno Sprite Sheet con Xcode è facilissimo (e praticamente trasparente allo sviluppatore). Tutto quello che dovete fare è:

  1. andare sul desktop e creare una cartella con nome Sprites.atlas (il realtà il nome è facoltativo, l’importante è l’estensione .atlas)
  2. aggiungere alla cartella tutte le immagini necessarie, ecco l’elenco tra quelle che avete scaricato:
    Elenco immagini Sprite Sheet
  3. in Xcode scegliere File > Add Files to “KoalaRunner”…
  4. selezionare la cartella Sprites.atlas sul desktop
  5. selezionare l’opzione Copy items if needed
  6. Premere Add

Da questo momento in poi Xcode penserà a generare lo Sprite Sheet durante la compilazione.

Potete verificare che le immagini sono disponibili all’interno del progetto aprendo il pannello destro di Xcode ed esplorando la Media Library.

Media Library

E’ presente anche lo sprite Spaceship che Xcode inserisce di default nei nuovi progetti basati su SpriteKit.

La classe Koala

Questa classe rappresenta il Koala protagonista del gioco. Vogliamo che sia rappresentabile sullo schermo, quindi estenderà SKSpriteNode. Inoltre vogliamo che offra 3 comportamenti:

  1. run
  2. jump
  3. die

Da Xcode:

  1. scegliamo File > New > File…
  2. poi selezioniamo iOS > Source sul pannello di sinistra
  3. e Swift File nel pannello di destra
  4. Next
  5. assegniamo il nome Koala al file
  6. premiamo Create

Ora cancelliamo il contenuto del file creato e incolliamoci il codice seguente.

Properties

Stiamo dichiarando le costanti walkForeverAction e jumpAction che conterranno, rispettivamente, le azioni per rappresentare la corsa e il salto del koala. Inoltre dichiariamo una variabile isJumping che conterrà il valore true se l’azione di salto è in esecuzione.

init

Il primo initializer si occupa di popolare le 2 costanti di tipo SKAction. Inoltre invoca il costruttore della superclasse SKSpriteNode assegnando una texture (immagine) al nostro oggetto.

Il secondo initializer è obbligatorio ma non lo useremo quindi al suo interno solleviamo un fatal error.

run

Questo metodo imposta la variabile isJumping a false e esegue sul koala l’azione walkForeverAction

jump

Questo metodo verifica che non sia già in esecuzione un salto. In caso negativo imposta a true la variabile isJumping, rimuove l’azione walkForeverAction ed esegue il salto. E’ importante notare che le azioni vengono eseguite in modo asincrono. Quindi quando si avvia l’esecuzione di un’azione, il codice alla riga successiva può essere eseguito prima che l’azione sia conclusa (in realtà questa è la situazione più frequente). Se volete eseguire del codice dopo che l’azione sia terminata dovete utilizzare il blocco completion. Le righe #40 e #41 ad esempio vengono eseguite quando il salto è effettivamente terminato e si occupano di eseguire nuovamente l’azione walkForeverAction e riportare false la variabile isJumping.

die

Se il koala muore smetterà di muoversi quindi dobbiamo rimuovere tutte le azioni in esecuzione su questo oggetto.

La classe Cheese

Create ora la classe Cheese.

Anche questa classe estende SKSpriteNode.

Il metodo startMoving si occupa di creare un’azione che sposta lo sprite a sinistra fino a uscire dallo schermo e poi la esegue sull’oggetto corrente.

La classe GameScene

Una scena (SKScene) in SpriteKit rappresenta generalmente un livello di un videogioco. Una scena contiene gli oggetti che vengono mostrati sullo schermo e che rappresentano graficamente il videogioco. Xcode ha già creato per noi la classe nel file GameScene.swift, apriamola.

 

Questa classe sta eseguendo l’override di 3 metodi fondamentali nella gestione dei gioco.

 

  • didMoveToView: viene chiamato una sola volta quando la scena sta per essere presentata. In questo metodo bisogna inserire il codice per preparare la scena.
  • touchesBegan: viene chiamato ogni volta che viene toccato lo schermo. Qui inseriremo il codice per la gestione dell’input utente.
  • update: questo metodo viene chiamato prima di renderizzare ogni fotogramma (cioè ogni 16 millisecondi). Si tratta di uno dei punti più critici per le performance di un videogioco. Se scrivete dei cicli for o loop (o chiamate ricorsive) qui dentro dovete fare molta attenzione perché potrebbero essere operazioni troppo complesse per essere eseguite ogni 16 millisecondi. Una buna regola è quella di costruire e salvare in variabili di istanza tutto quello che serve ogni frame e assolutamente evitare di creare nuovi oggetti dentro il metodo update.

Se premete CMD + R sulla tastiera si aprirà l’iPhone Simulator e vedrete quello che sta facendo ora la classe GameScene.

Screen Shot 2015-04-18 at 14.05.49

 Quello che vedete è stato costruito dal codice dentro didMoveToView.

Se cliccate con il mouse sullo schermo del simulatore invocate il metodo touchesBegan che si occupa di creare uno nuovo SKSpriteNode con l’immagine Spaceship, animarlo e aggiungerlo aggiunge alla scena nel punto in cui è stato rilevato il tap.

SpriteKit Hello World Spaceship

Torniamo a GameScene.swift e iniziamo ad adattare la scena secondo le nostre necessità. Cancelliamo il codice dentro i 2 metodi appena esaminati.

CMD + R per vedere l’effetto.

iPhone Simulator SpriteKit

Aggiungere il koala

Aggiungiamo una variabile koala. Vogliamo che questa variabile referenzi l’oggetto Koala presente nella scena. SpriteKit permette di recuperare un oggetto presente nella scena usando il metodo childNodeWithName. Tuttavia questo metodo deve cercare il nodo. Siccome avremo bisogno del koala all’interno del metodo update, per motivi di performance preferisco avere una variabile che lo referenzi direttamente. La variabile è di tipo weak quindi non “tratterrà” il koala il memoria una volta che è stato rimosso dalla scena.

Il metodo addKoala molto semplicemente crea un’istanza di Koala, posiziona l’oggetto nella scena e lo aggiunge.

Infine invochiamo addKoala() dentro didMoveToView.

CMD + R per vedere il risultato.

Koala

Bene, il koala è animato. Ora passiamo al formaggio.

Aggiungere il formaggio

Aggiungiamo la variabile di istanza isGameOver. Ci servirà per capire se il gioco è terminato.

Poi aggiungiamo il metodo addCheese che si occupa di creare un oggetto di tipo Cheese, aggiungerlo alla scena e animarlo (riga#39). Una volta che l’animazione (la quale sposta il formaggio dall’estremità destra dello schermo a sinistra fino a farlo uscire di scena) è terminata vogliamo avviare una nuova animazione (se il gioco non è terminato). E’ quello che fanno le righe da #40 a #43.

Infine invochiamo per la prima volta addCheese da didMoveToView.

CMD + R.

Gestione delle collisioni

Aggiungiamo il metodo collision che ritorna true se il frame del koala e quello del formaggio si intersecano. Il metodo è scritto in modo tale da controllare tutti gli oggetti di tipo Cheese presenti nella scena nel caso volessimo rendere il gioco più difficile.

Il nuovo metodo gameOver imposta a true la variabile isGameOver, segnala all’oggetto koala che è morto e invoca addLooserLabel il quale mostra una messaggio all’utente in sovrimpressione.

Infine dobbiamo aggiungere del codice al metodo update in modo da controllare, per ogni fotogramma, se c’è stata una collisione.

Attenzione, il metodo update sta chiamando collision che al suo interno contiene un ciclo for. Questa è una tipica situazione da valutare attentamente. Se il ciclo for dovesse scorrere troppi oggetti infatti potrebbe influenzare negativamente le performance del gioco.

CMD + R. Ora il gioco dovrebbe terminare appena il formaggio entra in collisione col koala.

Saltare

L’ultima logica che dobbiamo implementare è quella del salto. Vogliamo collegare il tap dell’utente sullo schermo al metodo jump del koala (nel caso in cui il la partita sia in esecuzione). Se invece siamo in modalità gameover vogliamo che il tap faccia iniziare una nuova partita.

Modifichiamo touchesBegan come mostrato di seguito e aggiungiamo i metodo restartGame e removeKoalaCheeseAndLabel.

 

Questo è il codice completo della classe GameScene.

 

Altri oggetti grafici

La logica del gioco è completa e possiamo giocarlo. Come ultimo cosa possiamo aggiungere altri sprite alla scena. Questa volta lo faremo senza scrivere codice dato che si tratta di oggetti che non eseguono una logica ma rimangono statici.

Aprite GameScene.sks. Dalla Media Library trascinate una nuvola sulla scena. Poi, con la nuvola selezionata, accedete al Panel Inspector a SKNode Inspector (premendo alt + cmd + 7) -> Physics Definition e selezionate Body Type: None. Infine, sempre dal Panel Inspection selezionate -3 nel campo Z (quando 2 oggetti si sovrappongono, SpriteKit disegna “sopra” quello con valore Z maggiore).

Ripetete l’operazione per la seconda nuvola e per la luna.

Infine fate click su un punto vuoto della scena e dal Panel Inspector aprite il menù Color e selezionare il nero. CMD + R.

 

Aggiungete ora gli alberi e i fiori. Potete rimpicciolirli usando la guida rettangolare che appare intorno allo sprite. Ricordate sempre di impostare Body = None. Il valore Z per questi oggetti può essere -2 per gli alberi più lontani e -1 per i fiori e gli alberi più vicini.

Conclusioni

Spero che le spiegazioni dei vari passaggi siano state abbastanza comprensibili. Se qualcosa non voi è chiaro scrivete pure nei commenti qui sotto. In attesa del prossimo articolo dedicato al mondo iOS, Swift e Game Development vi invito a sperimentare con questo progetto e a modificarlo implementando le vostre idee.

Luca Angeletti

Trainer • Developer • Writer

7 thoughts to “Create il vostro Infinite Scrolling Game per iPhone con Swift e SpriteKit”

  1. Ciao e complimenti per la guida!
    ho fatto tutto come hai descritto tu solo che mi da un errore
    e non mi fa caricare il gioco “Build Failed”…
    L’errore si trova nel GameScene.swift
    ho provato anche a fare copia e incolla con il codice completo
    ma nulla da sempre il solito errore non so cos’altro fare…un’aiutino please!!!

    Schermata 2016-09-07 alle 18.03.23.png

  2. Ciao Alex, questo tutorial è stato scritto (oltre un anno fa) con Xcode 6 e Swift 1.2. Per questo motivo te (che probabilmente stai usando Swift 2.2 o successivo) ottieni un errore. In questo può aiutarti Xcode, seleziona Edit > Convert > To Latest Swift Syntax per aggiornare in automatico il codice. Fammi sapere se risolvi!

Lascia un commento

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