SpriteKit From Scratch Begrensninger og handlinger

Introduksjon

I denne opplæringen, den andre delen av SpriteKit From Scratch-serien, lærer du om begrensninger og handlinger. Disse funksjonene brukes til å enkelt legge til bevegelse og animasjoner til SpriteKit-spillet mens du begrenser posisjonen og orienteringen av noder i spillet.

For å følge med meg kan du enten bruke prosjektet du opprettet i første opplæring i denne serien eller laste ned en ny kopi fra GitHub.

Grafikken som brukes til spillet i denne serien, finnes på GraphicRiver. GraphicRiver er en god kilde for å finne kunst og grafikk for spillene dine.

1. Tilpasset node og sceneklasser

Før vi kan begynne å legge til begrensninger og handlinger til en scene, må vi først lage noen klasser slik at vi kan jobbe med våre noder i kode. Lag en ny klasse, PlayerNode, basert på iOS> Kilde> Kakao Touch Class mal og sørg for at det er en underklasse av SKSpriteNode.

Hvis Xcode kaster en feil etter at du har opprettet klassen, legger du til en importoppgave for SpriteKit-rammen under importere UIKit uttalelse:

importere UIKit import SpriteKit

Deretter erklæres følgende tre egenskaper i PlayerNode klasse. Disse egenskapene vil holde begrensningene som brukes til å begrense bilens horisontale bevegelse.

importere UIKit import SpriteKit klasse PlayerNode: SKSpriteNode var leftConstraint: SKConstraint! var middleConstraint: SKConstraint! var rightConstraint: SKConstraint! 

Lag en annen Cocoa Touch Class og nev det MainScene, gjør det til en underklasse av SKScene.

På toppen legger du til en importerklæring for SpriteKit-rammeverket.

importere UIKit import SpriteKit

Med disse klassene opprettet, åpne MainScene.sks, klikk på den grå bakgrunnen for å velge scene, åpne den Tilpasset klasseinspektør til høyre, og sett Tilpasset klasse til MainScene.

Velg bilen og sett sin klasse til PlayerNode på samme måte som du gjorde for scenen. Til slutt, med bilen fortsatt valgt, åpner du attributter Inspektør og endre Navn til Spiller.

Nå som vi har grunnklassene satt opp, kan vi begynne å lage noen begrensninger i koden.

2. Begrensninger

Begrensninger i SpriteKit, representert av SKConstraint klassen, brukes til å begrense posisjon og orientering av bestemte noder. Mye variasjon kan oppnås med begrensninger som de kan være i forhold til scenen eller i forhold til andre noder. Begrensninger arbeider også med verdier i tillegg til konstante verdier, slik at sprites innenfor din scene kan festes til et bestemt sted eller lov til å bevege seg innenfor et bestemt område.

Begrensningene vi skal legge til er de tre som vi erklærte i PlayerNode klasse. Disse begrensningene vil bli brukt til å låse bilen til de tre banene i spillet.

Åpen MainScene.swift og opprett en eiendom for spilleren av typen PlayerNode!. Denne egenskapen lagrer en referanse til spillerens knutepunkt.

importere UIKit import SpriteKit klasse MainScene: SKScene var spiller: PlayerNode! 

Deretter overstyrer vi didMoveToView (_ :) metode av MainScene klasse:

overstyr func didMoveToView (visning: SKView) super.didMoveToView (view) size = view.frame.size hvis la foundPlayer = childNodeWithName ("Player") som? PlayerNode player = foundPlayer la center = size.width / 2.0, difference = CGFloat (70.0) player.leftConstraint = SKConstraint.positionX (SKRange (constantValue: senterforskjell)) player.middleConstraint = SKConstraint.positionX (SKRange (constantValue: center)) player.rightConstraint = SKConstraint.positionX (SKRange (constantValue: senter + forskjell)) player.leftConstraint.enabled = false player.rightConstraint.enabled = false player.constraints = [player.leftConstraint, player.middleConstraint, player.rightConstraint ]

