Build en Stage3D skytespillet Up: Eksplosjoner, Parallax, og Kollisjoner
en
Del
44
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 skytespillet Up.Starling partikkel effekter for Stage3D Shooter GamesQuick. Tips: A Simple Score Display for Flash Games
I denne opplæringen serien (del gratis , del Premium) vi skaper en høy ytelse 2D shoot-em-up med den nye maskinvareakselerert Stage3D rendering-motoren. I denne delen skal vi legge eye candy med partikkel-systemer, en parallax effekt, framerate-uavhengig spill sløyfe timere, og dueller.
Endelig resultat Forhåndsvisning
La oss ta en ser på det endelige resultatet vi skal jobbe mot: en maskinvareakselerert shoot-em-up demo som inneholder alt fra deler en og to av denne serien, pluss en effektiv partikkelsystem for masse eye-candy, framerate-uavhengige timere for konsekvent bevegelse, en subtil bakgrunn parallax effekt, muligheten for virksomheter i bane hverandre, og en kollisjon detection system som kan håndtere tonn enheter
Sjekk det ut:.! hver eksplosjon er litt annerledes
< hr>
Innledning:!. Velkommen til nivå tre
La oss fortsette å gjøre en siderullende skytespill inspirert av retro arcade titler som R-Type eller Gradius i Action
I Første del av denne serien, gjennomførte vi en grunnleggende 2D sprite motor som oppnår gode resultater gjennom bruk av Stage3D hardware rendering samt flere optimaliseringer.
I (den andre delen, gjennomførte vi en tittelskjermen, hoved . menyen, lydeffekter og musikk, og en inngang system, slik at spilleren kan kontrollere sin romskip med tastaturet
I denne delen, vi kommer til å legge all eye-candy: en partikkel system, komplett med gnister, flygende vrakrester, sjokkbølger, motorbrann stier og tonnevis av eksplosjoner.
I tidligere versjoner, spillet vårt var framerate-låst og kjørte saktere på gamle datamaskiner. For å sikre de samme timings for alt uansett hva framerate, vi kommer til å endre alle bevegelse og animasjon simuleringsenheter å gjøre rede for det nøyaktige antall millisekunder som har gått siden forrige bilde. Denne måten, om du kjører på 60fps på en moderne gaming rigg eller din bestemor gamle netbook, vil spillopplevelsen i seg selv være identiske.
Til slutt, vi kommer til å programmere dueller, som er nødvendig i nesten noen spill du kan tenke deg. For å utløse eksplosjoner, og vi må være i stand til å oppdage når en kule har truffet en fiende. Mens vi er i gang, har vi tenkt å kaste inn litt ekstra preg, bare for moro, inkludert et vertikalt parallax effekt på Star bakgrunn og en R-Type inspirert bane "power kule" følgesvenn som sirkler spillerens skip .
Trinn 1: Opprett din eksisterende prosjekt
Hvis du ikke allerede har det, må du huske å laste ned kildekoden fra del to. Åpne prosjektfilen i FlashDevelop og gjør deg klar til å oppgradere spillet ditt!
Denne kildekoden vil fungere i noen annen AS3 kompilator, fra CS6 til Flash Builder. Hvis du bruker FB, sørg for å inkludere "-default-frame-rate 60" i kompilatoren alternativer for å sikre at du får best mulig ytelse
Trinn 2:.
Vi kommer til å dra nytte av de godt optimalisert innvendige av din enhet leder klasse fra forrige gang ved å legge en enkel partikkel system til det som fortsatt bruker alle de samme grunnleggende enhet og spritesheet funksjonalitet.
På denne måten er vi fortsatt gjengi hele spillets sprites (skip, kuler og alle) i en enkelt geometri batch hjelp av en enkelt tekstur. Derfor vil mye av simuleringen av partikler behandles på samme måte som i øyeblikket håndterer bevegelsen av fiender. Viktigst, har vi tenkt å holde antall uavgjort samtaler til et minimum ved å sette inn partikler i vår eksisterende sprite batch.
knyttneve ting vi trenger å gjøre er å definere noen interessante effekter. Vi kommer til å ha det litt gøy og lage noen kule utseende effekter som en ekspanderende ring av blåaktig energi (en "Shockwave"), en haug med forskjellige ildkuler som spinner og forsvinne, noen raskt bevegelige gnister som holder seg fin og lyse og noen metalliske romskip skrog rusk.
Opprett en ny fil i prosjekt kalt GameParticles.as og gjennomføre de grunnleggende partikkel og eksplosjon hjelpefunksjoner.
//Stage3D Shoot-em-up Tutorial Del 3 //av Christer Kaitila - www.mcfunkypants.com//GameParticles.as//Et enkelt partikkel system klassen som //brukes av EntityManager for eksplosjoner, etc.package {import flash.geom.Point; public class GameParticles {offentlig Var allParticles. Vector < Entity >; offentlig Var gfx: EntityManager; offentlig funksjon GameParticles (entityMan: EntityManager). {allParticles = new Vector < Entity > (); gfx = entityMan; } //En kul eksplosjon effekt med en stor ildkule, //en blå rask shockwave, mindre utbrudd av brann, //en haug med små gnister og biter av skroget rusk offentlig funksjon addExplosion (Pos: Point): void {addShockwave ( pos); addDebris (pos, 6,12); addFireball (pos); addBursts (pos, 10,20); addSparks (pos, 8,16); }
I koden ovenfor, har vi opprettet en ny klasse som krever en referanse til vår eksisterende EntityManager. I klassen konstruktør, initial vi en liste over alle kjente partikler, som kan være nyttig i en senere tutorial for å lagre måtte iterere gjennom alle kjente enheter hvis alt vi ønsker er partiklene.
addExplosion () -funksjonen vil bli kalt inn som svar på et dueller mellom en kule og en fiende under spilling. Det vil gyte en shockwave, litt rusk, en enorm ildkule, noen mindre spinnng baller av brann og en haug med flygende gnister. La oss definere disse ulike effekter neste - men før vi kan, vi trenger en generisk partikkel skapelse funksjon
Trinn 3:. Definer en Basic Partikkel
Fortsett å legge til GameParticles.as av implementere initialisering funksjon for en generisk partikkel. Den vil bruke vår enhet manager for å gyte (eller respawn fra listen over inaktive enheter) en sprite med noen passende egenskaper.
Noen av standardverdiene kan ikke settes inn i funksjonen erklæringen i seg selv, siden de vil ta nytte av noen tilfeldigheter, så vi bare bruke NaN ("ikke et tall") som tilleggsfunksjon parameter mislighold og kjøre noen kode hvis ingen verdi ble definert når denne funksjonen blir kjørt. På denne måten trenger vi ikke å spesifisere alt om en spesiell partikkel dersom mislighold vil gjøre. Hvis vi brukte null som standard, da vi ikke kan tvinge null å være den faktiske verdien som brukes
offentlig funksjon addParticle (spr. Uint, //sprite ID x: int, y: int, //starter plassering startScale : Number = 0,01, //innledende skala spdX: Antall = 0, //horisontal hastighet i px /sek SPDY: Antall = 0, //vertikal hastighet i px /sek startAlpha: Number = 1, //innledende gjennomsiktighet (1 = ugjennomsiktig) råte: Number = NaN, //starter rotasjon i grader /sek rotSpd: Number = NaN, //rotasjonshastighet i grader /sek fadeSpd: Number = NaN, //fade inn /ut hastighet per sekund zoomSpd: Number = NaN //vekst hastighet per sekund): Entity {//Defaults fortelle oss til å random noen egenskaper //Hvorfor NaN? Kan ikke sette fastRandom () inne i en funksjon erklæring om (isNaN (rot)) rot = gfx.fastRandom () * 360; if (isNaN (rotSpd)) rotSpd = gfx.fastRandom () * 360-180; if (isNaN (fadeSpd)) fadeSpd = -1 * (gfx.fastRandom () * 1 + 1); if (isNaN (zoomSpd)) zoomSpd = gfx.fastRandom () * 2 + 1; Var anEntity: Entity; anEntity = gfx.respawn (spr); anEntity.sprite.position.x = x; anEntity.sprite.position.y = y; anEntity.speedX = spdX; anEntity.speedY = SPDY; anEntity.sprite.rotation = råte * gfx.DEGREES_TO_RADIANS; anEntity.rotationSpeed = rotSpd * gfx.DEGREES_TO_RADIANS; anEntity.collidemode = 0; anEntity.fadeAnim = fadeSpd; anEntity.zoomAnim = zoomSpd; anEntity.sprite.scaleX = startScale; anEntity.sprite.scaleY = startScale; anEntity.sprite.alpha = startAlpha; hvis allParticles.push (anEntity) (anEntity.recycled!); returnere anEntity; }
Trinn 4: Eye Candy
Det siste trinnet i opprettelsen av vår awesome nye partikkel system klassen er å skape funksjonene for ulike spesialeffekter som brukes av våre eksplosjoner i spillet som er oppført! ovenfor
//én stor spinnende ildkule offentlig funksjon addFireball (pos: Point):. void {addParticle (gfx.spritenumFireball, pos.x, pos.y, 0,01, 0, 0, 1, NaN, NaN, NaN, 4); } //En shockwave ring som ekspanderer raskt offentlig funksjon addShockwave (pos: Point): void {addParticle (gfx.spritenumShockwave, pos.x, pos.y, 0,01, 0, 0, 1, NaN, NaN, -3, 20 ); } //Flere små ildkuler som beveger seg og spinner offentlig funksjon addBursts (pos: Point, mincount: uint, MaxCount: uint): void {var nextparticle: int = 0; Var numparticles: int = gfx.fastRandom () * mincount + (MaxCount-mincount); for (nextparticle = 0; nextparticle < numparticles; nextparticle ++) {addParticle (gfx.spritenumFireburst, pos.x + gfx.fastRandom () * 16 - 8, pos.y + + gfx.fastRandom () * 16 - 8, 0,02 , gfx.fastRandom () * 200-100, gfx.fastRandom () * 200-100, 0,75); }} //Flere små lyse glødende gnister som beveger seg raskt offentlig funksjon addSparks (pos: Point, mincount: UINT, MaxCount: uint): void {var nextparticle: int = 0; Var numparticles: int = gfx.fastRandom () * mincount + (MaxCount-mincount); for (nextparticle = 0; nextparticle < numparticles; nextparticle ++) {//små gnister som holder seg sterkt, men får mindre addParticle (gfx.spritenumSpark, pos.x, pos.y, 1, gfx.fastRandom () * 320-160, gfx.fastRandom () * 320-160, 1, NaN, NaN, 0, -1,5); }} //Små biter av ødelagt romskip rusk, bevegelige i gjennomsnitt litt fremover offentlig funksjon addDebris (pos: Point, mincount: uint, MaxCount: uint): void {var nextparticle: int = 0; Var numparticles: int = gfx.fastRandom () * mincount + (MaxCount-mincount); for (nextparticle = 0; nextparticle < numparticles; nextparticle ++) {addParticle (gfx.spritenumDebris, pos.x, pos.y, 1, gfx.fastRandom () * 180-120, gfx.fastRandom () * 180-90, 1, NaN, NaN, -1, 0); }}} //End class} //end pakke
Det er det for vår forenklede partikkel system. Som du kan se, vi bare definere atferd av hver type visuell effekt i denne klassen: arbeidet med å animere hver partikkel er gjort samtidig som animere alle andre enheter, av vår enhet leder klassen som vi vil oppgradere neste. Men først må vi legge en haug av nye boliger i vår grunnleggende enhet klasse for å støtte disse nye atferd
Trinn 5:. Oppgrader Entity Class
Vi må legge til noen nye egenskaper til vår grunnleggende enhet klasse. Siden vi skal lage spillerens skipet ut en jevn strøm av ild fra motorene, for eksempel, vil vi være i stand til å lagre denne nye informasjonen for hver enhet. I tillegg har noen nye egenskaper som gjelder for partikkel simulering og dueller må defineres her. Åpne din eksisterende Entity.as og gjøre noen endringer som følger
//Stage3D Shoot-em-up Tutorial Part 3 //by Christer Kaitila -. Www.mcfunkypants.com//Entity.as//The Entity klassen vil til slutt holde alle spillspesifikke foretakets statistikk //for romskip, kuler og effekter i spillet vårt. For nå //det rett og slett har en referanse til en GPU sprite og noen få demo egenskaper .//Det er der du vil legge poeng, våpen, evne score, etc.package {import flash.geom.Point; import flash.geom.Rectangle; public class Entity {private Var _speedX: Number; private Var _speedY: Number; private Var _sprite: LiteSprite; offentlig Var aktiv: Boolean = true; //Hvis dette er satt, blir tilpasset atferd drevet offentlig Var aiFunction: Function; //Dueller offentlig Var isBullet: Boolean = false; //Bare disse sjekk kollisjoner offentlig Var leavesTrail: Boolean = false; //Skaper partikler som den beveger seg offentlig Var collidemode: uint = 0; //0 = ingen, 1 = sfære, 2 = boks, etc. offentlig Var collideradius: uint = 32; //Brukt for sfære kollisjon //boks kollisjonen er ikke implementert (ennå) offentlig Var collidebox: rektangel = new rektangel (-16, -16, 32, 32); offentlige Var collidepoints: uint = 25; //Skår tjent hvis ødelagt offentlig Var rørende: Entity; //Hva foretaket bare treffer oss? offentlig Var eier: Entity; //Så dine egne kuler ikke treffer deg offentlig Var Orbiting: Entity; //Enheter kan bane (sirkel) andre offentlige Var orbitingDistance: Number; //Hvor langt i px fra bane sentrum //brukt for partikkel animasjon (i enheter per sekund) offentlig Var fadeAnim: Antall = 0; offentlig Var zoomAnim: Antall = 0; offentlig Var rotationSpeed: Antall = 0; //Brukes til å markere hvorvidt dette foretaket ble //nyopprettet eller gjenbrukt fra en inaktiv ett offentlig Var resirkulert: Boolean = false; offentlig funksjon Entity (gs: LiteSprite = null) {_sprite = gs; _speedX = 0.0; _speedY = 0.0; } Offentlig funksjon die (): void {//tillate denne enheten som skal gjenbrukes av entitymanager aktiv = false; //Hoppe all tegning og oppdatere sprite.visible = false; //Null noen ting som kan påvirke fremtidige reuses: leavesTrail = false; isBullet = false; rørende = null; Eieren = null; collidemode = 0; } Offentlig funksjon får speedX (): Antall {return _speedX; } Offentlig funksjon satt speedX (sx: Number): void {_speedX = sx; } Offentlig funksjon får rask (): Antall {return _speedY; } Offentlig funksjon satt Speedy (sy: Number): void {_speedY = sy; } Offentlig funksjon får sprite (): LiteSprite {return _sprite; } Offentlig funksjon satt sprite (gs: LiteSprite): void {_sprite = gs; }
Som du kan se, er mye av inits er de samme som i forrige tutorial. Når et foretak "dør" (det vil si, er usynliggjort og tilgjengelig for gjenbruk av vår optimalisert enhet gjenbruk pool) vi slå av noen av disse nye verdiene slik at neste foretaket å gjenbruke denne sprite tar ikke på uønsket atferd
Trinn 6:. Implementere Collision Detection
Dette er den viktigste delen av denne opplæringen. Vi kommer til å ta vår tech demo fra kun grafikk demonstraton til noe som føles som en faktisk spillet ved å implementere vår dueller rutine.
For å holde ting enkelt (og raskt) for nå er vi ikke kommer til å implementere markerings-box kollisjon eller boks-til-sfæren eller ray kollisjoner, som ofte brukes i komplekse fysikk motorer. Vi kommer til å fokusere på akkurat hva som trengs av spillet vårt, som er en enkel måte å oppdage om noe er "nær nok" til noe annet for å utløse en kollisjon (og resulterende eksplosjonen).
Sphere dueller sjekker bare for å se om en sirkel er innvendig radius av en annen. På denne måten kan vi gi ulike enheter en "radius" størrelse og sjekke hvor langt deres centerpoints er å finne ut om disse to kretsene er overlappende. For å gjøre spillet vårt løpe enda raskere, er vi bare kommer til å gjøre dette regnestykket dersom begge enhetene er satt til å bli kolliderer-stand.
Som en ytterligere optimalisering, i stedet for å bruke den innebygde Point.distance funksjon, vi kommer til å gjøre det trigonometri matematikk manuelt, siden dette har vært vist i benchmarks å kjøre cirka seks ganger raskere. Det ser ut som mer kode, men alt vi egentlig gjør er Pythagoras teorem uten kvadratrøtter.
Ved å unngå plager med "riktig" avstand og i stedet sammenligne "squared" avstander med bare multiplikasjon, vi faktisk er sjekke avstanden til kraften i to. Ingenting av dette betyr noe, men. Sluttresultatet er en veldig rask og enkel måte å sjekke for å se om to sirkler overlapper som ikke trenger å bruke sin, cos, divisjoner, power-av eller kvadratrot beregninger. Jovial, men effektiv
//brukt for kollisjon tilbakeringing utført i GameActorpool offentlig funksjon kolliderer (checkme: Entity): Entity {if (collidemode == 0) {return null; } Else if (collidemode == 1) //sfære {if (isCollidingSphere (checkme)) avkastning checkme; annet avkastning null; }} //Enkel sfære til sfære kollisjon offentlig funksjon isCollidingSphere (checkme: Entity): Boolean {//aldri kollidere med deg selv om (denne == checkme) return false; //Bare sjekke om disse figurene er collidable if (collidemode || checkme.collidemode!) Return false; //Ikke sjekke dine egne kuler if (checkme.owner == denne) return false; //Ikke sjekke ting på samme "team" if (checkme.owner == eier) return false; //Sjekker ikke om ingen radius if (collideradius == 0 || checkme.collideradius == 0) return false; //Dette er den enklere måte å gjøre det, men det går veldig sakte //Var dist: Number = Point.distance (sprite.position, checkme.sprite.position); //If (dist < = (collideradius + checkme.collideradius)) //dette ser merkelig, men er 6x raskere enn de ovennevnte //se: http://www.emanueleferonato.com/2010/10/13/as3- geom-point-vs-trigonometri /if (((sprite.position.x - checkme.sprite.position.x) * (sprite.position.x - checkme.sprite.position.x) + (sprite.position.y - checkme.sprite.position.y) * (sprite.position.y - checkme.sprite.position.y)) < = (collideradius + checkme.collideradius) * (collideradius + checkme.collideradius)) {rørende = checkme; //Husker som treffer oss return true; } //Standard: for langt unna //trace (". No kollisjon Dist =" + dist); return false; }} //End class} //end pakke
Tht er det for vår nylig oppgradert Entity.as klasse. Vi har nå enhetene i spillet vårt som lagrer statistikken som trengs for denne opplæringen, og kan beregne kollisjoner
Trinn 7:. Oppgrader Entity manager
Det er mange nye tilskuddene til foretaket leder som legger evnen til å be om dueller, utløse lydeffekter, legge partikler og mye mer. Åpne eksisterende EntityManager.as og gjøre noen endringer som følger. Det er så mange små endringer siden forrige gang at hele filen er oppført her for å unngå forvirring, så vil du kanskje å bare bytte ut hele klassen med denne nye tredje versjonen.
//Stage3D Shoot-em-up Tutorial Del 3 //by Christer Kaitila - www.mcfunkypants.com//EntityManager.as//Foretaket leder håndterer en liste over alle kjente spillet enheter .//vil Dette objektet bassenget åpner for gjenbruk (restartet) av //sprites: for eksempel, når fiendtlige skip blir ødelagt, //de vil bli re-gytt ved behov som en optimalisering //som øker fps og reduserer ram use.package {import flash.display.Bitmap; import flash.display3D. *; import flash.geom.Point; import flash.geom.Rectangle; public class EntityManager {//en partikkel system klasse som oppdaterer våre sprites offentlige Var partikler: GameParticles; //Slik at eksplosjoner kan spilles offentlig Var sfx: GameSound; //Sprite ark image offentlig Var spriteSheet: LiteSpriteSheet; privat konst SpritesPerRow: int = 8; privat konst SpritesPerCol: int = 8; [Bygg (kilde = "../eiendeler /sprites.png")] privat Var SourceImage: Klasse; //Den generelle størrelsen på spilleren og fiender privat konst shipScale: Number = 1,5; //Hvor fort spilleren kuler går per sekund offentlig Var bulletSpeed: Nummer = 250; //For framerate-uavhengig timings offentlige Var currentFrameSeconds: Number = 0; //Sprite IDer (indeksere spritesheet) offentlig konst spritenumFireball: uint = 63; offentlig konst spritenumFireburst: uint = 62; offentlig konst spritenumShockwave: uint = 61; offentlig konst spritenumDebris: uint = 60; offentlig konst spritenumSpark: uint = 59; offentlig konst spritenumBullet3: uint = 58; offentlig konst spritenumBullet2: uint = 57; offentlig konst spritenumBullet1: uint = 56; offentlig konst spritenumPlayer: uint = 10; offentlig konst spritenumOrb: uint = 17; //Gjenbrukt for beregning hastighet offentlig const DEGREES_TO_RADIANS: Number = Math.PI /180; offentlig konst RADIANS_TO_DEGREES: Antall = 180 /Math.PI; //Spilleren enhet - en spesiell sak offentlig Var thePlayer: Entity; //En "power kule" som går i bane rundt spilleren offentlig Var theOrb: Entity; //En gjenbrukbar pool av enheter //denne inneholder alle kjente Entity //inkludert innholdet av listene under offentlig Var entityPool. Vector < Entity >; //Disse bassengene inneholder bare visse typer //av foretaket som en optimalisering for mindre sløyfer offentlige Var allBullets. Vector < Entity >; offentlige Var allEnemies. Vector < Entity >; //Alle polygoner som utgjør scenen offentlig Var batch: LiteSpriteBatch; //For statistikk offentlig Var numCreated: int = 0; offentlig Var numReused: int = 0; offentlig Var maxX: int; offentlig Var minX: int; offentlig Var maxy: int; offentlig Var miny: int;
I koden ovenfor, er vi definerer et stort antall klassevariabler, hvorav mange er nye for denne opplæringen. Av notatet er de som gjelder for timing og fart. I stedet for de relative hastigheter på hver flytte skipet blir knyttet direkte til framerate, vi vil at spillet skal kjøre på samme hastighet uansett hva slags maskin spilleren bruker.
Ved å holde styr på medgått tid siden forrige ramme, kan vi multiplisere ulike "speed per sekund" konstanter med antall millisekunder at dagens ramme tok for å oppnå jevn bevegelse selv om FPS svinger
Trinn 8:. Upgrade den Spritesheet
I koden ovenfor vi lagrer konstante verdier for posisjonene til ulike sprites i vår spritesheet image. Vi har lagt til noen nye typer sprite som gjelder for partikler, og har omorganisert spritesheet å sikre at våre randly-gyte fiender bare komme fra de første radene. Disse endringene har neccessitated noen mindre endringer i vår spritesheet:..
Høyreklikk for å laste ned
Som du kan se, har vi nå noen ekstra sprites for eksplosjoner, sjokkbølger, gnister og rusk
Trinn 9: Oppgrader inits
Fortsetter med EntityManager.as, oppgradere de grunnleggende varme rutiner for å lage lister for hver type enhet. Hver av disse listene holder styr på en bestemt type enhet /sprite. Vi kan bruke disse listene til å forbedre ytelsen når vi trenger å sløyfe gjennom alle bare en bestemt type enhet, noe som sparer tid det ville ta å se gjennom alle kjente enheter av noe slag. Partiklene, men kommer til å bli lagret i sin egen klasse forekomst ved hjelp av ny GameParticles klassen vi implementert over
offentlig funksjon EntityManager (vis: rektangel).. {EntityPool = new Vector < Entity > (); allBullets = new Vector. < Entity > (); allEnemies = new Vector. < Entity > (); partikler = nye GameParticles (denne); setPosition (vis); } Offentlig funksjon setPosition (vis: rektangel): void {//tillate flytting fullt offscreen før //automatisk blir hentet (og gjenbrukes) maxX = view.width + 64; minX = view.x - 64; maxy = view.height + 64; miny = view.y - 64; } Offentlig funksjon createBatch (context3D: Context3D): LiteSpriteBatch {var sourceBitmap: Bitmap = new SourceImage (); //Oppretter et spritesheet med 8x8 (64) sprites på det spriteSheet = new LiteSpriteSheet (sourceBitmap.bitmapData, SpritesPerRow, SpritesPerCol); //Opprett ny render batch batch = new LiteSpriteBatch (context3D, spriteSheet); returnere batch; } //Søke foretaket bassenget for ubrukte enheter og gjenbruke én //hvis de er alle i bruk, skaper en helt ny en offentlig funksjon respawn (sprID: uint = 0): Entity {var currentEntityCount: int = entityPool.length; Var anEntity: Entity; Var i: int = 0; //Søk etter en inaktiv enhet for (i = 0; i < currentEntityCount; i ++) {anEntity = entityPool [i]; if (anEntity.active &! & (anEntity.sprite.spriteId == sprID)) {//trace ("Gjenbruk Entity # '+ i); anEntity.active = true; anEntity.sprite.visible = true; anEntity.recycled = true; numReused ++; returnere anEntity; }} //Ingen ble funnet, så vi må lage en ny //trace ("Trenger du å opprette en ny Entity # '+ i); Var sprite: LiteSprite; sprite = batch.createChild (sprID); anEntity = new Entity (sprite); entityPool.push (anEntity); numCreated ++; returnere anEntity; }
Over, vi har også oppgradert setPosition funksjonen for å tillate virksomheter å gå utover noen av de fire kantene av skjermen før du blir respawned, siden det går i alle retninger nå. I forrige ukes tutorial, ble enheter bare ødelagt hvis de flyttet utenfor venstre kant og spratt av de tre andre kantene av skjermen. De createBatch og Respawn funksjonene er tilnærmet uendret siden forrige gang.
For å unngå enheter blir satt inn i de ulike sub-lister vi har gjennomført i vår klasse konstruktør mer enn en gang, legger vi et nytt flagg til foretaket, enEntity .recycled som informerer foretaket leder vidt sprite at den returnerer er helt ny eller ikke. På denne måten er bare en eneste referanse til hver sprite lagret i våre lister
Trinn 10:. Fast Random
Som en ytterligere liten optimalisering, i stedet for å bruke Math.random () om og om igjen i løpet av spillet, skal vi gjennomføre en litt raskere, XOR-basert pseudo-tilfeldighetsfunksjon.
Denne funksjonen har en sekundær fordel, bortsett fra det faktum at det går fire ganger raskere enn den inne -på tilfeldighetsfunksjon. Det kan eventuelt være podet med en konstant verdi som utgangs fastrandomseed for å produsere det samme sett av tilfeldige tall i rekkefølge hver gang.
Dette kan være nyttig i fremtidige versjoner av spillet for lagring eller for repriser Savegames. For nå, men den eneste grunnen til at vi gjør ting på denne måten er å eke ut en liten bit mer ytelse.
//Denne XOR basert fort tilfeldig nummer generator kjører 4x raskere //enn Math.random () og også returnerer et tall fra 0 til 1 //se http://www.calypso88.com/?cat=7 privat konst FASTRANDOMTOFLOAT: Number = 1 /uint.MAX_VALUE; private Var fastrandomseed: uint = Math.random () * uint.MAX_VALUE; offentlig funksjon fastRandom (): Antall {fastrandomseed ^ = (fastrandomseed < < 21); fastrandomseed ^ = (fastrandomseed > > > 35); fastrandomseed ^ = (fastrandomseed < < 4); avkastning (fastrandomseed * FASTRANDOMTOFLOAT); }
Trinn 11: Oppgrader Player
Fortsetter med EntityManager.as, gjennomføre følgende mindre oppgraderinger til spilleren inits. Spesielt skal vi sette boolsk flagg thePlayer.leavesTrail å true, slik at spillerens motorer avgir en jevn strøm av ildkuler som raskt krympe og forsvinne. Dette vil gi en fin effekt.
I tillegg bare for moro skyld la oss gjennomføre en "power kule" som går i bane rundt spillerens skipet. Denne "følgesvenn" er noe som er sterkt inspirert av retro skyttere som R-Type og vil gi spillet vårt litt mer preg. Den "kule", som vi kaller det, vil spinne rundt spilleren, sender ut en mindre sti av sine egne, og vil være i stand til å ødelegge innkommende fiender.
I fremtidige versjoner av spillet vårt, det kan være interessant å lage "kule dreper" gi spilleren flere poeng enn de som oppnås ved å skyte kuler. En slags "dyktighet shot", så å si. Du kan også gjennomføre en spesiell Achievement Award for et helt nivå gjennomført uten noen gang å avfyre et skudd - ved hjelp av kulen som eneste middel for å forsvare deg selv
//dette vesenet PLAYER offentlig funksjon addPlayer. (PlayerController: Function): Entity {thePlayer = respawn (spritenumPlayer); thePlayer.sprite.position.x = 32; thePlayer.sprite.position.y = maxy /2; thePlayer.sprite.rotation = 180 * DEGREES_TO_RADIANS; thePlayer.sprite.scaleX = thePlayer.sprite.scaleY = shipScale; thePlayer.speedX = 0; thePlayer.speedY = 0; thePlayer.active = true; thePlayer.aiFunction = playerController; thePlayer.leavesTrail = true; //Bare for moro, gyte en bane "power kule" theOrb = respawn (spritenumOrb); theOrb.rotationSpeed = 720 * DEGREES_TO_RADIANS; theOrb.leavesTrail = true; theOrb.collidemode = 1; theOrb.collideradius = 12; theOrb.isBullet = true; theOrb.owner = thePlayer; theOrb.orbiting = thePlayer; theOrb.orbitingDistance = 180; returnere thePlayer; }
Trinn 12: Kuler og Enemies
De shootBullet og addEntity funksjoner fra forrige gang forbli nesten den samme, men er tatt med her for å gjøre livet ditt enklere. Merk at vi nå bruker de nye enhetens egenskaper for kollisjoner, og de tilfeldige enheter blir nå satt til riktig rotasjons å stå overfor den retningen de flyr.
//Skyte en kule (fra spilleren for nå) offentlig funksjon shootBullet (powa: uint = 1): Entity {var anEntity: Entity; //Tre mulige kuler, progressivt større if (powa == 1) anEntity = respawn (spritenumBullet1); else if (powa == 2) anEntity = respawn (spritenumBullet2); annet anEntity = respawn (spritenumBullet3); anEntity.sprite.position.x = thePlayer.sprite.position.x + 8; anEntity.sprite.position.y = thePlayer.sprite.position.y + 2; anEntity.sprite.rotation = 180 * DEGREES_TO_RADIANS; anEntity.sprite.scaleX = anEntity.sprite.scaleY = 1; anEntity.speedX = bulletSpeed; anEntity.speedY = 0; anEntity.owner = thePlayer; anEntity.collideradius = 10; anEntity.collidemode = 1; anEntity.isBullet = true; hvis allBullets.push (anEntity) (anEntity.recycled!); returnere anEntity; } //For denne testen, lage tilfeldige enheter som flytter //fra høyre til venstre med tilfeldige hastigheter og skalerer offentlig funksjon addEntity (): void {var anEntity: Entity; Var randomSpriteID: uint = Math.floor (fastRandom () * 55); //Prøver å gjenbruke en inaktiv enhet (eller lage en ny) anEntity = respawn (randomSpriteID); //Gi den en ny posisjon og hastighet anEntity.sprite.position.x = maxX; anEntity.sprite.position.y = fastRandom () * maxy; anEntity.speedX = 15 * ((-1 * fastRandom () * 10) - 2); anEntity.speedY = 15 * ((fastRandom () * 5) - 2,5); anEntity.sprite.scaleX = shipScale; anEntity.sprite.scaleY = shipScale; anEntity.sprite.rotation = pointAtRad (anEntity.speedX, anEntity.speedY) - (90 * DEGREES_TO_RADIANS); anEntity.collidemode = 1; anEntity.collideradius = 16; hvis allEnemies.push (anEntity) (anEntity.recycled!); }
Trinn 13: Handy Math Utilities
Deretter må vi gjennomføre noen av de hjelpe matematiske funksjoner som brukes av gyte rutiner ovenfor. Dette er veldig praktisk og kan gjenbrukes i alle slags måter i fremtiden. Fordi Flash (og de fleste spillmotorer, i hvert fall i de lave nivå rutiner) lagre objektets rotasjon bruker radianer (i stedet for grader) vi har definert en konstant over at hastigheter opp disse beregningene.
//Returnerer vinkelen i radianer av to punkter offentlig funksjon pointAngle (point1: Point, poeng2: Point): Antall {var dx: Number = point2.x - point1.x; Var dy: Number = point2.y - point1.y; returnere -Math.atan2 (dx, dy); gå i stykker; gå i stykker; gå i stykker; gå i stykker; gå i stykker; gå i stykker; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; removeEventListener (Event.ADDED_TO_STAGE, init);