Positionering av skärmindikatorer för att peka på skärmmål

I 2D-rullningsspel (och vissa 3D-spel) behöver du ofta visa spelaren platsen för ett mål som är oskärmad, oavsett om det är en fiende, en allierad eller ett spelmål. Många spel använder en pil som flyter nära kanten av skärmen för att ange vilken riktning målet ligger i. I denna handledning ska jag förklara en metod som använder enkel algebra för att hitta var man ska placera en sådan indikatorpil.


Slope Intercept Form


Lutningsavlyssningsformen är ett sätt att beskriva en rak linje i 2D med linjär algebra. Det använder en backe, som normalt använder symbolen m, som definierar linjens branthet och en offset eller snappa upp, som använder symbolen b, som definierar var linjen korsar y-axeln.

\ [y = mx + b \]

Tack vare detta förhållande kan vi, om vi har ett värde, använda den allmänna ekvationen för att enkelt beräkna det andra värdet, både konceptuellt och matematiskt.

Eftersom vi hittar positionen relativt skärmen - en platt yta - gör vi alla beräkningar i 2D, även om spelet är i 3D.

Tips: Om du arbetar i 3D måste du omvandla världsplatsen till skärmplatsen för ditt 3D-objekt. De flesta vanliga motorer har inbyggda funktioner för att göra detta; konsultera din maskinens dokumentation för mer.

Om vi ​​kan hitta en rad på skärmen som beskriver vilken riktning objektet vi riktar in är in, kan vi bestämma punkten där den passerar en viss kant och använd sedan ett litet prov och fel för att ta reda på vilken sida av skärmen det kommer att bli fäst vid.


Göra antaganden


Om vi ​​tänker oss att vår skärm finns på ett rutnät, och att ursprunget pekar (0, 0) är rätt i mitten av skärmen, då är det enkelt att beräkna de värden som beskriver linjen.

Eftersom linjen kommer att gå igenom mitten, vet vi att vår avlyssning, b, måste vara noll. Och om gallret placeras så här kan vi mycket enkelt beräkna lutningen, m: det är helt enkelt målets y/x. (I bilden ovan är vårt mål muspekaren.)

När vi har sluttningen kan vi använda substitution för att beräkna var linjen skulle passera gränserna på skärmen. Om vi ​​till exempel vill hitta vad y-värdet är vid den punkt där linjen korsar kanten på skärmen använder vi den ursprungliga formen y = mx, var x är inställd på skärmens kant. Om vi ​​ville hitta var den korsar toppen eller botten av skärmen delar vi båda sidorna av m så att ekvationen blir: x = y / m - då satte vi bara in y till kanten av skärmen.

Medan gallret placeras på detta sätt skulle skärmens kant vara halva skärmens bredd, negativ för vänster och positiv för höger. För den vertikala axeln är skärmens kant också på halva sin höjd, men om uppåt är positivt eller negativt kan det variera mellan motorer.

Så ett 800x600px spel kommer att ha sina skärmkanter på x = -400px, x = + 400px, y = -300px, och y = + 300px.


Koordinera rymden

Ovanstående skulle vara bra om ursprunget för koordinatsystemet var skärmens mittpunkt, men det är sällan fallet. De flesta motorer har ursprung i antingen övre vänstra eller nedre vänstra hörn.

Innan vi gör våra beräkningar måste vi flytta vårt koordinatutrymme så att alla våra värden är i förhållande till skärmens mitt, i stället för det ursprungliga ursprung som vår motor använder.

Byta koordinatutrymme. Poäng att inte skala.

Ljudkomplex? Inte riktigt. Vi behöver bara ta reda på hur mycket vi vill flytta koordinatutrymmet och subtrahera det från vår målposition. Så om vi vill flytta vårt nät upp halv halva skärmens bredd, subtraherar vi hälften av skärmens bredd från målets y värde.


Här är jag som jag förberett tidigare

I exemplet ovan är skärmstorleken 800x600px, med koordinatutrymmet förskjutet så att (0, 0) är i mitten av bildskärmen. Skärmmålet är på (800, 400) med samma koordinatutrymme.

Eftersom målets y-koordinat är positivt (och i denna motor pekar y-axeln uppåt), vi vet att den inte kommer att ligga på skärmens undersida, så vi finner ursprungligen sin position längs skärmens övre kant , vilket är (600, 300).

Vi kan matematiskt säga att den här punkten fortfarande är utanför skärmen eftersom dess x-koordinat (600) är större än hälften av bredden (800/2 = 400), så vi flyttar sedan fram till sin position på sidan av skärmen.

