Plassering av skjermindikatorer for å peke til skjermmål

I 2D-rullespill (og noen 3D-spill) må du ofte vise spilleren plasseringen av et mål som er utenfor skjermen, enten det er en fiende, en alliert eller et spillmål. Mange spill bruker en pil som flyter nær kanten av skjermen for å indikere hvilken retning målet ligger i. I denne opplæringen skal jeg forklare en metode som bruker enkel algebra for å finne hvor du skal plassere en slik indikatorpil.


Slope Intercept Form


Hellingsfeltformen er en måte å beskrive en rett linje i 2D med lineær algebra. Den bruker en skråningen, som vanligvis bruker symbolet m, som definerer steinheten i linjen, og en offset eller avskjære, som bruker symbolet b, som definerer hvor linjen krysser y-aksen.

\ [y = mx + b \]

Takket være dette forholdet, hvis vi har en verdi, kan vi bruke den generelle ligningen til å enkelt beregne den andre verdien, både konseptuelt og matematisk.

Siden vi finner posisjonen i forhold til skjermen - en flat overflate - gjør vi alle beregninger i 2D, selv om spillet er i 3D.

Tips: Hvis du jobber i 3D, må du omdanne verdensplasseringen til skjermstedet for 3D-objektet ditt. De fleste vanlige motorer har innebygd funksjoner for å gjøre dette; ta kontakt med maskinens dokumentasjon for mer.

Hvis vi finner en linje på skjermen som beskriver hvilken retning objektet vi målretter inn er, kan vi bestemme punktet der det krysser en gitt kant, og bruk en liten prøve og feil for å finne ut hvilken side av skjermen det vil være festet til.


Å gjøre antagelser


Hvis vi forestiller oss at skjermen er på et rutenettet, og at opprinnelsen peker (0, 0) er midt på skjermen, så er det enkelt å beregne verdiene som beskriver linjen.

Siden linjen vil gå gjennom sentrum, vet vi at vi fanger opp, b, må være null. Og hvis nettverket er plassert slik, kan vi veldig enkelt beregne hellingen, m: Det er rett og slett målet y/x. (I bildet over er målet vårt musemarkøren.)

Når vi har skråningen, kan vi bruke substitusjon for å beregne hvor linjen vil krysse grensene på skjermen. For eksempel, hvis vi vil finne ut hva y-verdien er på det punktet der linjen krysser kanten av skjermen, bruker vi den opprinnelige formen y = mx, hvor x er satt til kanten av skjermen. Hvis vi ønsket å finne hvor det krysser toppen eller bunnen av skjermen, deler vi begge sider av m slik at ligningen blir: x = y / m - da satte vi nettopp y til kanten av skjermen.

Mens rutenettet er plassert på denne måten, vil kanten på skjermen være halvparten av skjermens bredde, negativ for venstre og positiv for høyre. For den vertikale aksen er kanten på skjermen på halvparten sin høyde, men om oppe er positiv eller negativ, kan det variere mellom motorer.

Så, et 800x600px spill vil ha sine skjermkanter på x = -400px, x = + 400px, y = -300px, og y = + 300px.


Koordinere plass

Ovennevnte ville være fint hvis opprinnelsen til koordinatsystemet var sentrum av skjermen, men det er sjelden tilfellet. De fleste motorer har opprinnelsen i enten øvre venstre eller nederste venstre hjørne.

Før vi utfører beregningene våre, må vi skifte koordinatplassen, slik at alle verdiene våre er i forhold til midten av skjermen, i stedet for den standard opprinnelsen vår motor bruker.

Bytte koordinatrom. Poengene skal ikke skaleres.

Lydkompleks? Ikke egentlig. Vi trenger bare å finne ut hvor mye vi vil flytte koordinatplassen, og trekke det fra vår målposisjon. Så hvis vi ønsker å flytte rutenettet opp halvparten av skjermbredden, trekker vi halvparten av skjermbredden fra målets y verdi.


Her er jeg jeg forberedt tidligere

I eksemplet ovenfor er skjermstørrelsen 800x600px, med koordinatplassen flyttet slik at (0, 0) er midt på skjermen. Skjermmålet er på (800, 400) bruker samme koordinatrom.

Siden målets y-koordinat er positivt (og i denne motoren peker y-aksen oppover), vet vi at den ikke vil være på undersiden av skjermen, slik at vi først finner sin posisjon langs skjermens øverste kant , som er (600, 300).

Vi kan matematisk fortelle at dette punktet fortsatt er utenfor skjermen fordi dets x-koordinat (600) er større enn halvparten av bredden (800/2 = 400), så vi beveger oss videre på å finne sin posisjon på siden av skjermen.