La oss gå gjennom koden trinn for trinn. De didMoveToView (_ :) Metoden kalles når scenen presenteres av en visning. Etter å ha ringt didMoveToView (_ :) metode for superklassen, endrer vi størrelsen på scenen til samme størrelse som den nåværende visningen. Dette sikrer at scenen alltid fyller på størrelsen på den nåværende enhetens skjerm og skaleres på riktig måte.

Vi får tilgang til spilleren sprite vi lagt til i Xcode scene editor ved å søke etter det ved navnet vi ga det tidligere. Vi tilordner så denne verdien til spiller eiendom.

Etter beregning av sentrum av scenen og angi en konstant forskjell på 70.0, Vi skaper spritets begrensninger. Ved å bruke positionX (_ :) klasse metode av SKConstraint klasse, lager vi venstre, mellom og høyre begrensninger for spillerens sprite. Denne metoden krever en SKRange eksempel som en parameter, som i vårt tilfelle er et område med en konstant verdi. Hvis du vil se på mulige begrensninger og spekter i SpriteKit, anbefaler jeg å ta en titt på SKConstraint og SKRange klassen referanser.

Vi deaktiverer de venstre og høyre begrensningene, fordi vi ikke vil at disse skal fungere på spillerens knutepunkt når spillet starter. Til slutt tildeler vi disse begrensningene til begrensninger Egenskapen til spillerens knutepunkt. Denne egenskapen er definert i SKNode klasse.

Bygg og kjør spillet ditt på en hvilken som helst simulator eller fysisk enhet. Du bør nå se at scenen din skaleres riktig med bilen sentrert nederst.

Du kan se at bilen nå er begrenset til det horisontale sentrum av scenen og kan begrenses til venstre og høyre baner når vi legger litt bevegelse til spillet.

2. Handlinger

Handlinger i SpriteKit er representert av den kraftige SKAction klasse. Handlinger lar oss enkelt animere og flytte sprites i en scene. De blir utført av noder og evalueres av SpriteKit API og funksjon sammen med begrensninger og fysikk simuleringer.

I tillegg til å spesifisere hva en handling gjør, kan du også programmere hvordan handlingen fungerer ved å konfigurere den. Du kan for eksempel pause og gjenoppta handlinger eller konfigurere en handlings lette oppførsel. Dette gir deg større grad av kontroll som du enkelt kan øke eller senke bestemte handlinger for å produsere noen interessante spillelementer.

På samme måte som hvordan noder kan ha barnnoder, er det tre typer handlinger som kan ha barns handlinger:

  • sekvens handlinger som utfører en rekke handlinger etter hverandre
  • gruppe handlinger, som utfører en rekke handlinger på samme tid
  • gjenta handlinger, som gjentar en enkelt handling for et gitt antall ganger eller på ubestemt tid

Du kan opprette handlinger programmatisk eller i Xcodes sceneredigerer, som vi brukte i den forrige opplæringen. Vi skal bruke begge teknikkene i denne opplæringen.

Åpen MainScene.sks og klikk på ikonet ved siden av animere knappen nederst til venstre på scenen for å hente opp Handlingsredigeringsvisning.

Deretter ruller du ned i Objektbibliotek til høyre og finn Flytt handling punkt. Klikk og dra dette inn i tidslinjen til Handlingsredigeringsvisning og plasser den på venstre kant som vist nedenfor:

Dette fører til at handlingen begynner å utføres på 00:00, det er så snart scenen presenteres. Hvis du er plassert et annet sted, vil handlingen begynne å bli utført etter tidsintervallet som vises øverst på tidslinjen.

Hold musen over handlingen, og klikk på det lille pilikonet nederst til venstre. I popup-vinduet som vises, klikker du på evighet knappen til venstre. Dette fører til at handlingen gjentas for alltid.

