En introduksjon til GameplayKit: Part 3

An Introduksjon til GameplayKit: Del 3
18
Del
5
Del
Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av
Dette innlegget er en del av en serie som heter An Introduction to GameplayKit.An Introduksjon til GameplayKit. Del 2

Dette er den tredje delen av An Introduction to GameplayKit. Hvis du ennå ikke har gått gjennom den første delen og den andre delen, så anbefaler jeg å lese disse tutorials først før du fortsetter med denne.

Innledning

I denne tredje og siste tutorial, jeg kommer til å lære deg om to flere funksjoner du kan bruke i dine egne spill:

tilfeldig verdi generatorer

regelsystemer

I denne opplæringen, vil vi først bruke en av GameplayKit er tilfeldig verdi generatorer for å optimalisere vår første fiende gyting algoritme. Vi vil deretter gjennomføre en grunnleggende regel system i kombinasjon med en annen tilfeldig fordeling til å håndtere restartet oppførsel av fiender.

For denne opplæringen, kan du bruke ditt eksemplar av det ferdige prosjektet fra andre tutorial eller laste ned en ny kopi av kildekoden fra GitHub.

1. Random Verdi Generatorer

Tilfeldige verdier kan genereres i GameplayKit ved hjelp av noen klasse som samsvarer med GKRandom protokollen. GameplayKit gir fem klasser som samsvarer med denne protokollen. Disse klassene inneholder tre tilfeldige kilder og to tilfeldige utdelinger. Den største forskjellen mellom tilfeldige kilder og tilfeldige utdelinger er at distribusjoner bruker en tilfeldig kilde til å produsere verdier innenfor et bestemt område, og kan manipulere tilfeldig verdi utgang på ulike andre måter.

De nevnte klasser er levert av rammen så at du kan finne den rette balansen mellom ytelse og tilfeldig for spillet ditt. Noen tilfeldig verdi generer algoritmer er mer komplekse enn andre og dermed påvirker resultatene.

For eksempel, hvis du trenger et tilfeldig tall genereres hver ramme (seksti ganger per sekund), så det ville være best å bruke en av de raskere algoritmer. I kontrast, hvis du bare sjelden genererer en tilfeldig verdi, kan du bruke en mer kompleks algoritme for å gi bedre resultater.

De tre tilfeldige kilde klasser tilbys av GameplayKit rammeverket er GKARC4RandomSource, GKLinearCongruentialRandomSource, og GKMersenneTwisterRandomSource .

GKARC4RandomSource

Denne klassen bruker ARC4 algoritme og er egnet for de fleste formål. Denne algoritmen virker ved å frembringe en rekke tilfeldige tall basert på et frø. Du kan initialisere en GKARC4RandomSource med en bestemt frø hvis du trenger å replikere tilfeldig oppførsel fra en annen del av spillet. En eksisterende kilde sæd kan hentes fra sine frø beskyttet eiendom.

GKLinearCongruentialRandomSource

Dette tilfeldig kilde klassen bruker den grunnleggende lineær kongruentrekursjonssekvens generator algoritme. Denne algoritmen er mer effektiv og gir bedre resultater enn den ARC4 algoritmen, men det frembringer også verdier som er mindre tilfeldig. Du kan hente en GKLinearCongruentialRandomSource objektets frø og lage en ny kilde med det på samme måte som en GKARC4RandomSource objekt.

GKMersenneTwisterRandomSource

Denne klassen bruker Mersenne Twister algoritme og genererer mest tilfeldige resultater, men det er også den minst effektive. Akkurat som de andre to tilfeldige kilde klasser, kan du hente en GKMersenneTwisterRandomSource objektets frø og bruke den til å lage en ny kilde.

De to tilfeldige distribusjons klasser i GameplayKit er GKGaussianDistribution og GKShuffledDistribution.
< h3> GKGaussianDistribution

sikrer Denne fordelingen type som de genererte tilfeldige verdier følge en gaussfordeling-også kjent som en normalfordeling. Dette betyr at flertallet av de genererte verdiene vil falle i midten av intervallet du angir.

For eksempel, hvis du setter opp en GKGaussianDistribution objekt med en minimumsverdi på 1, en maksimal verdi på 10, og standardavvik på 1, vil om lag 69% av resultatene være enten 4, 5 eller 6. Jeg vil forklare denne fordelingen i mer detalj når vi legger en til vårt spill senere i denne opplæringen.

