Positie-indicatoren op het scherm om naar doelen op het scherm te verwijzen

In 2D-scrolleergames (en sommige 3D-games) moet je de speler vaak de locatie tonen van een doel dat buiten het scherm valt, of het nu een vijand, een bondgenoot of een speldoelstelling is. Veel games gebruiken een pijl die dicht langs de rand van het scherm zweeft om aan te geven in welke richting het doelwit ligt. In deze tutorial zal ik een methode uitleggen die eenvoudige algebra gebruikt om te vinden waar zo'n indicatorpijl moet worden geplaatst.


Slope Onderschept formulier


Het hellingsintercept is een manier om een ​​rechte lijn in 2D te beschrijven met lineaire algebra. Het gebruikt een helling, die normaal gesproken het symbool gebruikt m, die de steilheid van de lijn bepaalt, en een compenseren of onderscheppen, welke het symbool gebruikt b, die definieert waar de lijn de y-as passeert.

\ [y = mx + b \]

Dankzij deze relatie kunnen we, als we één waarde hebben, de algemene vergelijking gebruiken om eenvoudig de andere waarde te berekenen, zowel conceptueel als wiskundig.

Omdat we de positie ten opzichte van het scherm - een vlak oppervlak - vinden, doen we alle berekeningen in 2D, zelfs als het spel in 3D is.

Tip: Als u in 3D werkt, moet u de locatie van de wereld transformeren naar de schermlocatie van uw 3D-object. De meeste reguliere engines hebben ingebouwde functies om dit te doen; raadpleeg de documentatie van uw motor voor meer informatie.

Als we een lijn op het scherm kunnen vinden die beschrijft in welke richting het object waarop we ons richten zich bevindt, kunnen we het punt bepalen waar het een gegeven rand kruist, en dan een beetje vallen en opstaan ​​gebruiken om uit te vinden aan welke kant van het scherm het zal zijn bevestigd aan.


Veronderstellingen maken


Als we ons voorstellen dat ons scherm op een raster staat en dat het oorsprongspunt is (0, 0) staat in het midden van het scherm, dan is het eenvoudig om de waarden te berekenen die de lijn beschrijven.

Omdat de lijn door het centrum gaat, weten we dat onze intercept, b, moet nul zijn. En als het raster op deze manier wordt geplaatst, kunnen we heel eenvoudig de helling berekenen, m: het zijn gewoon de doelwitten Y/X. (In de bovenstaande afbeelding is ons doel de muiscursor.)

Zodra we de helling hebben, kunnen we substitutie gebruiken om te berekenen waar de lijn de randen van het scherm zou overschrijden. Als we bijvoorbeeld willen weten wat de y-waarde is op het punt waar de lijn de rand van het scherm overschrijdt, gebruiken we de originele vorm y = mx, waar X is ingesteld op de rand van het scherm. Als we wilden weten waar het de boven- of onderkant van het scherm overschrijdt, verdelen we beide kanten m zodat de vergelijking wordt: x = y / m - dan zijn we net begonnen Y naar de rand van het scherm.

Terwijl het raster op deze manier wordt geplaatst, zou de rand van het scherm de helft van de breedte van het scherm zijn, negatief voor links en positief voor rechts. Voor de verticale as, op dezelfde manier, is de rand van het scherm op de helft van de hoogte, maar of omhoog positief of negatief is, kan variëren tussen motoren.

Dus een 800x600px-spel heeft zijn schermranden x = -400px, x = + 400 px, y = -300px, en y = + 300 px.


Coördineer de ruimte

Het bovenstaande zou goed zijn als de oorsprong van het coördinatensysteem het middelpunt van het scherm was, maar dat is zelden het geval. De meeste motoren hebben de oorsprong in de linkerbovenhoek of de linkerbenedenhoek.

Voordat we onze berekeningen uitvoeren, moeten we onze coördinaatruimte verschuiven zodat al onze waarden relatief zijn ten opzichte van het midden van het scherm, in plaats van de standaardoorsprong die onze engine gebruikt.

Coördinatenruimte verschuiven. Punten niet op schaal.

Klinkt complex? Niet echt. We moeten alleen uitvinden hoeveel we de coördinatenruimte willen verplaatsen en die van onze doelpositie aftrekken. Dus als we ons raster de helft van de schermbreedte willen verhogen, trekken we de helft van de schermbreedte van de doelen af Y waarde.


Hier is een die ik eerder heb voorbereid

In het bovenstaande voorbeeld is de schermgrootte 800x600px, met de coördinaatruimte zo verschoven dat (0, 0) staat in het midden van de monitor. Het doel buiten het scherm is op (800, 400) dezelfde coördinaatruimte gebruiken.

Omdat de y-coördinaat van het doel positief is (en, in deze motor, de y-as naar boven wijst), weten we dat het niet aan de onderkant van het scherm staat, dus we vinden zijn positie aan de bovenkant van het scherm in eerste instantie , dat is (600, 300).

We kunnen wiskundig vertellen dat dit punt nog steeds buiten het scherm ligt, omdat het zijn x-coördinaat (600) is groter dan de helft van de breedte (800/2 = 400), dus gaan we naar de positie aan de zijkant van het scherm.

