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

Implementare gli attori del gioco

Utilizzare Swift e la libreria SpriteKit per implementare un gioco mobile iOS: ecco come implementare le classi dei principali attori del gioco.
Utilizzare Swift e la libreria SpriteKit per implementare un gioco mobile iOS: ecco come implementare le classi dei principali attori del gioco.
Link copiato negli appunti

In questa lezione vedremo come implementare le classi che rappresenteranno i principali attori della nostra app: Monkey, Pineapple e Statue.

La classe Monkey

Questa classe rappresenterà l’entità della scimmia, ovvero il personaggio controllato dall’utente. Dovrà esporre 3 metodi che poi verranno utilizzati da GameScene, ovvero:

  • startMovingToLeft()
  • startMovingToRight()
  • stop()

Da Xcode scegliamo File > New > File… quindi scegliamo Swift File, assegniamo il nome Monkey al file e premiamo Create.

Copiamo nel file sorgente questo codice.

import SpriteKit
	class Monkey: SKSpriteNode {
		static let category: UInt32 = 0x1 << 1
		init() {
			let texture = SKTexture(imageNamed: "monkey")
			super.init(texture: texture, color: .clearColor(), size: texture.size())
			let physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
			physicsBody.restitution = 1.0
			physicsBody.affectedByGravity = false
			physicsBody.friction = 0.0
			physicsBody.linearDamping = 0.0
			physicsBody.categoryBitMask = Monkey.category
			physicsBody.contactTestBitMask = Pineapple.category | Statue.category
			physicsBody.collisionBitMask = 0
			physicsBody.angularDamping = 0.0
			physicsBody.dynamic = false
			self.physicsBody = physicsBody
		}
		required init?(coder aDecoder: NSCoder) {
			fatalError("init(coder:) has not been implemented")
		}
		func startMovingToLeftEdge() {
			self.removeAllActions()
			let delta = self.position.x
			let duration = NSTimeInterval(delta / 120)
			let moveLeft = SKAction.moveToX(self.frame.width / 2, duration: duration)
			self.runAction(moveLeft)
		}
		func startMovingToRightEdge() {
			self.removeAllActions()
			let delta = self.scene!.frame.width - self.position.x
			let duration = NSTimeInterval(delta / 120)
			let moveRight = SKAction.moveToX(self.scene!.frame.width - self.frame.width / 2, duration: duration)
			self.runAction(moveRight)
		}
		func stop() {
			self.removeAllActions()
		}
	}

Vediamo ora il significato del codice che abbiamo inserito.

class Monkey: SKSpriteNode

Questa riga ci dice che la nostra classe estende SKSpriteNode. Quindi la classe avrà una texture e potrà essere rappresentata graficamente sullo schermo.

static let category: UInt32 = 0x1 << 1

Associando una categoria distinta a Monkey, Pineapple e Statue potremo indicare al motore fisico quali collisioni devono esserci
notificate. Vedremo meglio questa logica più avanti.

init() {
		let texture = SKTexture(imageNamed: "monkey")
		super.init(texture: texture, color: .clearColor(), size: texture.size())
		let physicsBody = SKPhysicsBody(texture: texture, size: texture.size())

La prima parte del metodo init() utilizza l’immagine monkey per creare la texture di questo sprite.

physicsBody.restitution = 1.0
		physicsBody.affectedByGravity = false
		physicsBody.friction = 0.0
		physicsBody.linearDamping = 0.0
		physicsBody.categoryBitMask = Monkey.category
		physicsBody.contactTestBitMask = Pineapple.category | Statue.category
		physicsBody.collisionBitMask = 0
		physicsBody.angularDamping = 0.0
		physicsBody.dynamic = false
		self.physicsBody = physicsBody
	}

La seconda parte del metodo init() si occupa di costruire un body fisico associato a questo sprite. In particolare stiamo indicando che questo body fisico dovrà inviarci notifiche di collisione quando entra in contatto con i body di Pineapple e Statue (che definiremo tra poco).

func startMovingToLeftEdge() {
		self.removeAllActions()
		let delta = self.position.x
		let duration = NSTimeInterval(delta / 120)
		let moveLeft = SKAction.moveToX(self.frame.width / 2, duration: duration)
		self.runAction(moveLeft)
	}

Questo metodo avvia un’azione che sposta il nostro sprite Monkey verso l’estremo sinistro dello schermo. Tra poco faremo in modo che questo metodo venga chiamato quando l’utente tocca il lato sinistro dello schermo.

Analogamente il metodo startMovingToRight avvia un’azione per spostare Monkey verso il bordo destro dello schermo.

