An Introduksjon til FlashPunk: Opprette et romskip skytespillet Up
en
Del
15
Share
Cyber Monday 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.Create en enkel plass shooter spill i HTML5 Med EaselJS
I den siste opplæringen, vi introduserte FlashPunk og sine evner. Nå er det på tide å bygge et spill med det! Vi vil bygge et top-down, mus-kontrollerte shoot-'em-up, med en tittel skjerm og en game over skjermen. Les videre for å lære mer ...
Endelig resultat Forhåndsvisning
La oss ta en titt på det endelige resultatet vi skal jobbe mot:
Trinn 1: The Player Ship
Som alltid, først må vi en ren prosjekt. Grab den nyeste FlashPunk bygge fra det offisielle nettstedet. Opprett en ny AS3 prosjekt i FlashDevelop og sette FlashPunk kilde i kildemappen av prosjektet. Spillet vil ha følgende mål: 400x500 px
Vi vil begynne spillet vårt ved å legge til et skip - spilleren skipet - på skjermen.. For det, trenger vi en ny verden, kalt spillverden, og et bilde:
Spilleren Skipet vil være en enhet. Opprett en, legge inn bildet i den og sette den på skjermen. Hvis du føler deg fortapt, er under koden for spilleren skipet (hvis du virkelig følelsen tapt, anbefaler jeg å lese den første opplæringen på nytt). Jeg tror at å skape verden vil ikke være et problem for deg
pakke {import net.flashpunk.Entity.; import net.flashpunk.graphics.Image; public class PlayerShip strekker Entity {[Bygg (kilde = '../img/PlayerShipImage.png')] privat konst BILDE: Klasse; offentlig funksjon PlayerShip () {grafisk = new Image (BILDE); graphic.x = -27,5; graphic.y = -30; x = 200; y = 400; }}}
Legg spilleren skipet inn i verden og gjøre den gjeldende verden når FlashPunk motoren starter. Du får følgende:
Trinn 2: Bevegelse
Med spilleren skipet på skjermen, må vi gjøre det flytte. Akkurat som hver shoot-'em-up spill, vil spilleren skipet kunne bevege seg over hele skjermen. Det er en ting igjen å bestemme før koding bevegelsen: vi skal bruke rammebasert bevegelse (grunnen til dette er i neste trinn). Det betyr endring (om nødvendig) super () kaller å FlashPunk motor og IKKE bruker FP.elapsed eiendommen.
Koden for spilleren skipet bevegelsen er under. Bevegelsen er mus-baserte:
private Var _currentDistanceX: Number; private Var _currentDistanceY: Number; privat konst SPEED: int = 3; styre offentlig funksjon oppdateringen (): void {calculateDistances (); if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED) {x = Input.mouseX; y = Input.mouseY; } Else {x + = Math.cos (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED; y + = tak i Math.sin (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED; }} Private funksjons calculateDistances (): void {_currentDistanceX = Input.mouseX - x; _currentDistanceY = Input.mouseY - y; }
Du må importere net.flashpunk.utils.Input i spilleren skipsklasse. Også, ikke glem å aktivere FlashPunk konsoll. Etter kompilering prosjektet, vil du se at spilleren skipet følgende musa:
Trinn 3: Enemies
Tid for å legge til noe morsomt: fiender. Fiender må gyte tilfeldig (basert på bølger) og må ha en kontrollert bevegelse. De har også et annet bilde:
koden for å lage fienden klassen og tilsetning av bildet til det bør ikke være et problem. Det vi trenger å fokusere på er hvordan man skal gjøre fiender følge en sti. Tanken er denne: vi skape en bølge av fiender og sende dem en sti å følge, og da for å gyte. Etter det, vil de være ansvarlig for å vise seg på skjermen og beveger seg langs stien.
Hva er en god representasjon for en bane? En Vektor av punktene virker godt nok. Også må vi definere en avstand mellom hvert punkt. På den måten kan vi være sikker på én viktig ting: Hvis vi definerer avstanden mellom to punkter på banen for å være avstanden som fienden beveger seg under en ramme, vil vi ikke trenge fienden til å behandle for mye informasjon, og vi vil være i stand til å definere etter hvor mange rammer fienden forlater skjermen ved bare å telle antallet punkter i vektoren. På den måten er det veldig lett å definere når en bølge vil ende
Se den i aksjon. Koden under bare gjør fiender følge en sti allerede gitt til dem, og på den tiden gikk til dem (som vil være telles i rammer). Når fienden er opprettet, en teller som starter på et gitt tall begynner synkende etter hvert gått ramme, og når den når null, vil fienden sette seg på skjermen, og begynne å følge sin bane.
Pakke {import flash.geom. Punkt; import net.flashpunk.Entity; import net.flashpunk.FP; import net.flashpunk.graphics.Image; import net.flashpunk.World; public class Enemy strekker Entity {[Bygg (kilde = '../img/EnemyImage.png')] privat konst BILDE: Klasse; private Var _timeToAct: UINT; private Var _pathToFollow. Vector < Point >; private Var _currentPoint: UINT; private Var _myWorld: Verden; private Var _added: Boolean; offentlig funksjon Enemy (timeToAct: uint, pathToFollow. Vector < Point >, worldToBeAdded: World) {grafisk = new Image (BILDE); graphic.x = -15; graphic.y = -8; _timeToAct = timeToAct; _pathToFollow = pathToFollow; _currentPoint = 0; _myWorld = worldToBeAdded; _added = false; } Overstyre offentlig funksjon oppdateringen (): void {if (_timeToAct > 0) {_timeToAct--; } Else {if (_added!) {_myWorld.add (Denne); _added = true; } X = _pathToFollow [_currentPoint] .x; y = _pathToFollow [_currentPoint] .Y; _currentPoint ++; if (_currentPoint == _pathToFollow.length) {_myWorld.remove (denne); _added = false; ødelegge(); }}} Offentlig funksjon ødelegge (): void {grafisk = null; }}}
Fra koden ovenfor, kan du se at vi alltid flytte en fast avstand fra punkt til punkt ved bare å plassere fienden på sin nåværende punkt. Det er på grunn av dette at vi er i stand til å bestemme når en fiende bølge vil ende. Du kan også se at fienden tar seg av alt: å legge seg i verden, beveger seg gjennom verden og fjerne seg fra verden. Med det, er det veldig enkelt å lage fiender i spillet
Trinn 4:. Legge Enemies til Screen
Vår base Enemy klassen er ferdig. Nå er det på tide å endre spillverden, litt for å legge til fiender. Den første oppgaven er å generere stier for fiender. Ved anvendelsen av denne opplæringen, vil vi bare lage en rett linje, men gjerne prøve å skape noen form for bølgebane. Dette er funksjonen som skaper en rett linje:
privat funksjon generateEnemyPath (distanceBetweenPoints: Number): Vector < Point >. {Var i: Number; Var vec: Vector < Point >. = New Vector. ≪ Point > (); Var XPOS: Number = Math.random () * 360 + 20; for (i = -20; i < 520; i + = distanceBetweenPoints) {vec.push (ny Point (XPOS, i)); } Returnere vec; }
Med det, vi kan allerede gi til en fiende en sti å følge. Det neste trinnet er å faktisk lage fienden:
private Var _enemy: Enemy; offentlig funksjon spillverden () {_playerShip = new PlayerShip (); legge (_playerShip); _enemy = new Enemy (0, generateEnemyPath (1), dette); } Overstyre offentlig funksjon oppdateringen (): void {super.update (); if (_enemy) _enemy.update (); }
kompilere og kjøre spillet. Du vil sannsynligvis få følgende feilmelding: product: [Fault] unntak, informasjon = RangeError: Feil # 1 125: Indeksen 540 er utenfor rekkevidde 540.
Det skjer fordi selv etter fienden sletter seg selv fra verden, vi er fortsatt kalle oppdateringen () funksjon av det, fordi vår kode ikke oppdage når fienden fjernet seg selv. La oss fikse det ved å overstyre gjeldende remove () metode:
styre offentlig funksjon remove (e: Entity): Entity {if (e er Enemy) {_enemy = new Enemy (0, generateEnemyPath (1), dette); } Returnere super.remove (e); }
Nå kompilere prosjektet og du vil se dette:
Dette er hva denne funksjonen gjør: hver gang fienden fjerner seg fra verden, oppdager vi at gjennom vår overstyrt funksjon og deretter bare lage en annen fiende å "erstatte" den gamle. Det er alt! Vi har nå fiender som beveger seg over skjermen
Trinn 5: Skyting med spilleren Ship
En shoot-'em-up spill ikke ville være gøy uten kule måter skyting kuler ut av skipet, ville det? I dette trinnet vil vi se en flott måte å organisere bullet mønstre for å skyte dem. Hvis du prøvde å ta en gjetning, er du sannsynligvis riktig: vi kommer til å bruke vektorer av Points. Men denne gangen punktene vil ha dynamiske begynnelser og slutter, fordi skipet ditt vil ikke alltid være på samme sted hver gang du skyter, men ikke bekymre deg, det er ikke så vanskelig som det høres ut!
Strategien her er å generere en kule mønster rundt en fast x- og y-aksen, og deretter summere spilleren skipets posisjon til punktene fra mønsteret, og dermed flytte aksen til en ny posisjon, noe som gir inntrykk av at kulene kommer ut av spilleren skipet. Kulen bildet vi skal bruke er denne:
Alt blir enklere når du ser på koden. Vi er i utgangspunktet gjør noe veldig likt fienden banen:
pakke {import flash.geom.Point; import net.flashpunk.Entity; import net.flashpunk.graphics.Image; public class PlayerBullet strekker Entity {[Bygg (kilde = '../img/BulletImage.png')] privat konst BILDE: Klasse; private Var _pathToFollow. Vector < Point >; private Var _xPos: Number; private Var _yPos: Number; offentlig funksjon PlayerBullet (pathToFollow: Vector < Point >, XPOS:. Antall, yPos: Number) {grafisk = new Image (bilde); graphic.x = graphic.y = -3,5; _pathToFollow = pathToFollow; _xPos = XPOS; _yPos = yPos; } Overstyre offentlig funksjon oppdateringen (): void {x = _xPos + _pathToFollow [0] .x; y = _yPos + _pathToFollow [0] .Y; _pathToFollow.shift (); if (_pathToFollow.length == 0) {world.remove (denne); ødelegge(); }} Offentlig funksjon ødelegge (): void {_pathToFollow = null; grafisk = null; }}}
Legg merke til at vi ikke egentlig lage kule mønstre her: de er alltid sendes som parametere, akkurat som fiender. Den eneste forskjellen er at kulene blir alltid lagt en gang i verden, og vi holder utgangsstillingen av kulen.
La oss prøve å legge en kule når spilleren klikker med musen. I PlayerShip.as:
styre offentlig funksjon oppdateringen (): void {calculateDistances (); if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED) {x = Input.mouseX; y = Input.mouseY; } Else {x + = Math.cos (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED; y + = tak i Math.sin (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED; } If (Input.mousePressed) {world.add (ny PlayerBullet (spillverden (verden) .generateBulletPath (3), x, y)); }}
Nå må vi lage kule banen. Vi kommer til å lage en rett linje, akkurat som for fienden, men du kan gjøre noen form for bane! I GameWorld.as, la oss lage generateBulletPath () -funksjonen:
offentlig funksjon generateBulletPath (distanceBetweenPoints: Number):. Vector < Point > {Var i: Number; Var vec: Vector < Point >. = New Vector. ≪ Point > (); for (i = 0; i > -500; i - = distanceBetweenPoints) {vec.push (ny Point (0, i)); } Returnere vec; }
Med det, traff kompilere og kjøre knappen, og dette er hva du får:
Trinn 6: Collision Detection (Bruke Masker)
Vi har nå det grunnleggende spillet kjører: en spiller skip som skyter og fiender som går nedover skjermen. Tid for å legge dueller!
Det første trinnet for å legge til dueller er å gi hver enhet en type. Jeg vil la det til deg: gi "Player" type til PlayerShip, "Enemy" til Enemy og "PlayerBullet" til PlayerBullet
Vi skal bruke pixel-perfekt kollisjon i dette spillet, så det kan. være nyttig å snakke om masker. Masker er elementer som brukes av FlashPunk for kollisjoner. De er i utgangspunktet som hitboxes, men de kan ha en annen form (pixel-nivå). Vi må sette opp masker for spilleren skipet, fiender og kuler. Bildet brukes av masken er det samme bildet av foretaket. Se på koden for PlayerShip, Enemy og PlayerBullet henholdsvis:
offentlig funksjon PlayerShip () {grafisk = new Image (BILDE); graphic.x = -27,5; graphic.y = -30; maske = new Pixelmask (IMAGE, -27,5, -30); x = 200; y = 400; type = "Player"; } Offentlig funksjon Enemy (timeToAct: uint, pathToFollow: Vector < Point >, worldToBeAdded.: World) {grafisk = new Image (BILDE); graphic.x = -15; graphic.y = -8; maske = new Pixelmask (IMAGE, -15, -8); _timeToAct = timeToAct; _pathToFollow = pathToFollow; _currentPoint = 0; _myWorld = worldToBeAdded; _added = false; type = "Enemy"; } Offentlig funksjon PlayerBullet (pathToFollow. Vector < Point >, XPOS: Number, yPos: Number) {grafisk = new Image (BILDE); graphic.x = graphic.y = -3,5; maske = new Pixelmask (IMAGE, -3,5, -3,5); _pathToFollow = pathToFollow; _xPos = XPOS; _yPos = yPos; type = "PlayerBullet"; }
Som du kan se, er dette veldig enkelt: vi lage en ny Pixelmask, passerer kilden å bruke som en maske (akkurat som med grafikk) og deretter gi både x- og y-forskyvninger (i tilfelle du ønsker å sentrere masken et sted). Nå, i GameWorld.as:
private Var _bulletList. Vector < PlayerBullet >; styre offentlig funksjon oppdateringen (): void {super.update (); if (_enemy) _enemy.update (); _bulletList = new Vector. < PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {if (bullet.collideWith (_enemy, bullet.x, bullet.y)) {_enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }}}
Legg merke til at vi kunne ha bare brukt _enemy.collide ("PlayerBullet", _enemy.x, _enemy.y) for å sjekke for kollisjoner, men metoden er over bedre når vi har mange kuler på skjermen, og det er en mulighet for at to kuler treffer samme fienden samtidig. Vi har kalt den takeDamage () funksjon av Enemy klassen, men i øyeblikket er det ingen. (Lag en tom funksjon for nå I neste trinn vil vi gjøre fienden ta skade og eksplodere når det er nødvendig..) Utarbeide prosjektet, og du vil få dette:
Trinn 7: Enemy Død
Vi har laget kuler treffer våre fiender. I dette trinnet skal vi spille en eksplosjon animasjon hver gang en fiende dør og fjerne det fra spillet. Eksplosjonen animasjon sprite ark er under:
Den tilnærmingen vi vil ta å gjøre dette på er ved å redusere fiendens helse i takeDamage () -funksjonen, og hvis helsen blir under null, vil vi ødelegge den og sette den animasjon i skjermen. Koden for å redusere helse er under:
private Var _health: int = 100; offentlig funksjon takeDamage (): void {_health - = 50; if (_health < = 0) {addExplosion (); _myWorld.remove (denne); _added = false; ødelegge(); }}
Koden er svært enkel. Det er bare én ting ukjent om det: addExplosion () -funksjonen. Denne funksjonen vil opprette en forekomst av eksplosjon og legge det til verden. Eksplosjonen klassen vil bare spille og fjerne seg fra verden etter det. Det er en enkel klasse:
pakke {import net.flashpunk.Entity; import net.flashpunk.graphics.Spritemap; public class Explosion strekker Entity {[Bygg (kilde = '../img/ExplosionAnimation.png')] privat konst ANIMASJON: Klasse; offentlig funksjon Eksplosjons (XPOS: Number, yPos: Number) {grafisk = new Spritemap (animasjon, 50, 46, onAnimationEnd); graphic.x = -25; graphic.y = -23; x = XPOS; y = yPos; Spritemap (grafisk) .Legg ("eksplodere", [0, 1, 2, 3, 4], 25/60, false); Spritemap (grafisk) Beskytt din Nintendo DS ("eksplodere"); } Private funksjon onAnimationEnd (): void {world.remove (denne); ødelegge(); } Offentlig funksjon ødelegge (): void {grafisk = null; }}}
Trikset her er å bruke tilbakeringing parameter i Spritemap klassen. Når animasjonen slutter, vil denne funksjonen bli kalt, og da det fjerner seg fra verden
Nå, tilbake til Enemy .as å fullføre denne funksjonen
privat funksjon addExplosion (): void {world.add (ny Explosion (x, y));! }
Easy, er det ikke? Kompilere spill og ødelegge noen fiender
Trinn 8: Resultat
Det neste logiske skrittet etter at fiendene dør er å legge til en poengsum i spillet! Vi vil gjøre det ved hjelp FlashPunk Tekst klasse. Start med å lage en GameScore klasse, som vil holde resultatet av kampen. Siden teksten er en grafisk, vil vi gjøre GameScore en Entity og legge sin tekst som grafikk. Se på koden:
pakke {import net.flashpunk.Entity; import net.flashpunk.graphics.Text; public class GameScore strekker Entity {private Var _score: int; offentlig funksjon GameScore () {grafisk = ny tekst ("Resultat: 0"); _score = 0; } Offentlig funksjon addScore (poeng: int): void {_score + = poeng; Tekst (grafikk) .text = "Score:" + _score.toString (); } Offentlig funksjon ødelegge (): void {grafisk = null; }}}
Som du kan se, vil vi kaller addScore () -funksjonen til å legge til punkter i spillets poengsum. Først må vi legge det til verden. I GameWorld.as:
private Var _score: GameScore; offentlig funksjon spillverden () {_playerShip = new PlayerShip (); legge (_playerShip); _enemy = new Enemy (0, generateEnemyPath (1), dette); _score = new GameScore (); _score.x = 300; _score.y = 470; legge (_score); } Offentlig funksjon får poeng (): GameScore {return _score; } Offentlig funksjon får poeng (): int {return _score; }
Hvis vi treffer kompilere, får vi bare en statisk poengsum på bunnen av skjermen:
Vi trenger å legge noe til den stillingen hver gang en fiende blir drept. I Enemy.as:
offentlig funksjon takeDamage (): void {_health - = 50; if (_health < = 0) {addExplosion (); Spillverden (verden) .score.addScore (1); _myWorld.remove (denne); _added = false; ødelegge(); }}
Hit kompilere nå og poengene vil alltid øke når en fiende blir drept
Trinn 9: Oppgraderinger
På tide å legge oppgraderinger! Vi vil ikke ha en fin skjerm for å velge oppgraderinger. I stedet vil vi skape oppgraderinger basert på scoren: hver gang poengsum går opp med 5 (opp til 45), vil spillerens hastighet øker litt. Når stillingen blir 25, vil spilleren være i stand til å skyte to skudd på hvert klikk. Vi vil dundret 50 være slutten av spillet.
La oss begynne med koding spilleren speed oppgradering. For det, må vi legge til en multiplikator til hastigheten. I PlayerShip.as:
offentlig Var speedMultiplier: Number = 1; styre offentlig funksjon oppdateringen (): void {calculateDistances (); if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier) {x = Input.mouseX; y = Input.mouseY; } Else {x + = Math.cos (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; y + = tak i Math.sin (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; } If (Input.mousePressed) {world.add (ny PlayerBullet (spillverden (verden) .generateBulletPath (3), x, y)); }}
Nå er det handler om å endre multiplikatoren i GameWorld.as:
private Var _speedUpgradeNumber: int = 0; styre offentlig funksjon oppdateringen (): void {super.update (); if (_enemy) _enemy.update (); _bulletList = new Vector. < PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {if (bullet.collideWith (_enemy, bullet.x, bullet.y)) {_enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }} If ((_score.score% 5) == 0 & & _score.score > (_speedUpgradeNumber * 5)) {_playerShip.speedMultiplier + = 0,1; _speedUpgradeNumber ++; }}
Ferdig! Nå, hver 5 fiendtlige dødsfall spilleren vil motta en 10% økning i flytting hastighet!
For den doble bullet oppgradering, vil vi gjøre en boolsk i PlayerShip klassen som indikerer hvorvidt skipet har oppgraderingen. Da vil vi sjekke at når du fotograferer. Her er det:
offentlig Var hasDoubleShoot: Boolean = false; styre offentlig funksjon oppdateringen (): void {calculateDistances (); if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier) {x = Input.mouseX; y = Input.mouseY; } Else {x + = Math.cos (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; y + = tak i Math.sin (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; } If (Input.mousePressed) {if (hasDoubleShoot) {world.add (ny PlayerBullet (spillverden (verden) .generateBulletPath (3), x - 5, y)); world.add (ny PlayerBullet (spillverden (verden) .generateBulletPath (3), x + 5, y)); } Else {world.add (ny PlayerBullet (spillverden (verden) .generateBulletPath (3), x, y)); }}}
Nå, la oss gjøre det samme som vi gjorde for hastigheten i GameWorld.as:
styre offentlig funksjon oppdateringen (): void {super.update (); if (_enemy) _enemy.update (); _bulletList = new Vector. < PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {if (bullet.collideWith (_enemy, bullet.x, bullet.y)) {_enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }} If ((_score.score% 5) == 0 & & _score.score > (_speedUpgradeNumber * 5)) {_playerShip.speedMultiplier + = 0,1; _speedUpgradeNumber ++; } If (_score.score > = 25) {_playerShip.hasDoubleShoot = true; }}
Og det er det! Hit kompilere og spillet vil ha oppgraderinger
Trinn 10: Øke Vanskelighetsgrad
Hvis du har spilt spillet før får dobbel skutt oppgradering i det siste trinnet, du har kanskje lagt merke til at spillet er for lett akkurat nå. Hva synes du om å øke sin vanskelighetsgrad basert på spillerens poengsum
Det er ideen: spillet vil nå være i stand til å sette på skjermen mer enn én fiende. Og for hver drepe spilleren får vi redusere timeren av gyting en ny fiende. Interessant, er det ikke? Men det er ikke det eneste. Hva med å øke fiendens healths og redusere skadene de tar fra spilleren? Nå vi får et sted
La oss hoppe til koding! Første vi vil gjøre helseøkning og skade reduksjon hver drepe. De vil være akkurat som oppgraderinger på spilleren skip, men denne gangen vil vi trenger å endre vår tilnærming til hvor du kan holde multiplikatorer. I Enemy.as:
private Var _health: int; public static Var healthMultiplier: Number = 1; public static Var damageMultiplier: Number = 1; offentlig funksjon Enemy (timeToAct: uint, pathToFollow. Vector < Point >, worldToBeAdded: World) {grafisk = new Image (BILDE); graphic.x = -15; graphic.y = -8; maske = new Pixelmask (IMAGE, -15, -8); _timeToAct = timeToAct; _pathToFollow = pathToFollow; _currentPoint = 0; _myWorld = worldToBeAdded; _added = false; type = "Enemy"; helse = 100 * Enemy.healthMultiplier; } Offentlig funksjon takeDamage (): void {_health - = 50 * Enemy.damageMultiplier; if (_health < = 0) {addExplosion (); Spillverden (verden) .score.addScore (1); _myWorld.remove (denne); _added = false; ødelegge(); }}
Og nå, i GameWorld.as:
private Var _enemyUpgradeNumber: int = 0; styre offentlig funksjon oppdateringen (): void {super.update (); if (_enemy) _enemy.update (); _bulletList = new Vector. < PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {if (bullet.collideWith (_enemy, bullet.x, bullet.y)) {_enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }} If ((_score.score% 5) == 0 & & _score.score > (_speedUpgradeNumber * 5)) {_playerShip.speedMultiplier + = 0,1; _speedUpgradeNumber ++; } If (_score.score > = 25) {_playerShip.hasDoubleShoot = true; } If (_score.score > _enemyUpgradeNumber) {Enemy.damageMultiplier - = 0,015; Enemy.healthMultiplier + = 0,02; _enemyUpgradeNumber ++; }}
Og nå våre fiender blir sterkere etter hver drepe! Ta den, onde spiller!
Nå må vi endre spillverden for å gyte fiender basert på tid. Det er en enkel ting: vi trenger bare en tidtaker og en gyte intervall. Her er alt den modifiserte koden:
private Var _enemyList. Vector < Enemy >; private Var _enemySpawnInterval: int = 5000; private Var _enemySpawnTimer: int; offentlig funksjon spillverden () {_playerShip = new PlayerShip (); legge (_playerShip); _enemyList = new Vector. < Enemy > (); _score = new GameScore (); _score.x = 300; _score.y = 470; legge (_score); _enemySpawnTimer = 0; } Overstyre offentlig funksjon oppdateringen (): void {super.update (); _enemySpawnTimer--; if (_enemySpawnTimer < = 0) {_enemySpawnTimer = _enemySpawnInterval; _enemyList.push (ny Enemy (uint (Math.random () * 30), generateEnemyPath (2), dette)); legge (_enemyList [_enemyList.length - 1]); } _bulletList = New Vector. ≪ PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {for hver (var fienden: Enemy in _enemyList) {if (bullet.collideWith (fiende, bullet.x, bullet.y)) {enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }}} If ((_score.score% 5) == 0 & & _score.score > (_speedUpgradeNumber * 5)) {_playerShip.speedMultiplier + = 0,1; _speedUpgradeNumber ++; } If (_score.score > = 25) {_playerShip.hasDoubleShoot = true; } If (_score.score > _enemyUpgradeNumber) {Enemy.damageMultiplier - = 0,015; Enemy.healthMultiplier + = 0,02; _enemyUpgradeNumber ++; }} Overstyre offentlig funksjon remove (e: Entity): Entity {if (e er Enemy) {_enemyList.splice (_enemyList.indexOf (e), 1); } Returnere super.remove (e); }
Legg merke til at jeg ga fiender noen tilfeldige rammer av "vente tid" før de vises. Det vil gjøre sitt utseende uforutsigbar. Nå er alt som gjenstår er å redusere spawn intervall etter hvert kill:
styre offentlig funksjon oppdateringen (): void {super.update (); _enemySpawnTimer--; if (_enemySpawnTimer < = 0) {_enemySpawnTimer = _enemySpawnInterval; _enemyList.push (ny Enemy (uint (Math.random () * 30), generateEnemyPath (2), dette)); legge (_enemyList [_enemyList.length - 1]); } _bulletList = New Vector. ≪ PlayerBullet > (); getType ("PlayerBullet", _bulletList); for hver (var bullet: PlayerBullet i _bulletList) {for hver (var fienden: Enemy in _enemyList) {if (bullet.collideWith (fiende, bullet.x, bullet.y)) {enemy.takeDamage (); fjerne (bullet); bullet.destroy (); }}} If ((_score.score% 5) == 0 & & _score.score > (_speedUpgradeNumber * 5)) {_playerShip.speedMultiplier + = 0,1; _speedUpgradeNumber ++; } If (_score.score > = 25) {_playerShip.hasDoubleShoot = true; } If (_score.score > _enemyUpgradeNumber) {Enemy.damageMultiplier - = 0,015; Enemy.healthMultiplier + = 0,02; _enemySpawnInterval - = 3; _enemyUpgradeNumber ++; }}
Med det vi i utgangspunktet har alt gjort i spillverdenen
Trinn 11: The Main Menu Verden
Jeg tror vi har alt ferdig i spillverdenen . Spillets overraskende vanskelig med de tøffere fiender! Hva synes du om å lage en fin hovedmeny nå? Jeg laget en fin bakgrunn for det:
Lag MainMenuWorld klassen, som strekker seg fra net.flashpunk.World, og legge bakgrunnen i den. Jeg vil forlate koden for deg. Vi trenger en play-knapp, som jeg også laget:
For å skape avspillingsknappen, har vi tenkt å bruke Button klassen opprettet i første del av denne opplæringen serien. Her er koden for knappen i MainMenuWorld.as: product: [Embed (kilde = '../img/PlayGameButton.png')] privat konst PLAYBUTTON: Klasse; private Var _playButton: Button; offentlig funksjon MainMenuWorld () {addGraphic (new Image (TITTEL)); _playButton = new Button (playTheGame, null, 48, 395); _playButton.setSpritemap (PLAYBUTTON, 312, 22); legge (_playButton); } Private funksjon playTheGame (): void {FP.world = ny spillverden (); ødelegge(); } Offentlig funksjon ødelegge (): void {RemoveAll (); _playButton = null; }
Ikke glem å endre hovedklassen samt
styre offentlig funksjon init (): void {FP.world = new MainMenuWorld (!); FP.console.enable (); }
Hit kompilere og ... ja! Vår skinnende hovedmeny verden fungerer! Nå til spillet over verden
Trinn 12: The Game Over Verden
The game over verden kommer til å være svært enkel. Jeg har laget to bilder: ett for når spilleren dør og ett for når spilleren vinner spillet. Det vil være en Avslutt knapp som vil returnere spilleren til hovedmenyen. Det er i utgangspunktet det samme som hovedmenyen verden. Her er de to bildene og knappen:
Jeg vil forlate koding til deg. Det eneste som vil endre seg i denne klassen er at den trenger en argument til konstruktøren, forteller hvorvidt spilleren ødelagt fiender. Her er koden for konstruktøren:
offentlig funksjon GameOverWorld (hasLost: Boolean) {if (hasLost) {addGraphic (new Image (BACKGROUNDLOST)); } Else {addGraphic (new Image (BACKGROUNDWON)); } _quitButton = New Button (quitToMain, null, 166, 395); _quitButton.setSpritemap (QUITBUTTON, 69, 19); legge (_quitButton); }
Trinn 13: The Boss - Movement
Til slutt, i det øyeblikket alle ventet på. Hver shoot-'em-up trenger en sjef, og dette er vår!
Det vi trenger nå er normen. Først bevegelsene. Og da kulene. Dette trinnet er for bevegelsene.
Som du kanskje har gjettet, vil sjefen ikke gå direkte ned på skjermen. I stedet vil den flytte tilfeldig rundt toppen av skjermen, for å gi spilleren litt problemer med å beseire den. Det vi trenger å gjøre er en bevegelse svært lik spillerens. Den eneste forskjellen er at det vil følge et punkt valgt tilfeldig i toppen av skjermen, og ikke musen. Her er hele koden for Boss klassen
pakke {import flash.geom.Point!; import net.flashpunk.Entity; import net.flashpunk.graphics.Image; import net.flashpunk.masks.Pixelmask; public class Boss strekker Entity {[Bygg (kilde = '../img/BossImage.png')] privat konst BILDE: Klasse; private Var _currentDistanceX: Number; private Var _currentDistanceY: Number; private Var _randomPoint: Point; privat konst SPEED: int = 3; offentlig Var speedMultiplier: Number = 1; offentlig funksjon Boss () {grafisk = new Image (BILDE); graphic.x = -38; graphic.y = -35; maske = new Pixelmask (IMAGE, -38, -35); type = "BossEnemy"; getRandomPoint (); } Private funksjon getRandomPoint (): void {_randomPoint = new Point (); _randomPoint.x = Math.random () * 400; _randomPoint.y = 38 + (Math.random () * 100); } Overstyre offentlig funksjon oppdateringen (): void {calculateDistances (); if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier) {x = _randomPoint.x; y = _randomPoint.y; getRandomPoint (); } Else {x + = Math.cos (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; y + = tak i Math.sin (Math.atan2 (_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier; }} Private funksjons calculateDistances (): void {_currentDistanceX = _randomPoint.x - x; _currentDistanceY = _randomPoint.y - y;