Med handlingen som er valgt, åpner du Attributtsinspektør til høyre og endre Y Offset verdi til 100.

De andre verdiene angir at bilen starter, vil animere umiddelbart (Starttid) og hver 1 sekund (Varighet) vil flytte 0 poeng i X retning og 100retning (offset). De Timing Funksjon Eiendom kan brukes til å gradvis starte og / eller stoppe en handling. I dette tilfellet bruker vi lineær, som betyr at bilen alltid beveger seg med samme hastighet.

Til slutt, for å teste ut handlingen, klikk på animere knappen nederst til venstre i sceneditoren. Den nederste verktøylinjen skal bli blå og bilen skal begynne å bevege seg opp.

Med flyttehandlingen implementert, er det på tide å lage de horisontale handlingene programmatisk. Før vi gjør det, må vi legge til noen logikk, slik at knappene i spillet kan styre bilen.

Opprett en ny fil ved å velge iOS> Kilde> Swift File mal og navn den LaneStateMachine.

Legg til følgende kode i den nye filen:

importere GameplayKit klasse LaneStateMachine: GKStateMachine  klasse LaneState: GKState var playerNode: PlayerNode init (spiller: PlayerNode) playerNode = player klasse LeftLane: LaneState override func isValidNextState (stateClass: AnyClass) -> Bool if stateClass == MiddleLane.self return true return false override func didEnterWithPreviousState (forrigeState: GKState?) PlayerNode.moveInDirection (.Liv, toLane: self) klasse MiddleLane: LaneState overstyr func isValidNextState (stateClass: AnyClass) -> Bool  hvis stateClass == LeftLane.self || stateClass == RightLane.self return true return false overstyr func didEnterWithPreviousState (forrigeState: GKState?) hvis forrigeState er LeftLane playerNode.moveInDirection (.Right, toLane: self) annet hvis forrigeStat er RightLane playerNode.moveInDirection .Lever, toLane: selv) klasse RightLane: LaneState override func isValidNextState (stateClass: AnyClass) -> Bool if stateClass == MiddleLane.self return true return false overstyr func didEnterWithPreviousState (forrigeState: GKState?) playerNode.moveInDirection (.Right, toLane: selv)

Alt denne koden gjør, er å bruke det nye GameplayKit-rammeverket for å lage en statlig maskin som representerer de tre banene og bevegelsen mellom dem i spillet. Hvis du vil bedre forstå hva denne koden gjør, sjekk ut min opplæring som dekker GameplayKit.

Deretter åpne PlayerNode.swift og legg til følgende to metoder til PlayerNode klasse:

func disableAllConstraints () leftConstraint.enabled = false middleConstraint.enabled = false rightConstraint.enabled = false func moveInDirection (retning: ButtonDirection, toLane lane: LaneState) disableAllConstraints () la endreInX = (retning == .Left)? -70.0: 70.0 la rotasjon = (retning == .Left)? M_PI / 4: -M_PI / 4 la varighet = 0,5 la moveAction = SKAction.moveByX (CGFloat (changeInX), y: 0.0, varighet: varighet) la rotateAction = SKAction.rotateByAngle (CGFloat (rotasjon), varighet: varighet / 2) rotateAction.timingMode = .EaseInEaseOut la rotateSequence = SKAction.sequence ([rotateAction, rotateAction.reversedAction ()]) la moveGroup = SKAction.group ([moveAction, rotateSequence]) la ferdigstillelse = SKAction.runBlock () -> Ugyldig bryter lane case er LeftLane: self.leftConstraint.enabled = sant tilfelle er MiddleLane: self.middleConstraint.enabled = sant tilfelle er RightLane: self.rightConstraint.enabled = true default: break la sequenceAction = SKAction.sequence ([moveGroup, fullføring]) runAction (sekvensAction)

De disableAllConstraints () Metode er en praktisk metode for å deaktivere begrensningene til spillerens knutepunkt.

