A kamera koordinátarendszerei
Több féle módon tudjuk lekérni a kurzor pozícióját attól függően mire és hogyan akarjuk használni az információt. Ehhez háromféle koordinátarendszert kell megérteni. Mindegyik koordináta 3D-s.
- World Position - Világkoordináta
- Screen Position - Képernyőkoordináta
- ViewPort Poistion - VievPort koordináta
Ezt már jól ismerjük. A 3D-s tér globális koordinátarandszere.
A pozíció a játékot futtató ablakon belül pixelben megadva. Ez csak egy kamerán értelmezett.
A Screen helyvektor x és y komponense megadja az kurzor vízszintes és függőleges távolságát az ablak bal alsó sarkától pixelben megadva.
A z komponens a kamerától való távolság a Unity egységeiben mérve. Ha pont a kamera pozíciójában állunk, akkor z==0, ha 20 egységre előtte, akkor 20.
(Perspektív kamera esetén ez pont a kamerától való távolság, ortografikus kamerán azonban a távolságot csak a kamera tengelye mentén értelmezzük.)
Pozíció a játékot futtató ablakban 0 és 1 közt, ahol
viewPortPosition.x == 0
Az ablak baloldala
viewPortPosition.x == 1
Az ablak jobboldala
viewPortPosition.y == 0
Az ablak alja
viewPortPosition.y == 1
Az ablak teteje
A z komponens a Screen pozícióban is a kamera előtti távolságot adja szimpla egységekben kifejezve.
Tetszőlegesen tudunk váltani a Screen, ViewPort és World pozíciók közt. Ehhez persze ismernünk kell a Camera referenciáját.
Vector3 screenPos, worldPos, viewportPos;
Camera camera = Camera.main; // Más kamera is lehetne
//...
worldPos = camera.ScreenToWorldPoint(screenPos);
screenPos = camera.WorldToScreenPoint(worldPos);
viewportPos = camera.ScreenToViewportPoint(screenPos);
screenPos = camera.ViewportToScreenPoint(viewportPos);
worldPos = camera.ViewportToWorldPoint(viewportPos);
viewportPos =camera.WorldToViewportPoint(worldPos);
Kurzor pozíciója
…Screen pozícióban
A kurzor pozícióját legegyszerűbben Screen pozícióban kérhetjük le.
Vector3 screenPos = Input.mousePosition;
Ez egy Vector3 értékkel tér vissza, aminek x és y komponense megadja az kurzor vízszintes és függőleges távolságát az ablak bal alsó sarkától pixelben megadva.
A z komponens a Screen pozícióban a kamera előtti távolság. Ez nem állapítható meg a kurzorról, tehát az eredmény nulla lesz.
…ViewPort pozícióban
A ViewPort pozíciót a korábbi Screen pozíció alapján kérhetjük le.
Ennek megállapításához szükséges a kamera referenciája (pl.: Camera.main
).
Vector3 viewPortPos = Camera.main.ScreenToViewportPoint(screenPos);
ahol
A z komponens megint csak a kamera előtti távolság. A lekérdezés erre a tengelyre pontosan azt adja vissza a kimeneten, amit a bemeneten kapott.
…World pozícióban
A 3D-s térbeli pozíciót is a Screen pozíció alapján kérhetjük le.
Ehhez szintén kell a kamera referenciája és ezúttal a kamerától vett távolság is, amit előre be kell állítani a bemeneti változón: screenPos.z = distance;
Ezután kérhetjük le a world- azaz világkoordinátát.
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
void Update()
{
// SCREEN POSITION -------------------------
// Kurzor pozíciója a képernyőn pixelben megadva:
Vector3 screenPos = Input.mousePosition;
// Bal felső sarok: (0,0) Jobb alsó: (ablak szélessége, ablak magassága) pixelben
// VIEWPORT POSITION -------------------------
// Kurzor pozíciója a képernyőn 0-1 közötti koordinátában:
Vector3 viewPortPos = Camera.main.ScreenToViewportPoint(screenPos);
// Bal felső sarok: (0,0) Jobb alsó: (1,1)
// WORLD POSITION -------------------------
// Kurzor pozíciója a 3D térben.
screenPos.z = distance;
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
// Ha a bemeneti vektoron z == 0, akkor az eredmény pont a kameránál lesz.
// Ha z > 0 akkor a kamera síkjától előrébb z értékével.
}
Raycast
Ha azt szeretnénk tudni, hogy mely tárgyra mutat az egér és a térben mi a találkozás pozíciója azt a Raycast vagy magyarosan sugárvetés fejezetben fogjuk tárgyalni.
Az egér pozíció változása
Ha csak arra vagyunk kíváncsi, mennyit mozgott az egér az előző képfrissítés (frame) óta, akkor azt a legegyszerűbben két GetAxis
lekérdezéssel tudjuk megtenni:
float mouseDeltaX = Input.GetAxis("Mouse X"); // Vízszintes tengely
float mouseDeltaY = Input.GetAxis("Mouse Y"); // Függőleges tengely
Vector2 mouseDelta = new(mouseDeltaX, mouseDeltaY);
Az eredményt itt is képernyő koordinátában, azaz pixelben kapjuk meg.
A módszer előnye, hogy ha így kérjük le az egér mozgását, akkor mindig fogunk visszakapni nem nulla input értéket, ha az egeret fizikailag mozgatjuk. Még akkor is, amikor a kurzor nekiütközött a képernyő szélének és nem tud tovább menni.
Ezért ez a lekérdezés ideális például First és Third Person játékok kamerájának mozgatására. Ekkor általában nem is akarjuk látni a kurzort. Ezt a következő paranccsal tudjuk elérni.
Cursor.visible = false;
Ezt elég egyszer elvégezni mondjuk egy Start()
metódusban.
Kattintás lekérdezése
Kattintások állapotát hasonlóan lehet lekérdezni, mint ahogy azt a GetKey…
parancsokkal lehetett a billentyűk esetén. Lekérhető a lenyomás felengedés és lenyomva tartás.
Az alábbi metódusok mindegyike egy bool-lal tér vissza, ami igaz lesz a következő esetekben:
Input.GetMouseButtonDown(index)
Abban a frame-ben, amikor az egér gombját épp lenyomjuk.
Input.GetMouseButtonUp(index)
Abban a frame-ben, amikor az egér gombját épp felengedtük.
Input.GetMouseButtonDown(index)
Addig, amíg az egér gombját lenyomva tartjuk.
A fenti metódusok mindegyik egy int típusú (index
) paramétert vár, ami megmondja melyik egérgombot kérdezzük le:
0
- Bal egérgomb
1
- Jobb egérgomb
2
- Középső egérgomb (görgő)
3
- Bal elülső oldalgomb
4
- Bal hátsó oldalgomb
5
- Jobb elülső oldalgomb
6
- Jobb hátsó oldalgomb
Példakód:
void Update()
{
if (Input.GetMouseButtonDown(0))
Debug.Log("Pressed primary button."); // BAL egérgombot épp lenyomtuk
if (Input.GetMouseButtonDown(1))
Debug.Log("Pressed secondary button."); // JOBB egérgombot épp lenyomtuk
if (Input.GetMouseButtonDown(2))
Debug.Log("Pressed middle click."); // KÖZÉPSŐ egérgombot épp lenyomtuk
}
Az egér Unity üzenet metódusai
Képesek vagyunk kezelni bizonyos az egérrel és Collider-rel összefüggő eseményeket Unity üzenet metódusok segítségével.
Ahhoz, hogy a következő metódusokat meghívja a Unity szükséges, hogy egy 2D vagy 3D Collider hozzá legyen adva ugyanazon GameObject-hez, amin a MonoBehaviour komponensünk is szerepel.
Az események lefutása attól függ, hogy az egér milyen módon lép kapcsolatba ezen Collider-ekkel.
OnMouseEnter
- Abban a frame-ben (képkockában) egyszer, amikor az egér belép a Collider-be.
OnMouseExit
- Az első frame-ben egyszer, amikor az egér már elhagyta a Collider-t.
OnMouseOver
- Minden frame-ben addig, amíg az egér a Collider-en belül van.
OnMouseDown
- Abban a frame-ben egyszer, amikor az egér gombját épp lenyomjuk a Collider-en.
OnMouseUp
- Az első frame-ben egyszer, amikor az egér gombját már felengedtük.
OnMouseDrag
- Minden frame-ben addig, amíg az egér gombját lenyomva tartjuk.
Megjegyzések:
- A fenti metódusokat az
Update
előtt hívja meg a motor. - A fentiek akkor is működnek, ha a Collider egy trigger.
- Az
OnMouseEnter
-rel egy frame-ben le fog futni azOnMouseOver
is. - Ezzel szemben az első
OnMouseDrag
azOnMouseDown
után fut le. - Az
OnMouseUp
és azOnMouseDrag
lefutásához nem szükséges, hogy az egér még mindig a Collider felett legyen, csak akkor, mikor korábban lenyomták a gombot. - Az
OnMouseDrag
előtt lefut azOnMouseOver
is, ha az egér még mindig a Collider felett áll. - Az
OnMouseDown
,OnMouseUp
ésOnMouseDrag
csak a ball egérgombot figyeli.
Ahhoz, hogy egy másik, mondjuk a jobb egérgomb kattintás eseményeit is hasonlóan el tudjuk kapni extra kód szükséges. Erre itt láthattok egy példát:
const int mouseButtonindex = 1; // Az egérgomb index-e, amire figyelünk.
bool _rightClicked = false; // Ebben a változóban tároljuk, hogy
// a figyelt egérgomb le van-e nyomva.
void OnMouseOver()
{
if (Input.GetMouseButtonDown(mouseButtonindex )) // Manuálisan figyelünk a katt-ra
{
_rightClicked = true; // Lenyomtok a figyelt egérgombot.
OnRightMouseDown();
}
}
void Update()
{ // Az Updateben hívjuk a saját On___MouseDown-t,
if(_rightClicked ) // addíg, amíg le van nyomva a figyelt egérgomb.
{
OnRightMouseDrag();
else if (Input.GetMouseButtonUp(mouseButtonindex )) // Gomb felengedése
{
OnRightMouseUp();
_rightClicked = false;
}
}
}
void OnRightMouseDown(){ /* Saját kód */ }
void OnRightMouseDrag(){ /* Saját kód */ }
void OnRightMouseUp(){ /* Saját kód */ }
Drag&Drop
A fentiek használata elég ahhoz, hogy egy egyszerű mozgató szkriptet írjunk. Ha ezt hozzáadjuk egy GameObject-hez, akkor azt Drag&Drop módszerrel odébb tehetjük.
using UnityEngine;
public class DragAndDrop : MonoBehaviour
{
float _distance; // Az objektum távolsága a kamera előtt
Vector3 _offset; // A kurzor és az objektum közötti távolságvektor.
// Ez kell ahhoz, hogy az eltolás relatív legyen ahhoz képest, ahova kattintottunk.
void OnMouseDown() // Ha rákattintunk a Colliderre
{
// Kiszámoljuk a következő adatokat a kattintás pillanatan:
Vector3 objectWorldPosition = transform.position; // Az objektum helyzete World pozícióban
Vector3 objectScreenPosition = Camera.main.WorldToScreenPoint(objectWorldPosition); // és Screen pozícióban
Vector3 mouseScreenPosition = Input.mousePosition; // A kurzor helyzete Screen pozícióban
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(mouseScreenPosition); // és World pozícióban
// Elmentjük a következő adatokat a kattintás pillanatából:
_distance = objectScreenPosition.z; // Az objektum távolsága a kamera előtt
_offset = objectWorldPosition - mouseWorldPosition; // A kurzor és az objektum közötti távolságvektor
}
void OnMouseDrag()
{
Vector3 mouseScreenPosition = Input.mousePosition; // A kurzor helyzete World pozícióban
mouseScreenPosition.z = _distance; // A kurzor távolságt beállítása
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(mouseScreenPosition); // és World pozícióban
Vector3 objectWorldPosition = mouseWorldPosition + _offset; // Az objektum eltoolt helyzete World pozícióban
transform.position = objectWorldPosition; // Beállítjuk ezt az értéket
}
}
Érintés Input
Az okostelefonokon és táblagépeken az érintés segítségével tudjuk kontrollálni a játékunkat. Ha egyszerre csak egy érintést akarunk kihasználni, akkor használhatjuk a egér eseményeit és lekérdező függvényeit a fenti módon.
Ha több párhuzamos érintést is szeretnénk kezelni, az kissé komplikáltabb. Itt foglalkozunk vele bővebben: Érintés Input (Hamarosan)