În jocurile de defilare 2D (și unele jocuri 3D), adesea trebuie să arătați jucătorului locația unei ținte aflate în afara ecranului, indiferent dacă este vorba despre un inamic, un aliat sau un obiectiv de joc. Multe jocuri folosesc o săgeată care plutește aproape de marginea ecranului pentru a indica direcția în care se află ținta. În acest tutorial, voi explica o metodă care utilizează algebra simplă pentru a găsi unde să plasați o astfel de săgeată indicator.
Forma de intersecție a pantei este o modalitate de a descrie o linie dreaptă în 2D cu algebră liniară. Folosește a pantă, care utilizează în mod normal simbolul m
, care definește abrupta liniei și a ofset sau intercepta, care utilizează simbolul b
, care definește unde linia traversează axa y.
\ [y = mx + b \]
Datorită acestei relații, dacă avem o valoare, putem folosi ecuația generală pentru a calcula cu ușurință cealaltă valoare, atât conceptual cât și matematic.
Din moment ce găsim poziția față de ecran - o suprafață plană - facem toate calculele în 2D, chiar dacă jocul este în 3D.
Bacsis: Dacă lucrați în 3D, va trebui să transformați locația lumii în locația ecranului obiectului dvs. 3D. Majoritatea motoarelor mainstream au construit funcții pentru a face acest lucru; consultați documentația motorului pentru mai multe informații.
Dacă găsim o linie pe ecran care descrie în ce direcție se află obiectul pe care îl vizăm, putem determina punctul în care traversează orice margine dată și apoi folosiți un mic test și o eroare pentru a afla care parte a ecranului va fi atasat la.
Dacă ne imaginăm că ecranul nostru este pe o rețea și că punctul de origine (0, 0)
este exact în centrul ecranului, apoi este ușor să calculați valorile care descriu linia.
De când linia va trece prin centru, știm că interceptarea noastră, b
, trebuie să fie zero. Și dacă grila este așezată astfel, putem calcula foarte ușor panta, m
: este pur și simplu țintă y
/X
. (În imaginea de mai sus, ținta noastră este cursorul mouse-ului.)
Odată ce avem panta, putem folosi substituția pentru a calcula unde linia ar trece frontierele ecranului. De exemplu, dacă vrem să găsim ceea ce este valoarea y în punctul în care linia traversează marginea ecranului, atunci folosim formularul original y = mx
, Unde X
este setat la marginea ecranului. Dacă vrem să găsim locul în care traversează partea de sus sau de jos a ecranului, împărțim ambele părți m
astfel încât ecuația devine: x = y / m
- apoi am stabilit y
la marginea ecranului.
În timp ce grila este plasată în acest mod, marginea ecranului ar fi jumătate din lățimea ecranului, negativă pentru stânga și pozitivă pentru dreapta. Pentru axa verticală, în mod similar, marginea ecranului este la jumătatea înălțimii sale, dar dacă poziția pozitivă sau negativă poate varia între motoare.
Deci, un joc de 800x600px va avea marginea ecranului la x = -400px
, x = + 400px
, y = -300px
, și y = + 300px
.
Cele de mai sus ar fi bine dacă originea sistemului de coordonate ar fi centrul ecranului, dar acest lucru este rar. Cele mai multe motoare au originea fie în stânga sus, fie în colțul din stânga jos.
Înainte de a face calculele noastre, trebuie să ne schimbăm spațiul coordonat, astfel încât toate valorile noastre să fie relativ la centrul ecranului, mai degrabă decât originea implicită utilizată de motorul nostru.
Schimbarea spațiului coordonat. Punctele nu trebuie scalate.Sunet complex? Nu chiar. Trebuie doar să aflăm cât dorim să mutăm spațiul de coordonate și să scădem din poziția țintă. Deci, dacă vrem să mutăm grilajul până la jumătate din lățimea ecranului, scădem jumătate din lățimea ecranului de la țintă y
valoare.
În exemplul de mai sus, dimensiunea ecranului este 800x600px, cu spațiul de coordonate mutat astfel încât să fie (0, 0)
este în centrul monitorului. Tinta din afara ecranului este la (800, 400)
utilizând același spațiu de coordonate.
Deoarece coordonata y a țintă este pozitivă (și, în acest motor, axa y indică în sus), știm că nu va fi pe marginea inferioară a ecranului, așa că găsim inițial poziția sa de-a lungul marginii superioare a ecranului , care este (600, 300)
.
Putem spune matematic că acest punct este încă în afara ecranului deoarece coordonatele lui x (600
) este mai mare de jumătate din lățime (800/2 = 400
), deci ne mutăm pe găsirea poziției sale pe partea laterală a ecranului.
Din nou, trebuie doar să verificăm o parte a ecranului, deoarece dacă coordonatele noastre x sunt pozitive atunci punctul trebuie să fie în partea dreaptă a ecranului. (Dacă ar fi negativ, ar trebui să fie în partea stângă.)
Odată ce găsim punctul din partea dreaptă a ecranului - (400, 200)
- știm asta trebuie sa fiți corecți, deoarece am eliminat fiecare parte a ecranului printr-un proces de eliminare.
Pe lângă poziționarea indicatorului, poate doriți să îl rotiți și pentru un efect suplimentar, mai ales dacă este o săgeată. Există o funcție utilă care face parte din majoritatea claselor de matematică care rezolvă cu ușurință această problemă: atan2 ()
.
atan2 ()
funcția are doi parametri: o coordonată x și o coordonată y. Se întoarce un unghi care indică direcția de la (0, 0)
la (X y)
.
rotație = Math.atan2 (centerMouse.top, centerMouse.left); rotație = rotire * 180 / Math.PI; // convertiți radianele în grade
Există câteva lucruri pe care trebuie să le țineți cont atan2 ()
care pot varia între limbi și motoare. În primul rând, argumentele sunt deseori atan2 (y, x)
, în timp ce majoritatea celorlalte funcții de matematică iau mai întâi coordonatele x. De asemenea, rotația este adesea returnată în radiani mai degrabă de grade.
Bacsis: Nu voi intra în diferențele dintre radiani și grade, cu excepția faptului că convertirea de la unul la celălalt este ușoară: trebuie doar să multiplicați radianele prin (180 / Pi)
pentru a le transforma în grade și pentru a le multiplica (Pi / 180)
dacă doriți să le schimbați înapoi.
Există un ultim lucru pe care trebuie să-l verificăm înainte de a face un indicator de pe ecran, și anume dacă ținta noastră este de fapt pe ecran, deoarece nu prea are sens să ne îndreptăm direcția țintă dacă putem vedea deja ținta noastră. Din nou, vom folosi matematica destul de simplă pentru a rezolva această problemă.
Din moment ce ecranul nostru este un dreptunghi netratat, nu trebuie sa facem nimic cu unghiuri, trebuie doar sa verificam daca punctul tinta este mai mic decat partea de sus, mai mare decat partea de jos, la stanga marginii drepte, și în partea dreaptă a marginii din stânga a ecranului.
var ecran = lățimea: 200; înălțimea: 100 // valorile false alert (isTargetOnScreen (left: 50; top: 60)); // Alertă adevărată (isTargetOnScreen (left: 250; top: 10)); // Funcția falsă esteTargetOnScreen (țintă) if (target.top> 0 && target.top < screen.height && target.left < screen.width && target.left > 0) // țintă este pe ecran, folosește o suprapunere sau nu face nimic. return true; altceva // țintă este off-screen, găsiți poziția indicatorului. return false;
Folosind valorile fictive de mai sus, constatăm că țintă este pe ecran. Aceste valori pot veni de oriunde stochează informații despre obiectul pe care îl urmăriți.
Rețineți că codul de mai sus presupune că suntem în spațiul de coordonate unde (0, 0)
este in colţ a ecranului, așa cum majoritatea motoarelor vor avea în mod implicit. Prin urmare, acest pas trebuie făcut înainte de a schimba spațiul de coordonate în centru, așa cum facem atunci când se calculează poziția indicatorului.
Iată un demo rapid pentru a arăta aceste concepte în acțiune (vizualizați codul pe GitHub):
Să mergem prin cod:
Acolo îl aveți: un fragment de cod la îndemână pentru a adăuga la interfața de utilizator a jocului. Acum, că puteți îndrepta playerul în direcția unei ținte, luați în considerare modul în care puteți afișa și distanța.