func stop() {
		self.removeAllActions()
	}

Infine il metodo stop rimuove tutte le azioni attualmente in esecuzione su Monkey, arrestandone il movimento. Chiameremo questo metodo quando l’utente rilascia il dito dallo schermo.

Se proviamo a compilare adesso noteremo 2 errori, poiché non abbiamo ancora definito le classi Pineapple e Statue.

La classe Pineapple

La classe Pineapple rappresenta l’ananas che cade dal lato superiore dello schermo. Creiamo un nuovo file sorgente in Swift con nome Pineapple e incolliamo il seguente sorgente al suo interno:

import SpriteKit
	class Pineapple: SKSpriteNode {
		static let category: UInt32 = 0x1 << 2
		init() {
			let texture = SKTexture(imageNamed: "pineapple")
			super.init(texture: texture, color: .clearColor(), size: texture.size())
			let physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
			physicsBody.restitution = 1.0
			physicsBody.affectedByGravity = false
			physicsBody.dynamic = true
			physicsBody.friction = 0.0
			physicsBody.linearDamping = 0.0
			physicsBody.categoryBitMask = Pineapple.category
			physicsBody.contactTestBitMask = Monkey.category
			physicsBody.angularDamping = 0.0
			self.physicsBody = physicsBody
		}
		required init?(coder aDecoder: NSCoder) {
			fatalError("init(coder:) has not been implemented")
		}
	}

Vediamo in dettaglio il codice.

class Pineapple: SKSpriteNode

Anche la classe Pineapple, come Monkey, estende SKSpriteNode.

La categoria di questa classe sarà 2.

Il metodo init() si occupa di applicare una texture basata sull’immagine pineapple che abbiamo precedentemente aggiunto al progetto.

physicsBody.contactTestBitMask = Monkey.category

Questa riga del metodo init() indica che vogliamo essere avvertiti quando avviene una collisione tra Pineapple e Monkey.

La classe Statue

Creiamo infine l’ultima classe, quella che rappresenta le statue che cadono dal cielo. Aggiungiamo un nuovo file sorgente Swift e assegniamogli il nome Statue.

import SpriteKit
	class Statue: SKSpriteNode {
		static let category: UInt32 = 0x1 << 3
		init() {
			let texture = SKTexture(imageNamed: "statue")
			super.init(texture: texture, color: .clearColor(), size: texture.size())
			let physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
			physicsBody.restitution = 1.0
			physicsBody.affectedByGravity = false
			physicsBody.dynamic = true
			physicsBody.friction = 0.0
			physicsBody.linearDamping = 0.0
			physicsBody.categoryBitMask = Pineapple.category
			physicsBody.contactTestBitMask = Monkey.category
			physicsBody.angularDamping = 0.0
			self.physicsBody = physicsBody
		}
		required init?(coder aDecoder: NSCoder) {
			fatalError("init(coder:) has not been implemented")
		}
	}

Il codice è molto simile a quello di Pineapple con l’eccezione che la category in questo caso ha valore 3.

Premendo CMD + B possiamo ora compilare il progetto senza errori.

Una extension per SKSprite

Esiste un’ultima funzionalità che vogliamo aggiungere a Pineapple e Statue. Si tratta del metodo startFallingFromRandomPosition().

Questo metodo deve provvedere a posizionare lo sprite in un punto sopra il bordo superiore dello schermo (quindi in un luogo invisibile all’utente) con una coordinata x casuale. Inoltre il metodo deve avviare un’azione che (con velocità casuale) farà muovere il blocco verso il bordo inferiore dello schermo, fino a uscire nuovamente dalla scena.

Invece di scrivere lo stesso metodo in entrambi i sorgenti di Pineapple e Statue possiamo usare una extension per aggiungere il metodo a SKSpriteNode. Siccome sia Pineapple che Statue estendono SKSpriteNode, automaticamente lo erediteranno.

Creiamo un nuovo file Swift con nome Extensions.swift e inseriamo il seguente codice:

import SpriteKit
	extension SKSpriteNode {
		func startFallingFromRandomPosition() {
			let random01 = CGFloat(Float(arc4random()) / Float(UINT32_MAX))
			let randomX = CGFloat(random01 * self.scene!.frame.width)
			self.position.x = randomX
			self.position.y = self.scene!.frame.height
			let randomDuration = NSTimeInterval(arc4random_uniform(3) + 1)
			let fallAction = SKAction.moveToY(-self.frame.width, duration: randomDuration)
			self.runAction(fallAction) { [weak self] in
				self?.removeFromParent()
			}
		}
	}

Ti consigliamo anche