moveInDirection (_: toLane :), Vi bestemmer hvilken retning bilen skal bevege seg horisontalt, -70.0 når du flytter til venstre og +70.0 når du beveger deg rett. Vi beregner deretter den riktige vinkelen (i radianer) for å rotere bilen ved flytting. Merk at positive tall representerer en rotasjon mot urviseren.

Etter å ha angitt en konstant varighet, lager vi flytningen og roterer handlinger ved å bruke moveByX (_: y: varighet :) og rotateByAngle (_: varighet :) klassemetoder henholdsvis. Vi lager en rotasjonssekvens for å rotere bilen tilbake til hvordan det var før bevegelsen. De reversedAction () Metoden oppretter automatisk omvendt av en handling for deg.

Deretter oppretter vi en bevegelsegruppehandling for å utføre horisontal trekk og rotasjon samtidig. Endelig oppretter vi en fullføringshandling for å utføre en lukning når den utføres. I denne lukkingen finner vi ut hvilken bane bilen er i og aktiverer den riktige begrensningen for den banen.

Åpen ViewController.swift og legg til en eiendom, State, av type LaneStateMachine! til ViewController klasse.

klasse ViewController: UIViewController var stateMachine: LaneStateMachine! ...

Erstatt implementeringen av viewDidLoad () og didPressButton (_ :) i ViewController klasse med følgende:

overstyr func viewDidLoad () super.viewDidLoad () la skView = SKView (ramme: view.frame) la scene = MainScene (filNamed: "MainScene")! skView.presentScene (scene) view.insertSubview (skView, atIndex: 0) la venstre = LeftLane (spiller: scene.player) la middle = MiddleLane (spiller: scene.player) la høyre = RightLane (spiller: sceneplayer) stateMachine = LaneStateMachine (stater: [venstre, mellom, høyre]) stateMachine.enterState (MiddleLane) @IBAction func didPressButton (sender: UIButton) bytter sender.tag tilfelle ButtonDirection.Left.rawValue: switch stateMachine.currentState tilfelle er RightLane : stateMachine.enterState (MiddleLane) saken er MiddleLane: stateMachine.enterState (LeftLane) standard: break tilfelle ButtonDirection.Right.rawValue: bytt stateMachine.currentState saken er LeftLane: stateMachine.enterState (MiddleLane) saken er MiddleLane: stateMachine.enterState (RightLane) standard: break standard: break

I viewDidLoad (), vi setter inn SKView objekt på indeksen 0 slik at kontrollknappene er synlige, og vi initialiserer også tilstandsmaskinen.

didPressButton (_ :), vi finner ut hvilken knapp brukeren trykker på, basert på knappene på knappene, og skriver inn den riktige banen fra hvor bilen er i øyeblikket.

Bygg og kjør spillet. Trykk enten venstre eller høyre knapp nederst på skjermen for å få bilen til å bevege seg. Du bør se bilen vende og flytte i retning av knappen du trykket på.

Merk at knappikonene kan være feilaktige som vist nedenfor.

For å fikse dette, åpne aktivakatalogen (Image.xcassets) og for hvert bilde (Venstre pil og Høyre pil) sett Rendering Mode til Opprinnelig bilde.

Konklusjon

Du bør nå være trygg på å bruke begrensninger og handlinger i SpriteKit. Som du kan se, gjør disse funksjonene i rammen det veldig enkelt å legge til animasjoner og bevegelser til et SpriteKit-spill.

I neste veiledning av denne serien skal vi se på kamera noder i SpriteKit slik at bilen vår ikke alltid beveger seg oppe på toppen av skjermen. Etter dette vil vi se nærmere på fysikk simuleringssystemet i SpriteKit med fokus på fysikklegemer og kollisjonsdeteksjon.

Som alltid, vær sikker på å legge igjen dine kommentarer og tilbakemeldinger i kommentarene nedenfor.