GKShuffledDistribution

Denne klassen kan brukes til å sørge for at tilfeldige verdier er jevnt fordelt over det angitte området. For eksempel, hvis du generere verdier mellom 1 og 10, og en 4 genereres, en annen 4 vil ikke bli generert før alle de andre tall mellom 1 og 10 har også blitt generert.

Det er nå på tide å sette alt dette i praksis. Vi kommer til å legge to tilfeldige utdelinger til spillet vårt. Åpne prosjektet i Xcode og gå til GameScene.swift. Den første tilfeldig fordeling vil vi legge til en GKGaussianDistribution. Senere vil vi også legge til en GKShuffledDistribution. . Legge til følgende to eiendommer til GameScene klassen
Var initialSpawnDistribution = GKGaussianDistribution (randomSource: GKARC4RandomSource (), lowestValue: 0, highestValue: 2) Var respawnDistribution = GKShuffledDistribution (randomSource: GKARC4RandomSource (), lowestValue: 0, highestValue: 2 )

I denne tekstutdrag, skaper vi to fordelinger med en minimumsverdi på 0 og en maksimal verdi av 2. For GKGaussianDistribution, midlere og avvik blir automatisk beregnet etter følgende ligninger:

mener = (maksimum - minimum) /2

avvik = (maksimum - minimum) /6

Gjennomsnittet av en Gaussisk fordeling er midtpunktet og avviket brukes til å beregne hvor mange prosent av verdiene bør være innenfor et visst område fra middelverdien. Prosentandelen av verdier innenfor en viss rekkevidde er:

68,27% innen ett avvik fra gjennomsnittet

95% innen 2 avvik fra gjennomsnittet

100% innen 3 avvik fra gjennomsnittet

Dette betyr at ca 69% av de genererte verdiene skal være lik 1. Dette vil resultere i flere røde prikker i forhold til grønne og gule prikker. For å gjøre dette arbeidet, må vi oppdatere initialSpawn metoden

I for loop, erstatte følgende linje:.
La respawnFactor = arc4random ()% 3 //Vil produsere en verdi mellom 0 og 2 (inkluderende)

med følgende:
la respawnFactor = self.initialSpawnDistribution.nextInt ()

nextInt metoden kan kalles på et objekt som er i samsvar med GKRandom protokollen og vil returnere en tilfeldig verdi basert på kilde og eventuelt fordeling som du bruker.

Bygg og kjøre programmet ditt, og flytte rundt på kartet. Du skal se mye mer røde prikker i forhold til både grønne og gule prikker.

Den andre tilfeldig fordeling som vi skal bruke i spillet vil komme inn i bildet når du håndterer regelen systembasert respawn atferd.

2. Regel Systems

GameplayKit regel systemer brukes til å bedre organisere betinget logikk i spillet, og også innføre fuzzy logikk. Ved å innføre fuzzy logikk, kan du lage enheter i spillet ditt ta avgjørelser basert på et utvalg av ulike regler og variabler som spiller helse, nåværende fiende teller, og avstanden til fienden. Dette kan være svært fordelaktig i forhold til enkel hvis og slå uttalelser

