In het eerste deel van deze serie verkenden we de basis van het Sprite Kit-framework en implementeerden we het startscherm van de game. In deze tutorial zullen we de hoofdklassen van de game implementeren.
Swift is een object-georiënteerde taal en we zullen hiervan profiteren door alle entiteiten van de game te scheiden in hun eigen klassen. We beginnen met het implementeren van de binnendringer
klasse.
binnendringer
Klassebinnendringer
Klassekiezen nieuwe > Het dossier… van Xcode's het dossier menu, kies Cocoa Touch Class van de iOS> Bron sectie en klik op volgende. Geef de klas een naam binnendringer
en zorg ervoor dat het erft van SKSpriteNode
. Zeker weten dat Taal ingesteld op Snel. Voer de volgende code in Invader.swift.
import UIKit import SpriteKit class Invader: SKSpriteNode var invaderRow = 0 var invaderColumn = 0 init () let texture = SKTexture (imageNamed: "invader1") super.init (textuur: texture, kleur: SKColor.clearColor (), size: texture.size ()) self.name = "invader" vereist init? (coder aDecoder: NSCoder) super.init (coder: aDecoder) func fireBullet (scène: SKScene)
De binnendringer
klasse is een subklasse van de SKSpriteNode
klasse. Het heeft twee eigenschappen, invaderRow
en invaderColumn
. De indringers worden uitgelijnd in een raster, net als in het originele spel Space Invaders. De twee eigenschappen geven ons een eenvoudige manier om bij te houden welke rij en kolom de indringer bevat.
In de in het
methode, initialiseren we een SKTexture
aanleg. De init (imageNamed :)
methode neemt een afbeelding als een parameter. Vervolgens roepen we de initialisator van de superklasse aan, passerend in de structuur
, SKColor.clearColor
voor de kleur
parameter, en voor de grootte
parameter geven we in de grootte van de textuur door. Ten slotte hebben we de naam ingesteld op "Invader"
zodat we het later kunnen identificeren.
De in het
methode is een aangewezen initialisator, wat betekent dat we de initialisatie moeten delegeren naar een aangewezen initialisator van de binnendringer
de superklasse. Dat is waarom we het init (textuur: kleur: maat :)
methode.
Je vraagt je misschien af waarom het nodig is init (coder :)
methode is er ook. De SKSpriteNode
voldoet aan de NSCoding
protocol. De init (coder :)
methode is gemarkeerd als verplicht, wat betekent dat elke subklasse deze methode moet overschrijven.
We zullen het fireBullet
methode later in deze tutorial.
In deze stap zullen we de indringers toevoegen aan de GameScene
. Open GameScene.swift en verwijder alles binnen de didMoveToView (_ :)
methode evenals alles binnen de touchesBegan (_: withEvent :)
methode. De inhoud van GameScene.swift zou er nu zo uit moeten zien.
importeer de SpriteKit-klasse GameScene: SKScene override func didMoveToView (weergave: SKView) override func touchesBegan (touches: Set, withEvent event: UIEvent) / * Wordt aangeroepen wanneer een aanraking begint * / overschrijft functie-update (currentTime: CFTimeInterval) / * Wordt aangeroepen voordat elk frame wordt weergegeven * /
We zullen één globale variabele hebben in ons project, invaderNum
. Deze variabele wordt gebruikt om het huidige niveau van het spel bij te houden. Door het te verklaren als een globale variabele, hebben we toegang tot invaderNum
over scènes. Om de variabele als een globale variabele te declareren, verklaren we deze buiten de GameScene
klasse.
import SpriteKit var invaderNum = 1 class GameScene: SKScene ...
Voeg vervolgens de volgende eigenschappen toe aan de GameScene
klasse.
class GameScene: SKScene let rowsOfInvaders = 4 var invaderSpeed = 2 let leftBounds = CGFloat (30) var rightBounds = CGFloat (0) var invadersWhoCanFire: [Invader] = [] negeren func didMoveToView (bekijk: SKView)
De rowsOfInvaders
eigenschap is hoeveel rijen indringers het spel zal hebben en de invaderSpeed
eigenschap is hoe snel de indringers zullen bewegen. De leftBounds
en rightBounds
eigenschappen worden gebruikt om een marge aan de linker- en rechterkant van het scherm te creëren, waardoor de beweging van de indringers in de linker- en rechterrichtingen wordt beperkt. En tot slot, de invadersWhoCanFire
property is een array die wordt gebruikt om bij te houden welke indringers een kogel kunnen afvuren.
Voeg de toe setupInvaders
methode onder de Update (currentTime :)
methode in de GameScene
klasse.
func setupInvaders () var invaderRow = 0; var invaderColumn = 0; laat numberOfInvaders = invaderNum * 2 + 1 voor var i = 1; ik <= rowsOfInvaders; i++ invaderRow = i for var j = 1; j <= numberOfInvaders; j++ invaderColumn = j let tempInvader:Invader = Invader() let invaderHalfWidth:CGFloat = tempInvader.size.width/2 let xPositionStart:CGFloat = size.width/2 - invaderHalfWidth - (CGFloat(invaderNum) * tempInvader.size.width) + CGFloat(10) tempInvader.position = CGPoint(x:xPositionStart + ((tempInvader.size.width+CGFloat(10))*(CGFloat(j-1))), y:CGFloat(self.size.height - CGFloat(i) * 46)) tempInvader.invaderRow = invaderRow tempInvader.invaderColumn = invaderColumn addChild(tempInvader) if(i == rowsOfInvaders) invadersWhoCanFire.append(tempInvader)
We hebben de invaderRow
en invaderColumn
variabelen die zullen worden gebruikt om de eigenschappen van dezelfde naam in te stellen op de indringer. Vervolgens gebruiken we een dubbele voor
om de indringers op het scherm te leggen. Er vindt veel conversie van het numerieke type plaats, omdat swift impliciet geen cijfers naar het juiste type converteert. Dat moeten we zelf doen.
We stellen eerst een nieuw voor binnendringer
, tempInvader
, en verklaar vervolgens een constante invaderHalfWidth
dat is de helft van de grootte van tempInvader
.
Vervolgens berekenen we de xPositionStart
zodat de indringers altijd in het midden van de scène worden uitgelijnd. We krijgen de helft van de breedte van de scène en trekken de helft van de breedte van de indringer af, omdat het standaard registratiepunt het midden is (0,5, 0,5) van de sprite. We moeten dan de breedte van de tijd van de indringer even vaak aftrekken invaderNum
is gelijk aan, en voeg 10 toe aan die waarde, omdat er 10 spatiepunten zijn tussen de indringers. In het begin is dit misschien wat moeilijk te begrijpen, dus neem je tijd om het te begrijpen.
We hebben vervolgens de binnendringer
's positie
eigendom, dat is een GGPoint
. We gebruiken een beetje meer wiskunde om te zorgen dat elke indringer 10 punten ruimte tussen zich heeft en dat elke rij 46 punten ruimte tussen hen heeft.
We wijzen de invaderRow
en invaderColumn
eigenschappen en voeg de tempInvader
naar de scène met de addChild (_ :)
methode. Als dit de laatste rij indringers is, plaatsen we de tempInvader
in de invadersWhoCanFire
rangschikking.
De setupInvaders
methode wordt aangeroepen in de didMoveToView (_ :)
methode. In deze methode hebben we ook de Achtergrond kleur
eigendom aan SKColor.blackColor
.
override func didMoveToView (weergave: SKView) backgroundColor = SKColor.blackColor () setupInvaders ()
Als je de applicatie test, zou je 4 rijen van 3 indringers moeten zien. Als je instelt invaderNum
tot 2, je zou 4 rijen van 5 indringers in het midden van de scène uitgelijnd moeten zien.
Speler
KlasseSpeler
KlasseMaak een nieuw Cocoa Touch Class genaamd Speler
dat is een subklasse van SKSpriteNode
. Voeg de volgende implementatie toe aan Player.swift.
import UIKit import Klasse SpriteKit Speler: SKSpriteNode init () let texture = SKTexture (imageNamed: "player1") super.init (textuur: textuur, kleur: SKColor.clearColor (), size: texture.size ()) animeren ( ) required init? (coder aDecoder: NSCoder) super.init (coder: aDecoder) private func animate () var playerTextures: [SKTexture] = [] voor i in 1 ... 2 playerTextures.append (SKTexture (imageNamed : "player \ (i)")) laat playerAnimation = SKAction.repeatActionForever (SKAction.animateWithTextures (playerTextures, timePerFrame: 0.1)) self.runAction (playerAnimation) func die () func kill () func respawn () func fireBullet (scène: SKScene)
De in het
methode moet bekend voorkomen. Het enige verschil is dat we een andere afbeelding gebruiken voor de eerste installatie. Er zijn twee afbeeldingen met de naam player1 en player2 in de afbeeldingenmap heeft men de boegschroef ingeschakeld en de andere heeft de boegschroef uitgeschakeld. We zullen constant schakelen tussen deze twee beelden, waardoor de illusie ontstaat dat een boegschroef aan en uit gaat. Dit is wat de bezielen
methode doet.
In de bezielen
methode, we hebben een array playerTextures
die de texturen voor de animatie zal bevatten. We voegen het toe SKTexture
objecten aan deze array met behulp van a voor in
lus en een gesloten bereik met behulp van de operator voor gesloten bereik. We gebruiken stringinterpolatie om de juiste afbeelding te krijgen en een te initialiseren SKTexture
aanleg.
We verklaren een constante, playerAnimation
, die de repeatActionForever
methode van de SKAction
klasse. In die actie roepen we aan animateWithTextures (_: timePerFrame :)
. De animateWithTextures (_: timePerFrame :)
methode neemt als parameters een array van texturen en de hoeveelheid tijd dat elke textuur wordt getoond. Ten slotte voeren we aan runAction (_ :)
en pas in de playerAnimation
.
De andere methoden worden later in deze zelfstudie geïmplementeerd.
Declareer een constante eigenschap met de naam speler
naar de GameScene
klasse.
class GameScene: SKScene ... var invadersWhoCanFire: [Invader] = [Invader] () let player: Player = Player ()
Voeg vervolgens de setupPlayer
methode onder de setupInvaders
methode.
func setupPlayer () player.position = CGPoint (x: CGRectGetMidX (self.frame), y: player.size.height / 2 + 10) addChild (speler)
U zou bekend moeten zijn met de implementatie van de setupPlayer
methode. We hebben de speler
's positie
en voeg het toe aan de scène. We gebruiken echter een nieuwe functie, CGRectGetMidX (_ :)
, die het midden van een rechthoek langs de x-as retourneert. Hier gebruiken we de tafereel
het kader.
U kunt nu het setupPlayer
methode in de didMoveToView (_ :)
methode.
override func didMoveToView (weergave: SKView) backgroundColor = SKColor.blackColor () setupInvaders () setupPlayer ()
Als je de applicatie test, zou je de speler aan de onderkant van het scherm moeten zien verschijnen terwijl de stuwraketten aanstaan en schieten.
Kogel
KlassenKogel
klasseMaak een nieuw Cocoa Touch Class genaamd Kogel
dat is een subklasse van de SKSpriteNode
klasse.
import UIKit import SpriteKit class Bullet: SKSpriteNode init (imageName: String, bulletSound: String?) let texture = SKTexture (imageNamed: imageName) super.init (textuur: texture, kleur: SKColor.clearColor (), size: texture. size ()) if (bulletSound! = nil) runAction (SKAction.playSoundFileNamed (bulletSound !, waitForCompletion: false)) vereist init? (coder aDecoder: NSCoder) super.init (coder: aDecoder)
De in het
methode neemt twee parameters, imageName
en Bulletsound
. De tweede parameter is optioneel. De speler speelt een lasergeluid telkens wanneer een kogel wordt afgevuurd. Ik heb niet de indringers die dat doen in deze game, hoewel je dat zeker wel zou kunnen. Dat is ook de reden waarom het kogelgeluid een optionele parameter is. Je zou zelfs een ander geluid kunnen gebruiken voor elk geluid.
Het eerste deel zou bekend moeten zijn, hoewel we nu het structuur
met welk beeld dan ook als het eerste argument werd doorgegeven. Hiermee kun je verschillende afbeeldingen voor de kogels van de speler en indringers gebruiken als je dat wilde.
Als Bulletsound
is niet nul
, we hebben een SKAction
methode playSoundFileNamed (_: waitForCompletion :)
. Deze methode neemt als parameters a Draad
, welke is de naam van het geluidsbestand inclusief de extensie, en een Bool
, waitForCompletion
. De waitForCompletion
parameter is niet belangrijk voor ons. Als het was ingesteld op waar
, dan zou de actie duren, hoe lang het geluidsbestand ook is.
InvaderBullet
KlasseMaak een nieuw Cocoa Touch Class genaamd InvaderBullet
dat is een subklasse van de Kogel
klasse.
import UIKit import SpriteKit class InvaderBullet: Bullet overschrijven init (imageName: String, bulletSound: String?) super.init (imageName: imageName, bulletSound: bulletSound) required init? (coder aDecoder: NSCoder) super.init (coder : aDecoder)
De implementatie van de InvaderBullet
klasse is misschien niet zo logisch, omdat we alleen de init (imageName: Bulletsound :)
methode van de superklasse in de init (imageName: Bulletsound :)
initializer. Het zal echter veel logischer zijn waarom het op deze manier is ingesteld wanneer we code toevoegen voor detectie van botsingen.
PlayerBullet
KlasseMaak een nieuw Cocoa Touch Class genaamd PlayerBullet
dat is ook een subklasse van de Kogel
klasse. Zoals u kunt zien, is de implementatie van de PlayerBullet
klasse is identiek aan die van de InvaderBullet
klasse.
import UIKit import SpriteKit class PlayerBullet: Bullet overschrijven init (imageName: String, bulletSound: String?) super.init (imageName: imageName, bulletSound: bulletSound) required init? (coder aDecoder: NSCoder) super.init (coder : aDecoder)
In deze zelfstudie hebben we enkele van de belangrijkste klassen van het spel gemaakt en geïmplementeerd. We hebben een raster van indringers aan de scène toegevoegd en het ruimteschip dat de speler zal besturen. We zullen blijven werken met deze klassen in het volgende deel van deze serie waarin we de gameplay implementeren.