Bruke vektor Regioner å implementere Field of View i en flash Game

Use Vector Regioner å implementere Field of View i en Flash Game
Del
Del
5
Del

Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.

I denne opplæringen vil du lære hvordan du kan kaste et synsfelt på en turret vokter et bestemt sted. Når en fiende er innenfor turret synsfelt, vil turret skyte på dem. Vector matematikk vil bli brukt til å hjelpe i å implementere dette synsfeltet.




Endelig resultat Forhåndsvisning

La oss ta en titt på det endelige resultatet vi skal jobbe mot. Klikk på turret nederst på scenen for å starte simuleringen



Trinn 1:. Synsfelts

Jeg er sikker på at de fleste leserne har brukt kameraer. Hvert kamera har utsikt vinkel, definert av type linse festet. Det er smale og brede betraktningsvinkler. Visningsvinklene begrense synsfeltet i en sektor. Fra et top-down posisjon, de ser ut som figuren nedenfor. Hvis du tar et bilde, vil eveything innenfor grått område bli tatt.

turret synsfelt i vår simulering er sånn av et kamera. Hvis det er en fiende innenfor sitt synsfelt, en vakt vil svare (avgir en alarm, kan du sikte, skyte, etc)



Trinn 2:. Basic Concept

Diagrammet ovenfor viser synsfeltet til turret. Vanligvis synsvinkel vil være lik på både venstre og høyre. Radiusen vil også være konsekvent i hele sektoren. Så for å sjekke om en fiende er innenfor en turret synsfelt, kan disse to matematiske betingelser brukes:.


    Avstand mellom turret og fienden er mindre enn radius

    Angle fra turret s siktlinje til fienden er mindre enn 30 °


    Trinn 3:. Definer synsfelts Bruke Vector

    Vi skal bruke vektor matematikk for å hjelpe oss. I dette tilfellet, vektorene i betraktning er vLine2 og vLine3. Vi kan:

    Sammenlign størrelsene av vLine2 og vLine3 å validere Forhold 1 fra Trinn 2.

    Sammenlign vinkel klemt mellom vLine2 og vLine3 å validere Forhold 2 fra Trinn 2. Anmeldelser

    Ved hjelp av formelen for skalarproduktet mellom vektorer, kan vi finne vinkelen mellom to vektorer. Jeg har tatt med en Flash presentasjon over for å lette forståelsen. Klikk på knappene nederst for å bla gjennom rammene.

    Her er Action i Vector2D (som jeg har brukt i tidligere tutorials, som denne) som gjør jobben. Legg merke til at linjen 257 er med på å avgjøre om vinkelen er på den negative eller positive side. Dette er imidlertid ikke til å hjelpe oss mye her som retningen er ikke viktig. Flere forklaringer om dette temaet i neste del av denne serien. Twitter /** * Metode for å få den mindre vinkel, i radianer, klemt fra strømvektor til innspill vektor *param Vektor2 En vektor til bundet vinkelen *return vinkel i radianer, positive er klokken, er negativ mot klokken * /public funksjon angleBetween (Vektor2: Vector2D): Antall {//få normalisert vektorer Var Norm1: Vector2D = this.normalise (); Var Norm2: Vector2D = vector2.normalise (); //prikk produkt av vektorer for å finne vinkel Var produkt: Number = norm1.dotProduct (Norm2); Produktet = Math.min (1, produkt); Var vinkel: Number = Math.acos (produkt); //sider av vinkel if (this.vectorProduct (Vektor2) < 0) vinkel * = -1 retur vinkel;}



    Trinn 4: Gjennomføring

    Jeg har tatt med en presentasjon nedenfor som implementerer begrepet synsfelt. Føl deg fri til å klikke og dra de større grå sirkler rundt. Observere området som dekkes av synsfeltet angitt med mørkere prikker



    Trinn 5:. Viktig Action

    Hvis du ønsker å se Actionscript for presentasjonen ovenfor, gjerne åpne opp AppFan.as fra kilden nedlasting - det har kommen å lette forståelsen. Jeg skal bare omfatte her den viktige biten som sjekker forholdene.

    Jeg har uthevet den betingede påstanden om at hver av de små prikkene på scenen vurderes mot den for å se om det innenfor det markerte området.
    //Beregn størrelsen og anglevar vLine2: Vector2D = new Vector2D (b2.x - b1.x, b2.y - b1.y); Var vLine3: Vector2D = new Vector2D (b3.x - b1.x, b3. y - b1.y); Var ang: Number = Math.abs (vLine2.angleBetween (vLine3)) //Eliminer retnings trekk anglevar mag: Number = vLine2.getMagnitude (); for hver (var element: Ball i sp) {var vParticle1: Vector2D = new Vector2D (item.x - b1.x, item.y - b1.y); //Sjekker om faller innenfor sektoren //Tilstand: Magnitude mindre enn mag, vinkelen mellom partikkel ang vLine2 mindre enn ang if (Math.abs (vLine2.angleBetween (vParticle1)) < ang & & mag > vParticle1.getMagnitude ( )) {item.col = 0x000000; } //Hvis utenfor segmentet, opprinnelige fargen annet item.col = 0xCCCCCC; item.draw ();}



    Trinn 6: Variasjoner

    For å legge til variasjon i bruk av synsfeltet, kan vi gjennomføre fjern og nær demping. Faktisk har vi bare gikk gjennom langt demping. For langt demping, fiender som er lenger borte (lenger enn langt demping avstand) ikke kan ses med det turret. For nær demping, kan fiender som er for nær (mindre enn nær demping) ikke bli sett av turret. Dette høres kanskje irrasjonelt, men tenk turret sitter på en høy klippe mens fienden sniker seg rett under klippen.

    Ok, kanskje du ikke er overbevist, så her er et annet eksempel på ulik bruk. En vakt bærer et kort sverd, en bue og piler. Når en fiende er for langt unna, kan han bare ønsker å holde et tett øye på ham. Når fienden kommer på skuddhold, skyter han piler. Når fienden kommer for nær, kjemper han med kort sverd. Du kan også gjennomføre ulike typer vakter: bueskytterne og sverdmenn. Fiender innenfor skytebane behandles av bueskytterne mens de på på nært hold behandles av sverdmenn.

    Ved å forstå forholdene introdusert i trinn 2, variasjoner kan bli innført i vår simulering eller spillet.
    < hr>
    Trinn 7: Definer synsfelt betingelser

    Jeg har tatt med en Flash presentasjon nedenfor for å vise frem forskjellige saker og deres tilsvarende sett av betingelser. Klikk på knappene for å sjekke ut de forskjellige tilfellene



    Trinn 8:. Programmering synsfelt betingelser

    Det følgende er en bit med kode for å gjennomføre de forholdene som legges ut i trinn 7. Det kan være lurt å se hele kildekoden i Region2.as å sjekke ut hele gjennomføringen
    //Kontroll gjøres hver frameprivate funksjon flytte (e: MouseEvent):. void {//Beregn Vector fra vakt til fienden Var g_e: Vector2D = new Vector2D (enemy.x - guard.x, enemy.y - guard.y); Var vinkel: Number = r3.angleBetween (g_e); //Betingelser Var withinSector: Boolean = Math2.degreeOf (Math.abs (vinkel)) < sektor; Var withinR3: Boolean = g_e.getMagnitude () < r3.getMagnitude (); Var withinR2: Boolean = g_e.getMagnitude () < r2.getMagnitude (); Var withinR1: Boolean = g_e.getMagnitude () < r1.getMagnitude (); //Difference eksempel tilfeller if (f.eks == 0) {if (withinSector & & withinR3) {t1.text = "Innenfor FOV"} else t1.text = "Beyond FOV"} else if (f.eks == 1) {if (withinSector & & withinR3 & &! withinR1) {t1.text = "I mellom \\ nfar og nær demping"} else t1.text = "Beyond FOV"} else if (f.eks == 2) { if (withinSector) {if (withinR1) t1.text = "Sword angrep" else if (withinR2) t1.text = "Arrow shoot" else if (withinR3) t1.text = "Keep observere"} else t1.text = " Utover FOV "}} //Bytte eksempel tilfeller i takt med endringene i sammenheng menuprivate funksjon swap (e: ContextMenuEvent): void {//swap eksempel hvis (e.target.caption == & quot; Basic FOV & quot;) eksempel = 0; else if (e.target.caption == & quot; Far /Near Demping & quot;) eksempel = 1; else if (e.target.caption == & quot; Observer /Pil /Sword & quot;) eksempel = 2; //Tegne regionen indikerer registreringsområdet drawRegion ();}



    Trinn 9: Implementering

    Her er en implementering av ideer forklart i trinn 6. Klikk på den svarte sirkelen og dra den supplementene scenen til sjekke om det sitter innenfor det synlige området. Høyreklikk på scenen til pop kontekstmenyen ut, og velg deretter fra "Basic FOV", "Far /Near Demping" og "Observer /Pil /Sword" for å sjekke ut de forskjellige eksempler.



    Trinn 10: Scenario

    Nå til å sette i sammenheng det vi har lært, har vi tenkt å lage en simulering. Her er scenariet:

    En turret er stasjonert i den ene enden av scenen. Dens rolle er å eliminere så mange soldater som invaderer sin plass som mulig. Selvfølgelig vil turret må se disse tropper (innen synsfeltet) for å skyte lasere - og bye-bye tropper. Siden det bare kan skyte en stråle av laser på noe eksempel, det kommer til å velge den nærmeste fienden i sikte.

    På den annen side vil tropper prøve å lykkes over til den andre siden. De vil måtte krysse en elv, som de gjør, de vil avta. Nå er disse troppene skal respawn på toppen av scenen når de dør eller går ut av scenen



    Trinn 11:. Basic Setup

    Gjennomføringen av dette eksemplet vil bli hardkodet . Den grunnleggende oppsett er som følger. På initialisering vil vi trekke grafikk av elementer (elv, tropper, turret) og posisjon så pent. På å klikke på den lilla turret, vil animasjonen starte. På hvert bilde vil vi se dem animere henhold til atferd av hvert element
    offentlig funksjon Scene1 () {makeTroops (.); makeRiver (); makeTurret (); turret.addEventListener (MouseEvent.MOUSE_DOWN, start); funksjon start (): void {stage.addEventListener (Event.ENTER_FRAME, flytte); }} privat funksjon flytte (e: Hendelses): void {behaviourTroops (); behaviourTurret ();}

    Nedenfor er de variablene i denne klassen
    private Var elva. Sprite; private Var tropper: Vector < Ball >; private Var troopVelo:.. Vector < Vector2D >; private Var turret: Sprite, private Var fieldOfView: Sprite, private Var lineOfSight: Vector2D = new Vector2D (0, -300); //siktlinje overfor northprivate Var sectorOfSight: Number = 20 //Egentlig halvparten av sektoren, i grader



    Trinn 12: Tegn og plassering River

    Tegning og posisjonering elva. . Ganske enkelt
    privat funksjon makeRiver (): void {river = new Sprite; addChild (elv); //Angi plasseringen & tegne grafikk av elva med (elv) {x = 0; y = 150; graphics.beginFill (0x22BBDD, 0,2); graphics.drawRect (0, 0, 500, 50); graphics.endFill (); }}



    Trinn 13: Draw og posisjon Tropper

    Tegne tropper vil være enkelt. Men jeg ville ha en "V" formasjon på troppene. Så jeg plassere tropp på bunnen av "V" først, etterfulgt av soldater på begge sider av vingen. Det kan være lurt å justere sin midtstilling gjennom sentrum og avstanden mellom tropper gjennom xApart og yApart. Merk at soldater og dens tilhørende troopVelo har samme indeks. Alle soldater er på vei sørover
    privat funksjons makeTroops (): void {tropper = new Vector < Ball >;.. //Start tropper troopVelo = new Vector. ≪ Vector2D >; //initiere hastighet //lokale variabler Var senter: Vector2D = new Vector2D (stage.stageWidth * 0,5, 150); Var xApart: int = 20; Var yApart: int = 15; //Finne tropper & hastigheter Var en: Ball = new Ball; stage.addChild (a); troops.push (a); a.x = center.x; a.y = center.y; //tropper sørover Var av: Vector2D = new Vector2D (0, 1); troopVelo.push (AV); for (var i: int = 1; i < 11; i ++) {var b: Ball = new Ball; stage.addChild (b); troops.push (b); b.x = center.x + i * xApart; b.y = center.y - i * yApart; Var BV: Vector2D = new Vector2D (0, 1); troopVelo.push (BV); Var c: Ball = new Ball; stage.addChild (c); troops.push (c); c.x = center.x - i * xApart; c.y = center.y - i * yApart; Var CV: Vector2D = new Vector2D (0, 1); troopVelo.push (CV); }}



    Trinn 14: Tegn og plassering Turret

    Her skal vi tegne, posisjon, og orientere turret og dens synsfelt for å møte nordover mot fienden. Merk at siktelinjen er vendt mot nord
    privat funksjon makeTurret (): void {//instantiate, lokalisere, orient turret turret = new Sprite;. stage.addChild (turret); turret.x = stage.stageWidth * 0,5, turret.y = stage.stageHeight; turret.rotation = -90; turretRot = 2; //rotasjonshastighet //tegn turret grafikk Var w: int = 30; Var h: int = 10; turret.graphics.beginFill (0x9911AA); turret.graphics.lineStyle (2); turret.graphics.moveTo (0, -h /2); turret.graphics.lineTo (w, h /2); turret.graphics.lineTo (w, h /2); turret.graphics.lineTo (0, h /2); turret.graphics.lineTo (0, -h /2); turret.graphics.endFill (); //Innstilling data for synsfelt grafikk Var point1: Vector2D = new Vector2D (0, 0); Var poeng2: Vector2D = new Vector2D (1, 0); Var point3: Vector2D = new Vector2D (0, 0); point1.polar (lineOfSight.getMagnitude (), Math2.radianOf (sectorOfSight)); point2.setMagnitude (lineOfSight.getMagnitude () /Math.cos (Math2.radianOf (sectorOfSight))); point3.polar (lineOfSight.getMagnitude (), Math2.radianOf (-sectorOfSight)); //instantiate, lokalisere, orient synsfelt fieldOfView = new Sprite; addChild (fieldOfView); fieldOfView.x = turret.x; fieldOfView.y = turret.y; fieldOfView.rotation = -90; //trekke turret synsfelt fieldOfView.graphics.beginFill (0xff9933, 0,1); fieldOfView.graphics.lineStyle (1); fieldOfView.graphics.moveTo (0, 0); fieldOfView.graphics.lineTo (point1.x, point1.y); fieldOfView.graphics.curveTo (point2.x, point2.y, point3.x, point3.y); fieldOfView.graphics.lineTo (0, 0); fieldOfView.graphics.endFill ();}

    En liten detalj her på tegningen siktelinjen. Jeg har tatt bildet under for avklaring:



    Trinn 15: Tropper 'Behaviour

    Tropper vil bli animert over tid. Her er deres atferd. Legg merke til at de to siste linjene med kode er kommentert. Hvis du ønsker døde soldater for å bli fjernet fra animasjon, kan du uncomment dem
    //troppers behaviourprivate funksjons behaviourTroops (): void {//for hver tropp for (var i.: Int = 0; i < tropper .length; i ++) {//Hvis tropp nå nederst på skjermen, respawn på toppen av skjermen hvis (tropper [i] .Y > stage.stageHeight) {tropper [i] .Y = 0; tropper [i] .x = Math.random () * (stage.stageWidth - 100) + 100; } //Hvis vasser gjennom elven, tregere //annet normal hastighet hvis (river.hitTestObject (tropper [i])) tropper [i] .Y + = troopVelo [i] .Y * 0,3; annet tropper [i] .Y + = troopVelo [i] .Y //Hvis tropp er død (alfa < 0,05), respawn på toppen av skjermen hvis (tropper [i] a < 0,05) {tropper [i] .Y = 0; tropper [i] .x = Math.random () * (stage.stageWidth - 100) + 100; tropper [i] .col = 0xCCCCCC; tropper [i] .draw (); tropper [i] a = 1; //stage.removeChild(troops[i]); troops.splice (i, 1); //troopVelo.splice(i, 1); }}}



    Trinn 16: Turret s Behaviour

    turret vil vokte sin post ved å panorere sitt synsfelt rundt, men innenfor visse vinkler. Her har jeg definert panorering vinkel til å være mellom -135 og -45 (ved hjelp av Flash vinkler). Hvis det er en fiende innen synsvidde, vil den angripe det. Men hvis det er mer enn én fiende, det kommer til å velge det som ligger nærmest angripe
    //turret største behaviourprivate funksjon behaviourTurret (): void {//rotere turret innenfor grensene av -135 &. -45 If (turret.rotation > -45) turretRot = -2 else if (turret.rotation < -135) turretRot = 2 //skyte nærmeste fiende innen synsvidde graphics.clear (); if (enemyWithinSight () = null) {//nærmeste fiende i sikte Var target: Ball = enemyWithinSight (); target.col = 0; target.draw (); //slår til black & target.alpha - = 0,2; //helse forverres //orient turret mot fienden Var turret2Target: Vector2D = new Vector2D (target.x - turret.x, target.y - turret.y); turret.rotation = Math2.degreeOf (turret2Target.getAngle ()); //trekke laser bane til fienden graphics.lineStyle (2); graphics.moveTo (turret.x, turret.y); graphics.lineTo (target.x, target.y); } //Ingen fiende innen synsvidde, fortsette skanningen else {turret.rotation + = turretRot} //slå synsfelt og siktlinje av turret henhold til turret rotasjon fieldOfView.rotation = turret.rotation; lineOfSight.setAngle (Math2.radianOf (turret.rotation));}



    Trinn 17: Får Nærmest Enemy

    turret vil finne det nærmeste fienden i sitt synsfelt og reagerer ved å skyte en laser på det. For å se hvordan den finner det nærmeste fiende, sjekk ut Action gjennomføringen nedenfor
    //returnere nærmeste fiende innen sightprivate funksjon enemyWithinSight (): Ball {var closestEnemy. Ball = null; Var closestDistance: Number = lineOfSight.getMagnitude (); for hver (var element: Ball i tropper) {var turret2Item: Vector2D = new Vector2D (item.x - turret.x, item.y - turret.y); //sjekke om fienden er innen synsvidde //en. Innen sektoren syn //2. Innenfor rekkevidden til visning //3. Nærmere enn gjeldende nærmeste fienden Var c1: Boolean = Math.abs (lineOfSight.angleBetween (turret2Item)) < Math2.radianOf (sectorOfSight); Var c2: Boolean = turret2Item.getMagnitude () < lineOfSight.getMagnitude (); Var c3: Boolean = turret2Item.getMagnitude () < closestDistance; //hvis alle forhold oppfylt, oppdatere closestEnemy if (c1 & & c2 & & c3) {closestDistance = turret2Item.getMagnitude (); closestEnemy = element; }} Returnere closestEnemy;}



    Trinn 18: Lansering Simulering

    Du kan nå trykke Ctrl + Enter i FlashDevelop og observere denne simuleringen. Klikk på turret å starte demo under



    Trinn 19:. Et skritt videre

    Vi kan gjøre bruk av denne forståelsen til:

    Implementere en synsfelt for fiender.

    Implementere flere tårn.

    Introduser variasjon i synsfeltet som forklart i trinn 9.

    ... og så videre .

    Forhåpentligvis vil dette gnist noen ideer og kanskje hjelpe på din neste simulering eller spillet.

    Konklusjon

    Takk for lesing. Som vanlig gjør slippe en kommentar slik at jeg vet om dette har vært nyttig for deg. Jeg skal skrive neste opplæringen for å sjekke ut hvordan fiender kan være ute av turret synsfelt med "gjemmer seg" bak hindringer. Følg med. Anmeldelser