Igjen, vi trenger bare å sjekke den ene siden av skjermen, fordi hvis vår x-koordinat er positiv så må poenget være på høyre side av skjermen. (Hvis det var negativt, måtte det være på venstre side.)

Når vi finner punktet på høyre side av skjermen - (400, 200) - vi vet det Vær riktig, siden vi har utelukket hverandre på skjermen gjennom en elimineringsprosess.


Legg til et lite strekk av trigonometri

I tillegg til å plassere indikatoren, vil du kanskje også rotere den for ekstra effekt, spesielt hvis det er en pil. Det er en praktisk funksjon som er en del av de fleste matematikklasser som løser dette problemet ganske enkelt: atan2 ().

De atan2 () funksjonen tar to parametre: en x-koordinat og en y-koordinat. Den returnerer en vinkel som angir retningen fra (0, 0) til (x, y).

 rotasjon = Math.atan2 (centerMouse.top, centerMouse.left); rotasjon = rotasjon * 180 / Math.PI; // konvertere radianer til grader

Det er et par ting å huske på atan2 () som kan variere mellom språk og motorer. For det første er argumentene ofte atan2 (y, x), mens de fleste andre matematiske funksjoner tar x-koordinaten først. Også, rotasjonen blir ofte returnert i radianer, snarere enn grader.

Tips: Jeg vil ikke gå inn i forskjellene mellom radianer og grader, bortsett fra å si at konvertering fra den ene til den andre er lett: du multipliserer bare radialene med (180 / Pi) å slå dem i grader, og formere dem med (Pi / 180) hvis du vil endre dem tilbake.


Siste sjekker

Det er en siste ting vi må sjekke før du gjør en indikator off-screen, og det er om målet vårt egentlig ikke er på skjermen, siden det ikke gir mening å peke på målet vårt hvis vi allerede kan se målet vårt. Igjen, vi skal bruke ganske enkel matte til å fungere dette.

Siden skjermen er et urotert rektangel, trenger vi ikke å gjøre noe med vinkler, vi må bare sjekke om måletpunktet er lavere enn toppen, høyere enn bunnen, til venstre for høyre kant, og til høyre for venstre kant av skjermen.

var skjerm = bredde: 200; høyde: 100 // dummyverdier varsling (isTargetOnScreen (venstre: 50; topp: 60)); // True alert (isTargetOnScreen (venstre: 250; topp: 10)); // False funksjon erTargetOnScreen (target) if (target.top> 0 && target.top < screen.height && target.left < screen.width && target.left > 0) // målet er på skjermen, bruk et overlegg, eller gjør ingenting. returnere sant;  ellers // målet er på skjermen, finn indikatorposisjon. returner falsk; 

Ved å bruke dummyverdiene ovenfor finner vi at målet er på skjermen. Disse verdiene kan komme fra hvor som helst som lagrer informasjon om objektet du sporer.

Merk at koden ovenfor antar at vi er i koordinatområdet hvor (0, 0) er i den hjørne av skjermen, som de fleste motorer vil ha som standard. Derfor bør dette trinnet gjøres før du skifter koordinatplassen til midten som vi gjør når du beregner indikatorposisjonen.


Sette alt sammen

Her er en rask demonstrasjon for å vise disse begrepene i handling (se koden på GitHub):

La oss gå gjennom koden:

  • For det første kontrollerer vi om målet faktisk er utenfor skjermbildet; Hvis det er på skjermen, vet vi allerede hvor du skal plassere markøren, hvis vi ønsker å gjøre det.
  • Vi endrer koordinatplassen, slik at opprinnelsen ligger midt på skjermen.
  • Når vi ser på museposisjonen, kan vi enkelt fortelle om det er på toppen eller nederste halvdel av skjermen.
  • Ved å bruke denne informasjonen, og algebraisk substitusjon, beregner vi hvor dette punktet ville være på enten toppen eller bunnen av skjermen.
  • Vi ser på det punktet vi nettopp har beregnet, og sjekker om det faktisk er en posisjon på skjermen, eller hvis den er for langt til venstre eller høyre.
  • Hvis poenget er på skjermen, beregner vi et nytt punkt på siden av skjermen, i stedet for toppen eller bunnen.
  • Vi burde nå ha det rette poenget i feil koordinasjonsplass, så vi gjør det motsatte av det vi gjorde i første steg for å bringe det tilbake i riktig koordinatsystem.

Konklusjon

Der har du det: En praktisk kodebit for å legge til i spillets brukergrensesnitt. Nå som du kan peke spilleren i retning av et mål, bør du vurdere hvordan du kan vise avstanden også.