I denne opplæringen, den tredje delen av SpriteKit From Scratch-serien, tar vi et detaljert innblikk i fysikk simuleringsfunksjonaliteten til SpriteKit og hvordan dette kan utnyttes i 2D SpriteKit-spillene dine.
Denne opplæringen krever at du kjører Xcode 7.3 eller høyere, som inkluderer Swift 2.2 og iOS 9.3, tvOS 9.2 og OS X 10.11.4 SDKs.
For å følge med, kan du enten bruke prosjektet du opprettet i den forrige opplæringen 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.
Den første delen av en fysikk simulering i SpriteKit er physicsWorld
eiendom av gjeldende scene. Denne eiendommen er en SKPhysicsWorld
objekt som definerer egenskaper som din scene er tyngdekraft, fysikk simuleringshastighet og kontaktperson. Fysikkverdener kan også definere ledd mellom objekter for å effektivt knytte flere noder sammen på bestemte punkter.
For toppvisning stilspill vi lager i denne serien, ønsker vi å endre standardgravitasjonsverdien fra SpriteKit. Standardgravitasjonen er beregnet for a forfra spill med en verdi på (0, -9,8) som simulerer jordens tyngdekraft, det vil si, 0 horisontal akselerasjon og en nedadgående akselerasjon av 9.8m / s². For vårt spill trenger vi 0 vertikal tyngdekraft slik at bilen ikke begynner å akselerere nedover når vi setter dens fysikkegenskaper.
Åpen MainScene.sks og klikk på den grå bakgrunnen for å velge scene. Deretter åpner du Attributtsinspektør og endre Tyngde slik at begge X og Y komponenter er satt til 0.
Det er viktig å merke seg at tyngdekraften er den eneste fysikkverdenen som kan endres ved hjelp av Xcodes sceneredaktør. Eventuelle andre egenskaper må endres programmatisk.
For at spillet skal kunne oppdage kollisjoner mellom objekter, må vi sette scenens fysikkverden contactDelegate
eiendom. Denne delegaten kan være ethvert objekt som samsvarer med SKPhysicsContactDelegate
protokoll. Denne protokollen definerer to metoder, didBeginContact (_ :)
og didEndContact (_ :)
. Du kan bruke disse metodene til å utføre handlinger basert på objekter som kolliderer i scenen.
For å holde vår kode sammen, skal vi lage MainScene
eksempelvis sin egen kontaktdelegate. Åpen MainScene.swift og rediger MainScene
klasse definisjon for å passe til SKPhysicsContactDelegate
protokollen.
importere UIKit import SpriteKit klasse MainScene: SKScene, SKPhysicsContactDelegate ...
I didMoveToView (_ :)
, vi satte MainScene
eksempel som kontaktdelegator for physicsWorld
eiendom.
overstyr func didMoveToView (se: SKView) ... physicsWorld.contactDelegate = self
Vi vil implementere metodene til SKPhysicsContactDelegate
protokollen senere. Vi må først sette opp fysikkegenskapene til noderne i scenen.
Enhver node i SpriteKit som du vil simulere fysikk på på en måte må tildeles en unik SKPhysicsBody
gjenstand. Fysikkorganer inneholder flere egenskaper, inkludert:
I spillene dine kan du også definere opptil 32 unike kategorier og en fysikk kropp kan tilordnes til et hvilket som helst antall av disse kategoriene. Kategorier er svært nyttige for å bestemme hvilke noder i din scene kan samhandle med hverandre når det gjelder kollisjoner.
På fysikkorganer er disse kategoriene representert av categoryBitMask
og collisionBitMask
egenskaper, som begge er gitt 0xFFFFFFFF verdi som standard. Dette betyr at alle noder tilhører alle kategorier. Det er viktig å merke seg at i denne verdien, hvert heksadesimale siffer F er en shorthandform og representerer tallet 15 i binære sifre (1111) som hver svarer til en av de 32 kategoriene du kan bruke.
Når to noder kolliderer, en logisk OG
operasjonen utføres på collisionBitMask
og categoryBitMask
av henholdsvis den første og den andre kroppen. Hvis resultatet er en null-verdi, utfører SpriteKit sin simulering på de to noder kroppen tilhører.
Merk at dette OG
beregning utføres to ganger med de to organene byttet rundt. For eksempel:
bodyA.collisionBitMask & bodyB.categoryBitMask
bodyB.collisionBitMask & bodyA.categoryBitMask
Hvis du ikke vet hvordan en OG
operatør fungerer, så her er et veldig enkelt eksempel skrevet i Swift:
la mask1 = 0x000000FF la mask2 = 0x000000F0 la resultatet = mask1 & mask2 // resultat = 0x000000F0
De OG
operatøren bestemmer hvilke deler av bitmasker som er de samme og returnerer en ny bitmaskeverdi som inneholder de matchende delene.
En viktig ting å merke seg er at disse bitmasker bare påvirker SpriteKits side av fysikk simuleringen, og du blir ikke varslet om kollisjoner oppdaget på denne måten. Dette betyr at organer kan samhandle med hverandre, men ingen av kontaktdelegatorens metoder kalles.
For at disse metodene skal utføres, må du angi en contactTestBitMask
for hver kropp, som produserer en ikke-null verdi når en OG
operatør fungerer på dem. For alle fysikklegemer har denne bitmasken en standardverdi på 0x00000000 noe som betyr at du ikke vil bli varslet om eventuelle kollisjoner som fysikkorganet deltar i.
Fysikkorganer, inkludert deres forskjellige bitmasker, kan settes opp i Xcode scene editor. Åpen MainScene.sks, velg bilen, og åpne Attributtsinspektør til høyre. Rull ned til Fysikk Definisjon seksjon.
Fordi Kroppstype er satt til Ingen, Ingen av egenskapene knyttet til fysikk er synlige. For å endre dette må vi sette Kroppstype til en annen verdi enn Ingen. Tre kroppstyper er tilgjengelige:
Disse tre fysikk kroppstyper er de vanligste i SpriteKit. Bundet rektangel og Bounding sirkel arbeid ved å skape en barriere rundt sprite som skal brukes i fysikk simuleringer. Dette betyr at sprite kolliderer med en annen knute når dens avgrensende form treffer en annen knutes fysikk kropp.
Kanten på et avgrensende rektangel er nøyaktig det samme som nodens størrelse vist i sceneditoren. Hvis du velger Bounding sirkel, Du ser imidlertid en tynn lyseblå sirkel som representerer formen på avgrensesirkelen.
Alfa maske virker litt annerledes og ser på den faktiske bildestrukturen til sprite for å bestemme fysikkens kropps kanter. Denne kroppstypen er den mest nøyaktige i SpriteKit, men det kan ha stor innvirkning på spillets ytelse, spesielt når du bruker sprites med komplekse former.
For vårt spill, siden vi bare bruker en bilsprite og vår scene ikke er spesielt kompleks, skal vi bruke Alfa maske Kroppstype. Det er ikke anbefales å bruke denne kroppstypen for alle sprites i scenen din selv om den er den mest nøyaktige. Når du velger dette alternativet fra rullegardinmenyen, bør du se en lyseblå linje vises rundt kanten av bilen.
Det er viktig å merke seg at andre typer fysikkorganer kan opprettes programmatisk, for eksempel organer fra CGPath
objekter samt sirkler og rektangler av egendefinerte størrelser.
Fortsatt i Attributtsinspektør, Du bør nå se flere alternativer tilgjengelig for deg i Fysikk Definisjon seksjon. Den eneste eiendommen vi trenger å endre er Kontakt Mask. Endre dette til en verdi av 1.
Med bilens fysikk kropp satt opp, kan vi begynne å sette noen hindringer inn i spillet for å kollidere med bilen.
Før vi implementerer metodene til SKPhysicsContactDelegate
protokoll, må vi legge til noen hindringer for at bilen skal unngå. For å gjøre dette skal vi gyte et nytt hinder hvert tredje sekund foran bilen og plassere hinderet i en tilfeldig felt.
Åpen MainScene.swift og legg til en importerklæring for GameplayKit rammeverk slik at vi kan bruke tilfeldige tallgivere levert av GameplayKit.
importer GameplayKit
Deretter legger du til følgende metode for MainScene
klasse:
func spawnObstacle (timer: NSTimer) hvis player.hidden timer.invalidate () return la spriteGenerator = GKShuffledDistribution (lowestValue: 1, highestValue: 2) la hindring = SKSpriteNode (imageNamed: "Hindring \ (spriteGenerator.nextInt ()) ") obstacle.xScale = 0.3 obstacle.yScale = 0.3 la physicsBody = SKPhysicsBody (circleOfRadius: 15) physicsBody.contactTestBitMask = 0x00000001 physicsBody.pinned = true physicsBody.allowsRotation = falsk hindring.physicsBody = physicsBody let center = size.width / 2.0, forskjell = CGFloat (85,0) var x: CGFloat = 0 la laneGenerator = GKShuffledDistribution (lowestValue: 1, highestValue: 3) bytt laneGenerator.nextInt () tilfelle 1: x = senterforskjell saks 2: x = senterhus 3: x = senter + differanse standard: fatalError ("Antall utenfor [1, 3] generert") obstacle.position = CGPoint (x: x, y: (player.position.y + 800)) addChild (hinder)
Denne metoden er påkalt hvert tredje sekund. La oss slå det ned for å se hva som skjer. Hvis gjeldende spillerens knutepunkt er skjult, hvilket er sant når bilen treffer et hinder, annullerer vi timeren og stopper gytehinder.
Vi får et tilfeldig tall mellom 1 og 2, og bruk dette til å lage en sprite node med en av de to hindringene sprites tilgjengelig i prosjektet. Vi endrer deretter hindringens skala slik at de er små nok til at bilen skal manøvrere rundt.
Deretter oppretter vi en fysikk kropp for dette nye hinderet med en sirkel med en radius av 15 og en kontaktmaske av 0x00000001. Vi setter låste
til ekte
og allowsRotation
til falsk
slik at hindringen forblir på plass og ikke beveger seg. Fysikklegemet er da tilordnet hindringen.
Vi genererer et annet tilfeldig tall mellom 1 og 3 for å avgjøre hvilken bane hindringen skal plasseres i og gi hindringen sin beregnede posisjon, legger den til scenen.
Legg merke til at den horisontale forskjellen, 85, brukt i spawnObstacle (_ :)
er forskjellig fra den som brukes når du flytter bilen, 70. Vi gjør dette for å gi litt mer plass til bilen å bevege seg mellom hindringer.
Med hindringens gytlogikk på plass, kan vi legge til følgende kode til slutten av didMoveToView (_ :)
metode.
overstyr func didMoveToView (visning: SKView) ... la timer = NSTimer (timeInterval: 3.0, mål: selvvalg: #selector (spawnInObstacle (_ :)), brukerInfo: null, gjentakelser: sant) NSRunLoop.mainRunLoop (). addTimer (timer, forMode: NSRunLoopCommonModes) la kamera = SKCameraNode () self.camera = kamera kamera.position = CGPoint (x: senter, y: player.position.y + 200) la moveForward = SKAction.moveBy (CGVectorMake (0, 100 ), varighet: 1.0) camera.runAction (SKAction.repeatActionForever (moveForward)) addChild (kamera) player.xScale = 0.4; player.yScale = 0.4 // Gjør bil mindre for å passe bedre mellom hindringer
Vi lager en timer for å utføre spawnObstacle (_ :)
hvert tredje sekund og legg det til hovedløpsløyfen. Vi lager også en SKCameraNode
å fungere som kameraet for scenen og tildele det til kamera
eiendom av scenen. Dette fører til at scenen blir gjengitt fra denne kamera nodeens synspunkt. Merk at kameraet er sentrert horisontalt og litt over bilen.
Vi legger også til en identisk handling for kameraet slik at den forblir kantet opp med bilen. Vi legger til kameraet som en barnekode på scenen som alle andre vanlige noder. Sist men ikke minst, skaler vi bilen ned, slik at den kan passe mellom hindringene litt bedre.
Den siste delen for kollisjonsdeteksjon er å implementere en av de to SKPhysicsContactDelegate
protokollmetoder. I vårt tilfelle skal vi implementere didBeginContact (_ :)
Metode som vi vil bli varslet så snart bilen har et hinder. Legg til følgende metode for MainScene
klasse.
Func didBeginContact (kontakt: SKPhysicsContact) hvis kontakt.bodyA.node == spiller || contact.bodyB.node == player player.hidden = true player.removeAllActions () kamera? .removeAllActions ()
Du kan se at denne metoden har en SKPhysicsContact
parameteren passert til den. Dette objektet inneholder nøkkelinformasjon om kollisjonen, inkludert retning, impuls og objektene som er involvert.
I denne koden er vi bare bekymret for hvilke noder som er involvert i kollisjonen. Vi sjekker for å se om en av dem var bilen, og hvis det er sant, skjul bilen i scenen og avslutt bevegelsen til bilen og kameraet.
Bygg og kjør appen din og spill spillet ditt. Du vil se at når du kommer inn i et hinder, forsvinner bilen og scenen slutter å bevege seg.
Du bør nå vite hvordan du skal sette opp fysikkorganer for noder i scenen din og bruke disse til å simulere realistisk fysikk. Du bør også være komfortabel med å sette opp kollisjonsdeteksjon i din scene ved å definere en kontaktdelegate og tilordne kontakt-testmasker for noder du forventer å kollidere med hverandre.
I neste veiledning av SpriteKit From Scratch skal vi se på den mer avanserte visuelle funksjonaliteten i SpriteKit, inkludert partikkelsystemer, lys og filtre.
Som alltid, vær sikker på å legge igjen dine kommentarer og tilbakemeldinger i kommentarene nedenfor.