Återigen behöver vi bara kontrollera en sida av skärmen, för om vår x-koordinat är positiv så måste punkten vara på höger sida av skärmen. (Om det var negativt, skulle det vara på vänster sida.)

En gång hittar vi punkten på skärmens högra sida - (400, 200) - vi vet det måste vara korrekt, eftersom vi har uteslutit alla andra sidor av skärmen genom en elimineringsprocess.


Lägg till en liten streck av trigonometri

Förutom att placera indikatorn kan du också rotera den för extra effekt, särskilt om det är en pil. Det finns en praktisk funktion som är en del av de flesta matte klasser som ganska enkelt löser detta problem: atan2 ().

De atan2 () funktionen tar två parametrar: en x-koordinat och en y-koordinat. Den returnerar en vinkel som anger riktningen från (0, 0) till (x, y).

 rotation = Math.atan2 (centerMouse.top, centerMouse.left); rotation = rotation * 180 / Math.PI; // konvertera radianer till grader

Det finns ett par saker att tänka på med atan2 () som kan variera mellan språk och motorer. För det första är argumenten ofta atan2 (y, x), medan de flesta andra matematiska funktioner tar x-koordinaten först. Rotationen returneras också ofta i radianer i stället för grader.

Tips: Jag kommer inte att gå in i skillnaderna mellan radianer och grader, förutom att säga att omvandling från en till en annan är lätt: du multiplicerar bara radianerna med (180 / Pi) förvandla dem till grader och multiplicera dem med (Pi / 180) om du vill ändra dem tillbaka.


Senaste kontroller

Det finns en sista sak vi måste kolla innan vi gör en indikator utanför skärmen, och det är om vårt mål faktiskt är avstängt, eftersom det inte ger vettig mening att peka på vårt målriktning om vi redan kan se vårt mål. Återigen ska vi använda ganska enkel matte för att arbeta ut det här.

Eftersom vår skärm är en orotaterad rektangel behöver vi inte göra något med vinklar, vi behöver bara kontrollera om vår målpunkt är lägre än toppen, högre än botten, till vänster om höger kant, och till höger om skärmens vänstra kant.

var screen = bredd: 200; höjd: 100 // dummyvärden alert (isTargetOnScreen (vänster: 50; topp: 60)); // Sann varning (isTargetOnScreen (vänster: 250; topp: 10)); // Falsk funktion isTargetOnScreen (target) if (target.top> 0 && target.top < screen.height && target.left < screen.width && target.left > 0) // målet är på skärmen, använd ett överlag eller gör ingenting. återvänd sant;  annat // målet är utanför skärmen, hitta indikatorposition. returnera false; 

Med hjälp av dummyvärdena ovan finner vi att målet är på skärmen. Dessa värden kan komma från var som helst som lagrar information om objektet du spårar.

Observera att koden ovan förutsätter att vi befinner oss i koordinatutrymmet där (0, 0) är i hörn av skärmen, som de flesta motorer kommer att ha som standard. Därför bör detta steg ske innan du flyttar koordinatutrymmet till mitten som vi gör när du beräknar indikatorpositionen.


Få alltid att falla på plats

Här är en snabb demo för att visa dessa begrepp i aktion (se koden på GitHub):

Låt oss gå igenom koden:

  • För det första kontrollerar vi om målet verkligen är utanför skärmen. om det är på skärmen vet vi redan vart du ska placera markören om vi vill göra det.
  • Vi ändrar koordinatutrymmet så att ursprunget ligger i mitten av skärmen.
  • Om vi ​​tittar på muspositionen kan vi enkelt berätta om det är på den övre eller nedre delen av skärmen.
  • Med hjälp av den informationen och algebraisk substitution beräknar vi var den punkten skulle vara på antingen övre eller nedre delen av skärmen.
  • Vi tittar på den punkt som vi just har beräknat och kontrollerar om det verkligen är en position på skärmen, eller om den är för långt bort till vänster eller höger.
  • Om punkten är på skärmen beräknar vi en ny punkt på sidan av skärmen, i stället för toppen eller botten.
  • Vi borde nu ha rätt ställe i fel koordinatutrymme, så vi gör motsatsen till vad vi gjorde i det första steget för att återföra det till rätt koordinatsystem.

Slutsats

Där har du det: en praktisk kodbit för att lägga till i ditt spelets användargränssnitt. Nu när du kan peka spelaren i riktning mot ett mål, överväg hur du kan visa avståndet också.