Regel systemer, representert ved GKRuleSystem klasse, har tre sentrale deler til dem:.

  • Agenda. Dette er et sett med regler som har blitt lagt til regelen system. Som standard er disse reglene evalueres i den rekkefølgen de er lagt til regelen system. Du kan endre salience eiendom av noen regel for å angi når du vil at den skal evalueres.
  • State Information. Staten tilhører en GKRuleSystem objekt er en ordbok, som du kan legge til data til, inkludert egendefinerte objekttyper. Denne informasjonen kan deretter brukes av reglene i regelsystemet når du returnerer resultatet.
  • Fakta. Fakta innenfor en regel system representerer konklusjonene fra evalueringen av reglene. Et faktum kan også være representert ved en gjenstand type innenfor spillet ditt. Hver faktum har også en tilsvarende medlemskap karakter, som er en verdi mellom 0,0 og 1,0. Dette medlemskapet klasse representerer inkludering eller tilstedeværelse av det faktum innenfor regelen system

    Regler seg selv, representert ved GKRule klasse, har to hovedkomponenter:.

  • Predicate. Denne delen av regelen returnerer en boolsk verdi, noe som indikerer hvorvidt kravene i regelen er oppfylt. En regel er predikat kan lages ved hjelp av en NSPredicate objekt eller, som vi vil gjøre i denne opplæringen, en blokk med kode.
  • Handling. Når regelen er predikat returnerer sant, er det handling utført. Denne handlingen er en kodeblokk hvor du kan utføre noen logikk hvis regel krav er oppfylt. Det er der du vanligvis hevde (legg) eller trekke (fjern) fakta innenfor den overordnede regel system.

    La oss se hvordan alt dette fungerer i praksis. For vår regel system, skal vi lage tre regler som ser på:

    avstanden fra spawn punkt til spilleren. Hvis denne verdien er relativt liten, vil vi gjøre spillet mer sannsynlig å gyte røde fiender.

  • gjeldende node telling av scenen. Hvis dette er for høy, ønsker vi ikke noen flere punkter blir lagt til åstedet.
  • hvorvidt en prikk er allerede til stede på spawn punktet. Hvis det ikke er det, så ønsker vi å fortsette å gyte en prikk her

    Først legger følgende eiendom til GameScene klassen.
    Var ruleSystem = GKRuleSystem ()

    Neste legger du til følgende kode til didMoveToView (_ :) metode:
    la playerDistanceRule = GKRule (blockPredicate: {(system: GKRuleSystem) - > Bool inn hvis la value = system.state ["spawnPoint"] som? NSValue {la punkt = value.CGPointValue () la xDistance = abs (point.x - self.playerNode.position.x) la yDistance = abs (point.y - self.playerNode.position.y) la totaldistanse = sqrt (( xDistance * xDistance) + (yDistance * yDistance)) hvis totaldistanse < = 200 {return true} else {return false}} else {return false}}) {(system: GKRuleSystem) - > Void i system.assertFact ("spawnEnemy")} la nodeCountRule = GKRule (blockPredicate: {(system: GKRuleSystem) - > Bool inn hvis self.children.count < = 50 {return true} else {return false}}) {(system: GKRuleSystem) - > Void i system.assertFact ("shouldSpawn", Karakter: 0,5)} la nodePresentRule = GKRule (blockPredicate: {(system: GKRuleSystem) - > Bool inn hvis la value = system.state ["spawnPoint"] som NSValue der selv? . .nodesAtPoint (value.CGPointValue ()) teller == 0 {return true} else {return false}}) {(system: GKRuleSystem) - > Ugyldig i utleid klasse = system.gradeForFact ("shouldSpawn") system.assertFact ("shouldSpawn", klasse: (klasse + 0,5))} self.ruleSystem.addRulesFromArray ([playerDistanceRule, nodeCountRule, nodePresentRule])

    Med denne koden skaper vi tre GKRule gjenstander og legge dem til regelen system. Reglene hevde en bestemt faktum innenfor sine handlinger blokk. Hvis du ikke oppgir en karakter verdi og bare ringe assertFact (_ :) metode, som vi gjør med playerDistanceRule, er det faktum gitt et standardkarakter på 1,0.

    Du vil merke at for nodeCountRule vi bare hevde at "shouldSpawn" faktisk med karakteren 0,5. Den nodePresentRule hevder så er dette samme faktum og legger på en karakter verdi på 0,5. Dette er gjort slik at når vi sjekker det faktum senere, betyr en karakter verdi på 1,0 som begge regler er oppfylt.

    Du vil også se at både playerDistanceRule og nodePresentRule tilgang til "spawnPoint" verdien av Regelen systemets tilstand ordbok. Vi vil tildele denne verdien før du evaluerer regel system

    Til slutt, finne og erstatte respawn metoden i GameScene klassen med følgende gjennomføringen.
    Func respawn () {la endNode = GKGraphNode2D (punkt: float2 (x: 2048,0, y: 2048,0)) self.graph.connectNodeUsingObstacles (endNode) for punkt i self.spawnPoints {self.ruleSystem.reset () self.ruleSystem.state ["spawnPoint"] = NSValue (CGPoint: punkt) selv .ruleSystem.evaluate () hvis self.ruleSystem.gradeForFact ("shouldSpawn") == 1,0 {var respawnFactor = self.respawnDistribution.nextInt () hvis self.ruleSystem.gradeForFact ("spawnEnemy") == 1,0 {respawnFactor = selvtillit. initialSpawnDistribution.nextInt ()} Var node: SKShapeNode? = Nil slå respawnFactor {case 0: node = PointsNode (circleOfRadius: 25)! Node .physicsBody = SKPhysicsBody (circleOfRadius: 25) node .fillColor = UIColor.greenColor () case 1: node = RedEnemyNode (circleOfRadius: 75) node! .physicsBody = SKPhysicsBody (circleOfRadius: 75)! node .fillColor = UIColor.redColor () case 2: node = YellowEnemyNode (circleOfRadius: 50)! node .physicsBody = SKPhysicsBody (circleOfRadius: 50) node .fillColor = UIColor.yellowColor (! ) standard: break} hvis la enhet = node .valueForKey ("enhet") som? GKEntity, la agenten = node? .valueForKey ("Agent") som? GKAgent2D hvor respawnFactor! = 0 {entity.addComponent (agent) agent.delegate = node som? ContactNode agent.position = float2 (x: Float (point.x), y: Float (point.y)) agents.append (nestleder) la startNode = GKGraphNode2D (punkt: agent.position) self.graph.connectNodeUsingObstacles (startNode) la pathNodes = self.graph.findPathFromNode (startNode, toNode: endNode) som! [GKGraphNode2D] hvis pathNodes.isEmpty {la path = GKPath (graphNodes: pathNodes, radius: 1,0)! La followPath = GKGoal (toFollowPath: bane, maxPredictionTime: 1,0, fremover: true) la stayOnPath = GKGoal (toStayOnPath: bane, maxPredictionTime: 1.0) la atferd = GKBehavior (mål: [followPath, stayOnPath]) agent.behavior = atferd} self.graph.removeNodes ([startNode]) agent.mass = 0.01 agent.maxSpeed ​​= 50 agent.maxAcceleration = tusen} node !. stilling = punktet node! .strokeColor = UIColor.clearColor () node! .physicsBody! .contactTestBitMask = 1 self.addChild (! node)}} self.graph.removeNodes ([endNode])}

    Denne metoden vil bli kalt en gang hvert sekund, og er meget lik den initialSpawn metoden. Det finnes en rekke viktige forskjeller i for loop skjønt.

  • Vi først nullstille regelen systemet ved å kalle sin reset metoden. Dette må gjøres når en regel systemet blir sekvensielt evaluert. Dette fjerner alle hevdet fakta og relatert data for å sikre at ingen informasjon er igjen fra den forrige evalueringen som kan forstyrre den neste.
  • Vi deretter tildele spawn punkt til regelen systemets tilstand ordbok. Vi bruker en NSValue objekt, fordi CGPoint datatypen ikke samsvarer med Swifts AnyObject protokollen og kan ikke overdras til dette NSMutableDictionary eiendommen.
  • Vi evaluerer regelen systemet ved å kalle sin evaluere metoden.
  • Vi deretter hente regelen system medlemskap klasse for "shouldSpawn" faktum. Hvis dette er lik 1, fortsetter vi med restartet punktum.
  • Til slutt, vi sjekke regelen systemets karakter i "spawnEnemy" faktum, og hvis lik 1, bruker normalfordelt tilfeldig generator for å lage vår spawnFactor.

    Resten av respawn metoden er den samme som initialSpawn metoden. Bygge og drive din spillet en siste gang. Selv uten å flytte rundt, vil du se nye prikker gyte når de nødvendige betingelsene er oppfylt.

    Konklusjon

    I denne serien på GameplayKit, har du lært mye. La oss kort oppsummere hva vi har dekket.

  • Enheter og komponenter

    State Machines

    Agents, mål, og Behaviors

    pathfinding

    Tilfeldige Verdi Generatorer

    Rule Systems

    GameplayKit er et viktig tillegg til iOS 9 og OS X El Capitan. Det eliminerer mye av kompleksiteten i spillutvikling. Jeg håper at denne serien har motivert deg til å eksperimentere mer med rammen og oppdage hva det er i stand til.

    Som alltid må du huske å legge inn kommentarer og tilbakemeldinger under.