A játékfejlesztés vagy még általánosabban a számítógépes grafika bizonyos szempontból a geometria és a programozás találkozásánál helyezkedik el, ezért érdemes tisztában lennünk a legalapvetőbb geometriai összefüggésekkel.
Nézzük most át a derékszögű háromszögek matematikáját és felhasználásait a játékfejlesztésben!
Egy derékszögű háromszögöt a következő információk írnak le:
- Az a befogó hossza
- A b befogó hossza
- A c átfogó hossza
- Az a befogóval szembeni α (alfa) szög
- A b befogóval szembeni β (béta) szög
Ezen információkból, ha kettőt tudunk könnyedén kiszámolhatjuk a másik hármat a következő összefüggésekkel. (Kivétel ez alól, ha csak α és β szögeket ismerjük. Ekkor még legalább egy oldalhosszra szükségünk van a másik oldalak kiszámításához.)
A háromszög belső szögeinek összege: 180°
Ez nem csak a derékszögű, de minden egyéb háromszög esetén is igaz. A derékszögű háromszög ennek csak egy speciális esete, ahol a háromból ez egyik szög garantáltan 90°, így a maradék kettőre összesen jut a másik 90°.
Pitagorasz-tétel
Az egyik alapvető összefüggés, amit a derékszögű háromszögekkel kapcsolatban használunk, a Pitagorasz-tétel, amely a háromszög oldalainak hossza közti kapcsolatot mondja ki. A tétel szerint a derékszögű háromszög átfogójának négyzete egyenlő a két befogó négyzetének összegével.
Az egyenlet átalakítható úgy, hogy bármelyik oldalt meg tudjuk kapni a két másik alapján.
Emlékezzünk, hogy Unity-ben a négyzetgyök-vonást a Mathf.Sqrt
függvénnyel tudjuk megtenni szóval a fentiek a következőképp néznek ki C#-ban:
float c = Mathf.Sqrt(a*a + b*b);
float a = Mathf.Sqrt(c*c - b*b);
float b = Mathf.Sqrt(c*c - a*a);
Annak ellenére, hogy létezik hatványozó függvény Unity-ben, javaslom, hogy ilyen egyszerű esetben használjuk az szimplaszorzást. Olvashatóbb és optimálisabb is lesz a kód.
Trigonometriai függvények
6 trigonometriai függvény érdekel most minket: a szinusz, a koszinusz és a tangens valamint ezek inverz függvényei, az arkuszszinusz, az arkuszkoszinusz és az arkusztangens.
Szögfüggvény | Definíció | Mathf függvény |
Szinusz | Egy szög szinusza = szöggel szemben lévő befogó / átfogó | Mathf.Sin( ) |
Koszinusz | Egy szög koszinusza = szög melletti lévő befogó / átfogó | Mathf.Cos( ) |
Tangens | Egy szög tangense = szöggel szemben lévő bef. / szög melletti bef. | Mathf.Tan( ) |
A fenti definíciók alapján felírhatók:
Tehát a fenti 3 trigonometriai függvény akkor hasznos nekünk, ha egy fokot és egy oldal ismerünk. Ezek alapján kiszámolható a másik két oldal hossza:
a befogó hossza:
b befogó hossza:
c átfogó hossza:
// Például az alábbi kóddal "alpha" szög és a "c" átfogó alapján kiszámolhatók a befogók
float a = Mathf.Sin(alphaInRad) * c; // a oldal
float b = Mathf.Cos(alphaInRad) * c; // b oldal
A Unity trigonometriai függvényei radiánban várják a paramétert, nem fokban!
Tehát ha fokban ismertjük az alfa vagy a béta szöget először át kell váltani azt radiánba.
Ehhez a Mathf.Deg2Rad
szorzókonstans használhatjuk.
float a = Mathf.Sin(alphaInDeg * Mathf.Deg2Rad) * c; // a oldal
float b = Mathf.Cos(alphaInDeg * Mathf.Deg2Rad) * c; // b oldal
Inverz trigonometriai függvények
Ahogy korábban láttuk, ha két oldalhosszt ismerünk, akkor a Pitagorasz-tétel segítségével kiszámolható a harmadik. Mit tehetünk akkor, ha viszont minket nem a harmadik oldal hossza érdekel, hanem a szögek? A korábban megismert szögfüggvények leírták már az összefüggést a szögek és oldalak közt, ám ez önmagában nem elég akkor, ha pont egy szög érdekel minket:
Pl.: Ismerjük a-t és c-t és ismerjük a kettő közti összefüggést: . Ez alapján ki tudjuk számolni α szinuszát, de nem α- magát. Ekkor kellenek az arkusz függvények, amikor egy szög szinusza, koszinusza vagy tangense alapján meg akarjuk kapni a fokot magát.
Szögfüggvény | Definíció | Mathf függvény |
Arkuszszinusz | Egy szög szinuszának arkuszszinusza = A szög maga | Mathf.Asin( ) |
Arkuszkoszinusz | Egy szög koszinuszának arkuszkoszinusza = A szög maga | Mathf.Acos( ) |
Arkusztangens | Egy szög tangensének arkusztangense = A szög maga | Mathf.Atan( ) |
Tehát α és β szögek megkaphatók az oldalak alapján a következőképpen:
// Például az alábbi kóddal "alpha" és "béta" szögek az "a" és "c" oldalak alapján
float alphaInRad = Mathf.Asin(a/c);
float betaInRad = Mathf.Acos(a/c);
⚠️ Ne feledjük ⚠️ A Mathf
könyvtár arkusz függvényei az eredményeket szintén radiánban adják. Ha a szögeket fokban szeretnénk megkapni, át kell váltanunk a Mathf.Rad2Deg
szorzó segítségével.
float alphaInDeg = Mathf.Asin(a/c) * Mathf.Rad2Deg;
float betaInDeg = Mathf.Acos(a/c) * Mathf.Rad2Deg;
A derékszögű háromszög jelentősége a játékfejlesztésben
A 2 és 3D-ben történő programozás alapjait a vektorok képezik. A 2D vektor-ra viszont úgy is tekinthetünk, mint egy derékszögű háromszögre:
x és y komponensek a befogók, a vektor hossza az átfogó és a vízszintessel valamint a függőlegessel bezárt szögei a háromszög belső szögeivel egyeznek meg.
A fentiek alapján tehát sok esetben kiszámolhatunk egy szükséges vektort korlátolt információk alapján. Egy példa:
// Egy lövedék kezdő sebesség-vektora, az ágyú dőlésszöge és a kezdő sebesség alapján
float startSpeed = 10f; // Derékszögű háromszög "c" átfogója
float gunAngle = 45f; // A vízszintessel bezárt "alfa" szög
float x = Mathf.Sin(Mathf.Deg2Rad * gunAngle) * c; // alfával szmközti "a" oldal hossza
float y = Mathf.Cos(Mathf.Deg2Rad * gunAngle) * c; // alfa melletti "b" oldal hossza
Vector3 velocity = new Vector2(x,y); // Kész is a vektpor
A következő fejezetekben egyéb valós példákat is megismerünk: Pl.: A virtuális kamera látótere
Ha feljebb lépünk a harmadik dimenzióba, akkor is felbontható egy vektor derékszögű háromszögekre a következőképpen:
Vegyük V vektort, amit az (x, y és z) értékek írnek le descartes koordináta rendszerben.
Vh = V vektor vízszintes komponense (Vetítése a vízszintes síkra)
|V| = V vektor hossza
Ekkor Vh és y, mint befogók és |V|, mint átfogó leír egy derékszögű háromszöget. (illusztráción sárga)
Emellett x, és z, mint befogók és Vh, mint átfogó szintén leír egy derékszögű háromszöget. (illusztráción lila)
Példa a felhasználásra: Célpontkövető kamera