Nogmaals, we hoeven slechts één kant van het scherm te controleren, want als onze x-coördinaat positief is, moet het punt zich aan de rechterkant van het scherm bevinden. (Als het negatief was, zou het aan de linkerkant moeten zijn.)

Zodra we het punt aan de rechterkant van het scherm hebben gevonden - (400, 200) - we weten dat moet correct zijn, omdat we elke andere zijde van het scherm uitgesloten hebben door een proces van eliminatie.


Voeg een kleine streepje trigonometrie toe

Naast het plaatsen van de indicator, kunt u deze ook draaien voor extra effect, vooral als het een pijl is. Er is een handige functie die deel uitmaakt van de meeste wiskundelessen en die dit probleem vrij gemakkelijk oplost: BOOGTAN2 ().

De BOOGTAN2 () functie neemt twee parameters: een x-coördinaat en een y-coördinaat. Het geeft een hoek terug die de richting aangeeft (0, 0) naar (x, y).

 rotatie = Math.atan2 (centerMouse.top, centerMouse.left); rotatie = rotatie * 180 / Math.PI; // convert radians to degrees

Er zijn een aantal dingen waarmee u rekening moet houden BOOGTAN2 () dat kan variëren tussen talen en zoekmachines. Ten eerste zijn de argumenten vaak atan2 (y, x), terwijl de meeste andere wiskundige functies eerst de x-coördinaat nemen. Ook wordt de rotatie vaak in radialen geretourneerd in plaats van graden.

Tip: Ik zal niet ingaan op de verschillen tussen radialen en graden, behalve om te zeggen dat het eenvoudig is om van de ene naar de andere te converteren: je vermenigvuldigt gewoon de radialen met (180 / Pi) om ze in graden te veranderen en ze te vermenigvuldigen met (Pi / 180) als je ze terug wilt veranderen.


Laatste controles

Er is nog een laatste ding dat we moeten controleren voordat we een off-screen indicator maken, en dat is of ons doelwit eigenlijk buiten beeld is, omdat het niet veel zin heeft om in de richting van ons doel te wijzen als we ons doel al kunnen zien. Nogmaals, we gaan vrij eenvoudige wiskunde gebruiken om dit uit te werken.

Omdat ons scherm een ​​niet-geroteerde rechthoek is, hoeven we niets met hoeken te doen, we moeten alleen controleren of ons richtpunt lager is dan de bovenkant, hoger dan de onderkant, links van de rechterkant, en rechts van de linkerrand van het scherm.

var scherm = width: 200; height: 100 // dummy values ​​alert (isTargetOnScreen (left: 50; top: 60)); // True alert (isTargetOnScreen (left: 250; top: 10)); // Valse functie isTargetOnScreen (doel) if (target.top> 0 && target.top < screen.height && target.left < screen.width && target.left > 0) // het doelwit staat op het scherm, gebruik een overlay of doe niets. geef waar terug;  else // het doelwit bevindt zich buiten het scherm, vind indicatorpositie. return false; 

Met behulp van de dummy-waarden hierboven, zien we dat het doelwit op het scherm staat. Deze waarden kunnen overal vandaan komen waar informatie wordt opgeslagen over het object dat u bijhoudt.

Merk op dat de bovenstaande code veronderstelt dat we ons in de coördinatenruimte bevinden waar (0, 0) is in de hoek van het scherm, zoals de meeste motoren standaard hebben. Daarom moet deze stap worden uitgevoerd voordat de coördinaatruimte wordt verschoven naar het midden zoals bij het berekenen van de indicatorpositie.


Alles samenvoegen

Hier is een korte demo om deze concepten in actie te tonen (bekijk de code op GitHub):

Laten we de code eens doorlopen:

  • Eerst controleren we of het doelwit eigenlijk buiten beeld is; als het op het scherm staat, weten we al waar we de cursor moeten plaatsen, als we dat willen.
  • We veranderen de coördinatenruimte zodat de oorsprong in het midden van het scherm staat.
  • Als we naar de positie van de muis kijken, kunnen we gemakkelijk zien of deze zich in de bovenste of onderste helft van het scherm bevindt.
  • Met behulp van die informatie en algebraïsche substitutie berekenen we waar dat punt zich aan de boven- of onderkant van het scherm zou bevinden.
  • We kijken naar het punt dat we zojuist hebben berekend en controleren of het daadwerkelijk een positie op het scherm is, of dat het te ver weg is naar links of rechts.
  • Als het punt buiten beeld valt, berekenen we een nieuw punt aan de zijkant van het scherm in plaats van de boven- of onderkant.
  • We moeten nu het juiste punt in de verkeerde coördinaatruimte hebben, dus doen we het tegenovergestelde van wat we in de eerste stap hebben gedaan om het terug te brengen in het juiste coördinatensysteem.

Conclusie

Daar heb je het: een handig codefragment om toe te voegen aan de gebruikersinterface van je spel. Nu u de speler in de richting van een doelwit kunt wijzen, kunt u overwegen hoe u de afstand ook kunt weergeven.