Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Finalizzare la GameScene

Implementare la classe GameScene, principale componente di un gioco mobile per iOS, utilizzando Swift e SpriteKit su XCode.
Implementare la classe GameScene, principale componente di un gioco mobile per iOS, utilizzando Swift e SpriteKit su XCode.
Link copiato negli appunti

Dopo aver visto come implementare gli oggetti Coin e Block, non ci resta che utilizzarli all'interno della classe GameScene, in modo che il nostro gioco prenda vita.

Per prima cosa, aggiungiamo una label che mostrerà il punteggio, posizionandola in alto centrata orizzontalmente. Lo faremo usando l’editor grafico di Xcode, senza quindi dover scrivere codice.

Apriamo il file GameScene.sks e trasciniamo l’elemento Label all’interno della scena, come mostrato dalla figura seguente.

Figura 27. (click per ingrandire)


Selezioniamo quindi la label, ed impostiamo i seguenti campi:

Campo Valore
Name scoreLabel
Position X -1,655l
Position Y 169,498
Figura 28. (click per ingrandire)


Passiamo ora al file GameScene.swift, e sovrascriviamolo interamente con il codice che segue:

import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
    private var gameRunning = true
    private var mouse: Mouse!
    private var didGetCoin = false
    private var collectedCoins = 0
    private var scoreLabel: SKLabelNode!
    override func didMove(to view: SKView) {
        startGame()
    }
    private func startGame() {
        mouse = Mouse(gameScene: self)
        mouse.position = CGPoint(x: -frame.width / 4, y: frame.midY)
        addChild(mouse)
        addElementsForever()
        self.physicsWorld.contactDelegate = self
        self.physicsWorld.gravity = .zero
        scoreLabel = childNode(withName: "scoreLabel") as! SKLabelNode
        collectedCoins = 0
        scoreLabel.text = "0"
        gameRunning = true
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if gameRunning {
            mouse.fly()
        } else {
            restart()
        }
    }
    private func restart() {
        children.filter { $0 is Coin || $0 is Block || $0 is Mouse  }.forEach { $0.removeFromParent() }
        startGame()
    }
    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        if didGetCoin {
            didGetCoin = false
            collectedCoins += 1
            scoreLabel.text = "\(collectedCoins)"
        }
    }
    func didDie() {
        gameRunning = false
    }
    private func addElementsForever() {
        let addElement = SKAction.run {
            self.addElement()
        }
        let wait = SKAction.wait(forDuration: 0.5)
        let sequence = SKAction.sequence([addElement, wait])
        let forever = SKAction.repeatForever(sequence)
        self.run(forever)
    }
    private func addElement() {
        let element = arc4random_uniform(2) == 0 ? Coin() : Block()
        let randomY = CGFloat(arc4random_uniform(UInt32(self.frame.height - 100))) + 50
        element.position =  CGPoint(x: self.frame.maxX + element.frame.width, y: randomY - self.frame.height / 2 )
        self.addChild(element)
        let move = SKAction.moveTo(x: -self.frame.width, duration: 3)
        let sequence = SKAction.sequence([move, SKAction.removeFromParent()])
        element.run(sequence)
    }
    func didBegin(_ contact: SKPhysicsContact) {
        guard let otherNode = contact.bodyA.node is Mouse ? contact.bodyB.node : contact.bodyA.node else { return }
        if let coin = otherNode as? Coin {
            coin.removeFromParent()
            self.didGetCoin = true
        }
        if otherNode is Block {
            gameRunning = false
            self.removeAllActions()
            self.children.forEach { $0.removeAllActions() }
            scoreLabel.text = " *** GAME OVER *** Score: \(collectedCoins)"
            mouse.die()
        }
    }
}

Esaminiamo il codice in dettaglio.

Le properties

Riportiamo di seguito una tabella riepilogativo delle proprietà definite nella classe GameScene.

Proprietà Descrizione
gameRunning Indica se il gioco è in esecuzione (true) o se è terminato (false)
mouse Riferimento allo sprite del protagonista
didGetCoin Viene impostata a true ogni volta che rileviamo una collisione tra un oggetto Coin e Mouse
collectedCoins Rappresenta il numero di Coin raccolti
scoreLabel Riferimento alla label aggiunta poc'anzi con l’editor grafico

I metodi

Abbiamo esaminato in precedenza il metodo startGame, ma questa nuova versione include alcune istruzioni aggiuntive.

In particolare, viene invocato il metodo addElementsForever(), che si occuperà di aggiungere in continuazione sprite di tipo Coin o Block, e di animarli.

Stiamo anche indicando che questa scena è il contactDelegate del mondo fisico simulato. In questo modo, riceveremo notifiche relative alle collisioni che avvengono.

Altro metodo già discusso in una sua precedente versione è touchesBegan, che si limitava ad invocare il metodo fly() di Mouse. Adesso, esso controlla anche se il gioco è in esecuzione, e solo in tal caso richiama mouse.fly(); altrimenti, riavvia la partita.

Il metodo restart ripulisce la scena eliminando tutti gli sprite di tipo Coin, Block e Mouse, per poi invocare startGame.

Di fondamentale importanza per tutte le app basate su SpriteKit è il metodo update, che viene eseguito automaticamente ogni 16 millisecondi e rappresenta la nostra opportunità di aggiornare e/o preparare il prossimo frame. In particolare, lo utilizziamo controllare se si è verificata una collisione tra gli sprite Mouse e Coin. In tal caso, incrementiamo il contatore dello score (collectedCoins) e aggiorniamo la label scoreLabel.

Altri due metodi che ci interessa attenzionare sono addElementsForever e addElement. Il primo si occupa semplicemente di invocare addElement ogni mezzo secondo. Il secondo metodo posiziona casualmente un Coin o un Block in una coordinata Y casuale, associandolo piu ad un’animazione che lo muoverà da sinistra verso destra.

Infine, come abbiamo più volte ripetuto, il metodo didBegin viene chiamato dal motore fisico ogni volta che avviene una collisione. Al suo interno verifichiamo se la collisione è avvenuta con un oggetto di tipo Coin o Block: nel primo caso, rimuoviamo il Coin e impostiamo didGetCoin a true; nel secondo caso, prepariamo la schermata di Game Over.

A questo punto avremo già una prima versione funzionante della nostra app. Possiamo subito provare ad eseguirla sul simulatore, utilizzando la combinazione di tasti CMD + R.

Ti consigliamo anche