Developedia
Developedia
Kamera tér és egér input

Kamera tér és egér input

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.

  1. World Position - Világkoordináta
  2. Ezt már jól ismerjük. A 3D-s tér globális koordinátarandszere.

  3. Screen Position - Képernyőkoordináta
  4. 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.)

  5. ViewPort Poistion - VievPort koordináta
  6. 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);

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 RaycastRaycast 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:

image

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 az OnMouseOver is.
  • Ezzel szemben az első OnMouseDrag az OnMouseDown után fut le.
  • Az OnMouseUp és az OnMouseDrag 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 az OnMouseOver is, ha az egér még mindig a Collider felett áll.
  • Az OnMouseDown, OnMouseUp és OnMouseDrag 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:

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.

É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)Érintés Input (Hamarosan)

Logo

Főoldal

Blog

Elmélet

3D Studio

Adatvédelmi nyilatkozat

GY.I.K.

Házirend

Szerző: Marosi Csaba / marosi.csaba@3d-studio.hu

DiscordGitHubLinkedIn
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.
}
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 */   }
 
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
	}
}