I denna handledning, den andra delen av SpriteKit From Scratch-serien, lär du dig om begränsningar och åtgärder. Dessa funktioner används för att enkelt lägga till rörelser och animeringar till ditt SpriteKit-spel medan du begränsar positionen och orienteringen av noder i spelet.
För att följa med mig kan du antingen använda projektet du skapade i den första handledningen i den här serien eller ladda ner en ny kopia från GitHub.
Grafiken som används för spelet i denna serie finns på GraphicRiver. GraphicRiver är en bra källa för att hitta konstverk och grafik för dina spel.
Innan vi kan börja lägga till begränsningar och åtgärder till en scen, måste vi först skapa några klasser så att vi kan arbeta med våra noder i kod. Skapa en ny klass, PlayerNode, baserat på iOS> Källa> Kakao Touch Class mall och se till att det är en underklass av SKSpriteNode
.
Om Xcode kastar ett fel efter att ha skapat klassen lägger du till en importrapport för SpriteKit-ramen under importera UIKit
påstående:
importera UIKit import SpriteKit
Därefter förklara följande tre egenskaper i PlayerNode
klass. Dessa egenskaper kommer att hålla de begränsningar som används för att begränsa bilens horisontella rörelse.
importera UIKit import SpriteKit klass PlayerNode: SKSpriteNode var leftConstraint: SKConstraint! var middleConstraint: SKConstraint! var rightConstraint: SKConstraint!
Skapa en annan Kakao Touch Class och namnge det MainScene, gör det till en underklass av SKScene
.
Till toppen lägger du till ett importdeklaration för SpriteKit-ramen.
importera UIKit import SpriteKit
Med dessa klasser skapade, öppna MainScene.sks, klicka på den grå bakgrunden för att välja scenen, öppna den Anpassad klassinspektör till höger och sätt Anpassad klass till MainScene.
Välj bil och ställ in sin klass till PlayerNode på samma sätt som du gjorde för scenen. Slutligen, med bilen fortfarande vald, öppna Egenskaper Inspector och ändra namn till Spelare.
Nu när vi har de grundläggande klasserna inrättat kan vi börja skapa några begränsningar i koden.
Begränsningar i SpriteKit, representerad av SKConstraint
klass, används för att begränsa positionen och orienteringen av vissa noder. Mycket variation kan uppnås med begränsningar, eftersom de kan vara i förhållande till scenen eller i förhållande till andra noder. Begränsningar arbetar också med värden utöver konstanta värden så att sprites inom din scen kan fixas till en viss plats eller tillåtas att röra sig inom ett visst område.
De begränsningar som vi ska lägga till är de tre som vi förklarade i PlayerNode
klass. Dessa begränsningar kommer att användas för att låsa bilen till de tre banorna i spelet.
Öppna MainScene.swift och skapa en egenskap för spelaren av typen PlayerNode!
. Den här egenskapen lagrar en referens till spelarnoden.
importera UIKit import SpriteKit klass MainScene: SKScene var spelare: PlayerNode!
Därefter åsidosätter vi didMoveToView (_ :)
metod för MainScene
klass:
åsidosätta func didMoveToView (visa: SKView) super.didMoveToView (view) size = view.frame.size om låt foundPlayer = childNodeWithName ("Player") som? PlayerNode player = foundPlayer låt centrum = size.width / 2.0, skillnad = CGFloat (70.0) player.leftConstraint = SKConstraint.positionX (SKRange (constantValue: center-difference)) player.middleConstraint = SKConstraint.positionX (SKRange (constantValue: center)) player.rightConstraint = SKConstraint.positionX (SKRange (constantValue: center + difference)) player.leftConstraint.enabled = false player.rightConstraint.enabled = false player.constraints = [player.leftConstraint, player.middleConstraint, player.rightConstraint ]
Låt oss gå igenom koden steg för steg. De didMoveToView (_ :)
Metoden heter när scenen presenteras av en vy. Efter att ha ringt till didMoveToView (_ :)
Metoden för superklassen, vi ändrar storleken på scenen i samma storlek som den aktuella vyn. Detta säkerställer att scenen alltid fyller på den aktuella enhetens skärm och skalar på rätt sätt.
Vi får tillgång till spelarens sprite som vi lagt till i Xcode scenredigeraren genom att leta efter den med namnet vi gav det tidigare. Vi tilldelar sedan detta värde till spelare
fast egendom.
Efter att ha beräknat centrum av scenen och specificerar en konstant skillnad på 70,0
, vi skapar spriteens begränsningar. Genom att använda positionX (_ :)
klass metod av SKConstraint
klass skapar vi vänstra, mitten och rätt begränsningar för spelarens sprite. Denna metod kräver en SKRange
Exempel som en parameter, som i vårt fall är ett intervall med ett konstant värde. Om du vill titta på de möjliga begränsningarna och sträckorna i SpriteKit, rekommenderar jag att du tittar på SKConstraint
och SKRange
klassreferenser.
Vi inaktiverar vänstra och högra hinder, eftersom vi inte vill att dessa ska fungera på spelarnoden när spelet börjar. Slutligen tilldelar vi dessa begränsningar till begränsningar
egenskapen hos spelarnoden. Den här egenskapen definieras i SKNode
klass.
Bygg och kör ditt spel på vilken simulator eller fysisk enhet som helst. Du bör nu se att din scen är skalad korrekt med bilen centrerad längst ner.
Du kan se att bilen nu är begränsad till det horisontella centrumet av scenen och kan begränsas till vänster och höger körfält när vi lägger lite rörelse i spelet.
Åtgärder i SpriteKit representeras av den kraftfulla SKAction
klass. Åtgärder tillåter oss att enkelt animera och flytta sprites i en scen. De utförs av noder och utvärderas av SpriteKit API: erna och funktionen tillsammans med begränsningar och fysiksimuleringar.
Förutom att ange vad en åtgärd gör kan du också programmera hur åtgärden fungerar genom att konfigurera den. Du kan till exempel pausa och fortsätta handlingar eller konfigurera en åtgärds lättnad beteende. Detta ger dig större kontroll eftersom du enkelt kan påskynda eller sakta ner vissa åtgärder för att producera några intressanta spelelement.
På samma sätt som hur noder kan ha barnkoder finns det tre typer av åtgärder som kan ha barnåtgärder:
Du kan skapa åtgärder programmatiskt eller i Xcodes scenredigerare, som vi använde i föregående handledning. Vi ska använda båda teknikerna i denna handledning.
Öppna MainScene.sks och klicka på ikonen bredvid Animera knappen längst ner till vänster på scenen för att få fram Action Editor View.
Därefter rullar du ner i Objektbibliotek till höger och hitta Flytta åtgärd Artikel. Klicka och dra det här till tidslinjen för Action Editor View och placera den i vänstra kanten enligt nedan:
Detta gör att åtgärden börjar börja utföras på 00:00, det är så snart scenen presenteras. Om den placeras någon annanstans skulle åtgärden börja utföras efter det tidsintervall som visas längst upp på tidslinjen.
Håll musen över åtgärden och klicka på den lilla pilikonen längst ned till vänster. I popupen som visas klickar du på oändlighet knappen till vänster. Detta medför att åtgärden repeteras för alltid.
Med den åtgärd som fortfarande valts öppnar du Attribut Inspector till höger och ändra Y Offset värde till 100.
De andra värdena anger att bilen börjar animera omedelbart (Starttid) och varje 1 andra (Varaktighet) ska flytta 0 poäng i X riktning och 100 i Y riktning (Offset). De Timing Funktion egendom kan användas för att gradvis starta och / eller stoppa en åtgärd. I det här fallet använder vi Linjär, vilket innebär att bilen alltid rör sig med samma hastighet.
Slutligen, för att testa åtgärden, klicka på Animera knappen längst ned till vänster i scenredigeraren. Den nedre verktygsfältet ska bli blå och bilen ska börja röra sig upp.
Med den rörliga åtgärden som implementeras är det dags att programmera de horisontella åtgärderna. Innan vi gör det måste vi lägga till lite logik så att knapparna i spelet kan styra bilen.
Skapa en ny fil genom att välja iOS> Källa> Swift File mall och namnge den LaneStateMachine.
Lägg till följande kod i den nya filen:
importera GameplayKit klass LaneStateMachine: GKStateMachine klass LaneState: GKState var playerNode: PlayerNode init (spelare: PlayerNode) playerNode = player klass VänsterLane: LaneState override func isValidNextState (stateClass: AnyClass) -> Bool if stateClass == MiddleLane.self return true return false omdirigera func didEnterWithPreviousState (tidigareState: GKState?) PlayerNode.moveInDirection (.Left, toLane: self) klass MiddleLane: LaneState override func isValidNextState (stateClass: AnyClass) -> Bool om stateClass == LeftLane.self || stateClass == RightLane.self return true returnera false åsidosätta func didEnterWithPreviousState (tidigareState: GKState?) om tidigareState är LeftLane playerNode.moveInDirection (.Right, toLane: self) annars om tidigareState är RightLane playerNode.moveInDirection .Lever, toLane: själv) klass RightLane: LaneState omstyra func isValidNextState (stateClass: AnyClass) -> Bool if stateClass == MiddleLane.self return true returnera false åsidosätta func didEnterWithPreviousState (tidigareState: GKState?) playerNode.moveInDirection (.Right, toLane: själv)
All denna kod gör, utnyttjar det nya GameplayKit-ramverket för att skapa en statlig maskin som representerar de tre banorna och rörelsen mellan dem i spelet. Om du vill bättre förstå vad den här koden gör, kolla in min handledning som täcker GameplayKit.
Nästa, öppna PlayerNode.swift och lägg till följande två metoder till PlayerNode
klass:
func disableAllConstraints () leftConstraint.enabled = false middleConstraint.enabled = false rightConstraint.enabled = false func moveInDirection (riktning: ButtonDirection, toLane lane: LaneState) disableAllConstraints () låt ändraInX = (riktning == .Left)? -70.0: 70.0 låt rotation = (riktning == .Left)? M_PI / 4: -M_PI / 4 låt varaktighet = 0,5 låt moveAction = SKAction.moveByX (CGFloat (changeInX), y: 0.0, duration: duration) låt roteraAction = SKAction.rotateByAngle (CGFloat (rotation), duration: duration / 2) rotateAction.timingMode = .EaseInEaseOut låt roteraSequence = SKAction.sequence ([roteraAction, rotateAction.reversedAction ()]) låt moveGroup = SKAction.group ([moveAction, rotateSequence]) låt completion = SKAction.runBlock () -> Radera in lane case är LeftLane: self.leftConstraint.enabled = true case är MiddleLane: self.middleConstraint.enabled = true case är RightLane: self.rightConstraint.enabled = true default: break låt sequenceAction = SKAction.sequence ([moveGroup, slutförande]) runAction (sequenceAction)
De disableAllConstraints ()
Metoden är en bekväm metod för att inaktivera spelarens nod.
I moveInDirection (_: toLane :)
, Vi bestämmer vilken riktning bilen ska röra sig i horisontellt, -70,0 när du flyttar vänster och +70,0 när du flyttar höger. Vi beräknar då den rätta vinkeln (i radianer) för att rotera bilen när den flyttas. Observera att positiva tal representerar rotation moturs.
Efter att ha angivit en konstant varaktighet skapar vi rörelsen och roterar åtgärder genom att använda moveByX (_: y: varaktighet :)
och rotateByAngle (_: varaktighet :)
klassmetoder. Vi skapar en rotationssekvens för att rotera bilen tillbaka till hur det var före rörelsen. De reversedAction ()
Metoden skapar automatiskt det omvända av en åtgärd för dig.
Därefter skapar vi en rörelsegruppsaktivitet för att utföra horisontell rörelse och rotation samtidigt. Slutligen skapar vi en färdighetsåtgärd för att genomföra en stängning när den utförs. I den här stängningen kan vi ta reda på vilken körfält bilen är för närvarande och möjliggöra den korrekta begränsningen för den körfältet.
Öppna ViewController.swift och lägg till en egendom, statsmaskin
, av typ LaneStateMachine!
till ViewController
klass.
klass ViewController: UIViewController var stateMachine: LaneStateMachine! ...
Ersätt implementeringen av viewDidLoad ()
och didPressButton (_ :)
i ViewController
klass med följande:
åsidosätta func viewDidLoad () super.viewDidLoad () låt skView = SKView (frame: view.frame) låt scen = MainScene (filnamn: "MainScene")! skView.presentScene (scene) view.insertSubview (skView, atIndex: 0) låt vänster = LeftLane (spelare: scene.player) låt mitten = MiddleLane (spelare: scene.player) låt höger = RightLane (spelare: scene.player) stateMachine = LaneStateMachine (stater: [vänster, mitten, höger]) stateMachine.enterState (MiddleLane) @IBAction func didPressButton (avsändare: UIButton) switch sender.tag fall ButtonDirection.Left.rawValue: switch stateMachine.currentState fallet är RightLane : stateMachine.enterState (MiddleLane) är MiddleLane: stateMachine.enterState (LeftLane) standard: break case ButtonDirection.Right.rawValue: switch stateMachine.currentState fallet är LeftLane: stateMachine.enterState (MiddleLane) är MiddleLane: stateMachine.enterState (RightLane) standard: break standard: break
I viewDidLoad ()
, vi sätter in SKView
objekt på index 0 så att kontrollknapparna är synliga och vi initierar också tillståndsmaskinen.
I didPressButton (_ :)
, vi får reda på vilken knapp som användaren trycker på, baserat på taggarna på knapparna och ange rätt körfält från var bilen är närvarande.
Bygg och kör spelet. Tryck antingen på vänster eller höger knapp längst ner på skärmen för att få bilen att röra sig. Du ska se bilen vända och flytta i riktning mot den knapp som du tryckte på.
Observera att knappikonen kan vara felaktiga enligt nedan.
För att åtgärda detta öppnar du tillgångskatalogen (Image.xcassets) och för varje bild (Vänster pil och Höger pil) uppsättning Rendering Mode till Originalbild.
Du bör nu vara säker på att använda begränsningar och åtgärder i SpriteKit. Som du kan se, gör dessa funktioner i ramverket det väldigt enkelt att lägga till animeringar och rörelser i ett SpriteKit-spel.
I nästa handledning av denna serie kommer vi att titta på kamerans noder i SpriteKit så att vår bil inte alltid rör sig längst upp på skärmen. Efter det kommer vi att se djupt på fysiksimuleringssystemet i SpriteKit med fokus på fysikorgan och kollisionsdetektering.
Som alltid, var noga med att lämna dina kommentarer och feedback i kommentarerna nedan.