Vector Regioner: Hiding Fra en synsfelts
en
Del
to
Del
Denne Cyber Monday Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.
Vi har tidligere utforsket tilnærming for å bruke vektor regioner for å gjennomføre synsfeltet til en turret. Tropper nærmet turret på marken, og ingen hindringer lå mellom dem. Nå antar det er en hindring, sier en vegg, som tilslører synligheten tropp fra turret; hvordan skal vi implment det? Denne opplæringen foreslår en tilnærming til å takle dette problemet.
Endelig resultat Forhåndsvisning
La oss ta en titt på det endelige resultatet vi skal jobbe mot. Klikk på tårnet på bunnen av scenen for å starte simuleringen
Trinn 1:. Den grunnleggende konseptet
Så her er det vi prøver å oppnå i denne opplæringen. Observere bildet ovenfor. Turret kan se trooper enheten hvis det er innenfor turret synsfelt (øverst). Når vi plasserer en vegg i mellom tårnet og trooper, er trooper synlighet skjermet mot turret
Trinn 2:. Recap
Først av alt, la oss gjøre en liten revisjon. Si vektoren av turret siktlinje er P og vektoren fra turret til trooper er Q. trooper er synlig for turret dersom:
Vinkel mellom P og Q er mindre enn synsvinkel (i dette tilfellet 30 ° på begge sider)
Omfanget av P er mer enn Q
Trinn 3: Approach Oversikt
Over er pseudo -code for den tilnærmingen vi skal gjennomføre. Fastslå om trooper er innenfor turret synsfelt (FOV) er forklart i trinn 2. Nå la oss komme til å avgjøre om den trooper er bak en vegg.
Vi skal bruke vektoroperasjoner for å oppnå dette. Jeg er sikker på at ved omtale av dette, prikk-produktet og kryssproduktet kommer raskt til hjernen. Vi skal lage en liten omvei for å revidere disse to vektoroperasjoner bare for å være sikker på alles kunne følge
Trinn 4:. Dot og Cross Product mellom vektorer
La oss se på vektoroperasjoner : dot produkt og kryssproduktet. Dette er ikke en matte klasse, og vi har dekket disse i mer detalj før, men likevel, det er godt å oppdatere vår hukommelse på hjemkomsten så jeg har tatt bildet ovenfor. Diagrammet viser "B dot A" operasjon (øverst til høyre) og "B kryss A" operasjon (nederst i høyre hjørne).
Mer viktig er ligninger av disse operasjonene. Ta en titt på bildet nedenfor. | A | og | B | refererer til skalar størrelse Merk at disse bølgeformer er kontinuerlige og repeterende. For eksempel kan du klippe ut og lime inn sinuskurve i det negative området for å få noe sånt under I tabellen over viser cosinus og sinus verdier tilsvarende spesifikke grader. Du vil merke den positive sinus grafen dekker 0 ° til 180 ° rekkevidde og positiv cosinus grafen dekker -90 ° til 90 °. Vi skal relatere disse verdiene til prikk-produktet og kryssproduktet senere Så hvordan kan alle disse være nyttig? Å klippe til forfølgelse, er prikken produktet et mål på hvor parallelt Lar håndtere prikken produktet først. Husker formelen for prikk-produktet, som nevnt i trinn 4. Vi kan fastslå hvorvidt resultatet er positivt eller negativt bare ved å se på cosinus til vinkelen klemt mellom de to vektorer. Hvorfor? På grunn av at størrelsen av en vektor er alltid positive. Den eneste parameter igjen å diktere tegn på resultatet er cosinus til vinkelen Igjen, husker at positive cosinus grafen dekker -90 ° -. 90 °, som i trinn 6. Derfor skalarproduktet A med en hvilken som helst av de vecotrs L, M, N, O ovenfor, vil gi en positiv verdi, fordi vinkelen klemt fast mellom en og noen av disse vektorer er innenfor -90 ° og 90 °! (For å være presis, er det positive området mer som -89 ° - 89 ° fordi både -90 ° og 90 ° produserer cosinus verdier av 0, noe som bringer oss til neste punkt.) Prikken produkt mellom A og P (gitt P er vinkelrett på A) vil produsere 0. Resten Jeg tror du kan allerede gjette. skalarproduktet av A med K, R, eller Q vil gi en negativ verdi Ved hjelp av dot produkt, kan vi splittet området på scenen i to regioner. Skalarproduktet av vektoren nedenfor med et punkt som ligger på innsiden av "x" -merket område vil gi en positiv verdi, mens dot produkt med de i "o" -merket region vil produsere negative verdier. La oss gå videre til korset produktet. Husk at kryssproduktet er relatert til sinus Så ser igjen på diagrammet fra trinn 7, vil kryssproduktet mellom A og K, L eller M gi positive verdier, mens kryssproduktet mellom A og N, O, P, eller Q vil produsere negative verdier. Kryssproduktet mellom A og R vil produsere 0 da sinus til 180 ° er 0. For å klargjøre ytterligere, kryssproduktet av vektor mellom ethvert punkt som ligger i "o" -merket region nedenfor vil være positiv, vil, mens de i "x" -merket region være negativ. Ett punkt å ta merke til er at, i motsetning til dot produktet, er kryssproduktet sekvens sensitive. Dette betyr resultatene av AxB og BXA vil være annerledes i forhold til retning. Så som vi skriver programmet vårt, må vi være presis når du velger hvilke vektor å bli sammenlignet mot (Merk:. Disse begrepene forklart gjelder 2D kartesisk plass). For å forsterke din forståelse, har jeg plassert her en liten applikasjon som lar deg spille med. Klikk på den blå ballen på toppen av scenen og dra den rundt. Når du beveger deg, vil tekstboksen verdi oppdatere avhengig av hvilken operasjon du har valgt (dot eller kryssproduktet mellom statisk pilen med den du styrer). Du kan observere en kuriositet med kryssproduktet er omvendt retning. Regionen på toppen er negativ, og den nederste er positiv, i motsetning til vår forklaring i foregående trinn. Vel, dette er på grunn av y-aksen blir invertert i Flash koordinere plass i forhold til kartesisk koordinatsystem plass; den peker ned, mens tradisjonelt matematikere ta det som peker oppover Nå som du har forstått konseptet med regioner, la oss gjøre en liten praksis. Vi skal dele vår plass i fire kvadranter:. A1, A2, B1, B2 Jeg har ordnet resultatene for å se etter under. "Vector" her refererer til pilen i bildet ovenfor. "Point" refererer til en hvilken som helst koordinat i det angitte området. Vektoren deler scenen inn i fire hovedområder, hvor skillevegger (stiplede linjer) strekker til uendelig. Her er Flash presentasjon utstillingsvindu ideer som forklart i trinn 10. Høyreklikk på scenen til pop kontekstmenyen og velg den regionen du ønsker å se uthevet Her er den Action gjennomføringen av begrepet forklart i trinn 10. Føl deg fri til å vise hele stykke kode i kilden nedlasting, som AppLine.as Etter å ha forstått de geometriske tolkninger av dot produkt og kryssproduktet, skal vi bruke det til vår scenario. The Flash presentasjon over viser variasjoner av samme scenario og oppsummerer de vilkår som gjelder for et trooper skjermet av en mur, men inne i turret er FOV. Du kan bla gjennom rammene ved hjelp av piltastene. Forklaringene nedenfor er basert på 2D Flash koordinere plass. I ramme 1, er en vegg plassert mellom dreietårnet og trooper. La A og B være vektorer fra dreietårnet til halen og hodet til veggens vektor, respektivt. La C være vektoren av veggen, og D være vektoren fra halen av veggen til trooper. Til slutt, la Q være vektoren fra turret til trooper Jeg har ordnet de resulterende forholdene nedenfor Dette er ikke den eneste betingelsen er aktuelt, fordi vi trenger også å begrense trooper til innenfor de stiplede linjer på begge sider. Sjekk ut rammer 2-4 for å se neste sett av betingelser Jeg tror mine andre lesere kan nå velge de riktige forhold for å avgjøre om trooper er skjult eller ikke. Husk at dette settet med forholdene vurderes etter at vi fant tropp å være innenfor turret sin FOV (se trinn 3) Her er den Action implementering av begrepene forklart i trinn 13. Bildet over viser den opprinnelige vektoren av veggen, C. Klikk og dra den røde knappen nedenfor og flytte den rundt for å se området skjermet. Du kan se hele kildekoden i HiddenSector.as. Ok, jeg håper du har eksperimentert med den røde ballen, og hvis du er observant nok du kanskje har lagt merke til en feil. Merk at det ikke er skjermet område som de røde knappen seg til venstre for den andre enden av veggen, således invertering av veggen vektoren for å peke mot venstre i stedet for høyre. Løsningen er i neste trinn Men før det la oss se på et viktig Actionbiten her i HiddenSector.as. For å løse dette problemet, må vi vite om veggen vektoren peker mot venstre eller høyre. La oss si at vi har en referanse vektor, R, som alltid peker mot høyre. Selvfølgelig, det er andre måter rundt dette problemet, men jeg finne det er en mulighet til å utnytte konsepter uttrykt i denne opplæringen, slik at det du går Nedenfor er en Flash-presentasjon som implementerer korreksjon forklart i trinn 15. Etter at du har spilt med det, bla nedover for å sjekke Action tweaks. Endringene fra forrige gjennomføring er uthevet. Dessuten er det sett av tilstanden redefinert i henhold til veggen retning: Sjekk ut full kilde i HiddenSector2.as Nå skal vi lappe vårt arbeid på Scene1.as fra forrige tutorial. Først skal vi sette opp vår vegg Vi initiere variablene, etter public class Scene1_2 strekker Sprite {private Var elva. Sprite; private Var wall_origin: Vector2D, vegg: Vector2D; //lagt i andre tutorial private Var tropper: Vector < Ball >;. . privat Var troopVelo: Vector < Vector2D >; ... deretter trekke veggen for første gang, etter offentlig funksjon Scene1_2 () {makeTroops (); makeRiver (); makeWall (); //lagt i andre tutorial makeTurret (); turret.addEventListener (MouseEvent.MOUSE_DOWN, start); funksjon start (): void {stage.addEventListener (Event.ENTER_FRAME, flytte); }} privat funksjon makeWall (): void {wall_origin = new Vector2D (200, 260); vegg = new Vector2D (80, -40); graphics.lineStyle (2, 0); graphics.moveTo (wall_origin.x, wall_origin.y); graphics.lineTo (wall_origin.x + wall.x, wall_origin.y + wall.y);} ... og tegne på hver ramme, fordi graphics.clear () kall er et sted i behaviourTurret (): Tropper vil samhandle med veggen også. Som de kolliderer med veggen, vil de gli langs veggen. Jeg vil ikke prøve å gå inn i detaljer om dette som det er dokumentert omfattende i kollisjon reaksjon mellom en sirkel og linjesegmenter. Jeg oppfordrer leserne til å sjekke det ut for ytterligere forklaring. Følgende snippet liv i funksjons behaviourTroops (). Til slutt kommer vi til kjøtt av denne opplæringen: å sette opp stand og sjekke om troopers er bak veggen og dermed skjermet mot turret synlighet. Jeg har fremhevet den viktige oppdateringen koder: Sjekk ut full koden i Scene1_2.as Til slutt kan vi lene deg tilbake og ta en titt på lappen. i aksjon. Trykk Ctrl + Enter for å se resultatene av arbeidet ditt. Jeg har tatt med en kopi av arbeids Flash presentasjon under. Klikk på tårnet på bunnen av scenen for å starte simuleringen.
av hver vektor - lengden på pilen. Legg merke til at skalarproduktet angår cosinus til vinkelen mellom vektorene, og kryssproduktet angår sinus til vinkelen mellom vektorene
Trinn 5:. Sinus og cosinus
< p> Boring lenger inn i temaet, trigonometri kommer til å spille: sinus og cosinus. Im sikker på at disse grafene tenne gode minner (eller kvaler). Klikker på knappene på Flash presentasjon under for å se disse grafene med forskjellige enheter (grader eller radianer).
Trinn 6:. Oppsummering av verdier
DegreeSine av degreeCosine av grad-1800-1-90 -1000190101800-1
Trinn 7:. Geometriske Tolkning av Dot Product
vektorene er mens kryssproduktet er et mål på hvor ortogonal
vektorene er.
< hr>
Trinn 8: Geometriske Tolkning av Cross Product
av vinkelen klemt mellom de to vektorene. Den positive sinus Grafen dekker et område på 0 ° til 180 °; den negative dekker 0 ° til -180 °. Bildet nedenfor oppsummerer disse punktene.
< hr>
Trinn 9: Demo Application
Trinn 10:. Definere Regioner
RegionVector på diagrammet kryssproduktet med pointVector på diagram dot produkt med pointA1 (+), på grunn av Flash koordinere plass (+) A2 (+) (-) B1 (-), på grunn av Flash koordinere plass (+) B2 (-) (-)
Trinn 11: Regioner Divided
Trinn 12:. Gjennomføring
//fremhever fargen i henhold til brukerens selectionprivate funksjon farge (). void {//hver ball på scenen kontrolleres mot forholdene for den valgte sak for hver (var element: Ball i sp) {var vec1: Vector2D = new Vector2D (item.x - stage.stageWidth * 0,5, item.y - stage.stageHeight * 0,5); if (velg == 0) {if (vec.vectorProduct (vec1) > 0) item.col = 0xFF9933; annet item.col = 0x334455; } Else if (velg == 1) {if (vec.dotProduct (vec1) > 0) item.col = 0xFF9933; annet item.col = 0x334455; } Else if (velg == 2) {if (vec.vectorProduct (vec1) > 0 & & vec.dotProduct (vec1) > 0) item.col = 0xFF9933; annet item.col = 0x334455; } Else if (velg == 3) {if (vec.vectorProduct (vec1) > 0 & & vec.dotProduct (vec1) < 0) item.col = 0xFF9933; annet item.col = 0x334455; } Else if (velg == 4) {if (vec.vectorProduct (vec1) < 0 & & vec.dotProduct (vec1) > 0) item.col = 0xFF9933; annet item.col = 0x334455; } Else if (velg == 5) {if (vec.vectorProduct (vec1) < 0 & & vec.dotProduct (vec1) < 0) item.col = 0xFF9933; annet item.col = 0x334455; } Item.draw (); }} //bytte saken i henhold til brukerens selctionprivate funksjon swap (e: ContextMenuEvent): void {if (e.target.caption == "VectorProduct") velg = 0; else if (e.target.caption == "DotProduct") velg = 1; else if (e.target.caption == "RegionA1") velg = 2; else if (e.target.caption == "RegionA2") velg = 3; else if (e.target.caption == "RegionB1") velg = 4; else if (e.target.caption == "RegionB2") velg = 5;}
Trinn 13: Skjermet Sikt
LocationCross ProductTroop er foran wallC x D >..; 0Troop er bak wallC x D
LocationCross ProductTroop er innenfor sidene av wall.Q x En 0Troop er til venstre for wallQ x A >.; 0, Q x B > 0Troop er til høyre for wallQ x A
Trinn 14:. Action Implementering
Privat funksjon høydepunkt (): void {var lineOfSight: Vector2D = new Vector2D ( 0, -50) Var sektoren: Number = Math2.radianOf (30); for hver (var element: Ball i sp) {var turret_sp: Vector2D = new Vector2D (item.x - turret.x, item.y - turret.y); //Q if (Math.abs (lineOfSight.angleBetween (turret_sp)) < sektor) {var veggen: Vector2D = new Vector2D (wall2.x - wall1.x, wall2.y - wall1.y); //C Var turret_wall1: Vector2D = new Vector2D (wall1.x - turret.x, wall1.y - turret.y); //En VAR turret_wall2: Vector2D = new Vector2D (wall2.x - turret.x, wall2.y - turret.y); //B Var wall_sp: Vector2D = new Vector2D (item.x - wall1.x, item.y - wall1.y); //D if (wall.vectorProduct (wall_sp) < 0 //C x D & & turret_sp.vectorProduct (turret_wall1) < 0 //Q x A & & turret_sp.vectorProduct (turret_wall2) > 0 //Q x B) {item.col = 0xcccccc} else {item.col = 0; } Item.draw (); }}}
Trinn 15: Retning på Wall
Retning vectorDot ProductWall peker mot høyre (samme side som R) w. R > 0 Wall peker mot venstre (motsatt side av R) w. R
Trinn 16:. Action Tilpasninger Anmeldelser
privat funksjon høydepunkt (): void {var lineOfSight: Vector2D = new Vector2D (0, -50); Var sektor: Number = Math2.radianOf (30); Var pointToRight: Vector2D = new Vector2D (10, 0); //lagt i andre versjon for hver (var element: Ball i sp) {var turret_sp: Vector2D = new Vector2D (item.x - turret.x, item.y - turret.y); //Q if (Math.abs (lineOfSight.angleBetween (turret_sp)) < sektor) {var veggen: Vector2D = new Vector2D (wall2.x - wall1.x, wall2.y - wall1.y); //C Var turret_wall1: Vector2D = new Vector2D (wall1.x - turret.x, wall1.y - turret.y); //En VAR turret_wall2: Vector2D = new Vector2D (wall2.x - turret.x, wall2.y - turret.y); //B Var wall_sp: Vector2D = new Vector2D (item.x - wall1.x, item.y - wall1.y); //D Var sider: boolske; //bytter i henhold til veggen retning hvis (pointToRight.dotProduct (vegg) > 0) {sider = wall.vectorProduct (wall_sp) < 0 //C x D & & turret_sp.vectorProduct (turret_wall1) < 0 //Q x A & & turret_sp.vectorProduct (turret_wall2) > 0 //Q x B} else {sider = wall.vectorProduct (wall_sp) > 0 //C x D & & turret_sp.vectorProduct (turret_wall1) > 0 //Q x A & & turret_sp.vectorProduct (turret_wall2) < 0 //Q x B} if (sider) {item.col = 0xcccccc} else {item.col = 0; } Item.draw (); }}}
Trinn 17:. Sett opp veggen
//lagt i andre tutorialprivate funksjon flytte (e: Hendelses): void {behaviourTroops (); behaviourTurret (); redrawWall ();} //lagt i andre tutorialprivate funksjon redrawWall (): void {graphics.lineStyle (2, 0); graphics.moveTo (wall_origin.x, wall_origin.y); graphics.lineTo (wall_origin.x + wall.x, wall_origin.y + wall.y);}
Trinn 18: Interaksjon med Wall
//Versjon 2 //hvis vasser gjennom elven, tregere //hvis kolliderer med veggen skyver gjennom //annet normal speedvar collideWithRiver: Boolean = river.hitTestObject (tropper [i]) Var wall_norm: Vector2D = wall.rotate (Math2.radianOf (-90)); Var wall12Troop: Vector2D = new Vector2D (tropper [i ] .x - wall_origin.x, tropper [i] .Y - wall_origin.y); Var collideWithWall: Boolean = tropper [i] .rad > Math.abs (wall12Troop.projectionOn (wall_norm)) & & wall12Troop.getMagnitude () < wall.getMagnitude () & & wall12Troop.dotProduct (vegg) > 0; if (collideWithRiver) tropper [i] .Y + = troopVelo [i] .Y * 0,3; else if (collideWithWall) {//omplassere tropp Var projOnNorm: Vector2D = wall_norm.normalise (); projOnNorm.scale (tropper [i] .rad -1); Var projOnWall: Vector2D = wall.normalise (); projOnWall.scale (wall12Troop.projectionOn (vegg)); Var omplassere: Vector2D = projOnNorm.add (projOnWall); tropper [i] .x = wall_origin.x + reposition.x; tropper [i] .Y = wall_origin.y + reposition.y; //skyv gjennom veggen Var justering: Number = Math.abs (troopVelo [i] .projectionOn (wall_norm)); Var slideVelo: Vector2D = wall_norm.normalise (); slideVelo.scale (justering); slideVelo = slideVelo.add (troopVelo [i]) tropper [i] .x + = slideVelo.x; tropper [i] .Y + = slideVelo.y;} else tropper [i] .Y + = troopVelo [i] .Y
Trinn 19: Kontrollere Troopers '"Hidden-ness"
//sjekke om fienden er innen synsvidde //en. Innen sektoren syn //2. Innenfor rekkevidden til visning //3. Nærmere enn gjeldende nærmest enemyvar c1: Boolean = Math.abs (lineOfSight.angleBetween (turret2Item)) < Math2.radianOf (sectorOfSight); Var c2: Boolean = turret2Item.getMagnitude () < lineOfSight.getMagnitude (); Var c3: Boolean = turret2Item.getMagnitude () < closestDistance; //Sjekker om tropp er skjermet av wallvar withinLeft: Boolean = turret2Item.vectorProduct (turret2wall1) < 0var withinRight: Boolean = turret2Item.vectorProduct (turret2wall2) > 0var behindWall: Boolean = wall.vectorProduct (wall12troop) < 0; Var skjermet: Boolean = withinLeft & & withinRight & & behindWall //dersom alle betingelsene oppfylt, oppdatere closestEnemyif (c1 & & c2 & & c3 & &! skjermet) {closestDistance = turret2Item.getMagnitude (); closestEnemy = element;}
Trinn 20: Lauch Application