Developedia
Developedia
Ütközés: Collider-ek és Trigger-ek

Ütközés: Collider-ek és Trigger-ek

A Collider

Ha azt szeretnénk, hogy egy GameObject-nek térbeli alakja legyen, amit nem csak megjelenít a renderer, de bármiféle hatása is van a világra, akkor egy Collider-t kell hozzáadni.

A Collider-ek a Unity fizikai rendszerének részei. A Unity-ban két egymástól teljesen független fizikai rendszer létezik, 2D és 3D. Ezért a colliderek közt is 2 kategória van:

A két rendszer közül a 3D az alapértelmezett, ha 2D-t szeretnénk használni, mindig egy extra “2D” szokott szerepeleni a megfelelő komponens vagy metódus nevében.

2D colliderek:

A 2D colliderek mindig az X-Y síkban fognak létezni. A Z koordináta elhanyagolandó, bármilyen Z pozícióval úgy működnek együtt, mintha egy síkban lennének.

BoxCollider2D
Téglalap
CircleCollider2D
Kör
CapsuleCollider2D
2D kapszula
PolygonCollider2D
Egy alakot határoz meg
CompositeCollider2D
Több PolygonCollider2D egyesítése (Gyerekekbe kell tenni a Collidereket és bejelölni, rajtuk a “Used by Composite” opciót)
EdgeCollider2D
Kiterjedés nélküli él
CustomCollider2D
Kódból vezényelhető 2D alak (Nem tárgyaljuk bővebben)
TilemapCollider2D
Speciális Collider a Tilemap rendszerhez (Nem tárgyaljuk bővebben)

A téglalappal, körrel és kapszulával a leggyorsabb a Unity-nek ütközést számolni. Ez néha nem elég az alak leírásához, akkor van szükség bonyolultabb colliderekre, mint a Polygon, Edge és a Composite Collider.

3D colliderek:

BoxCollider
Téglatest
SphereCollider
Gömb
CapsuleCollider
Kapszula
MeshCollider
MeshFilter komponenssel az objektumhoz csatolt mesh.
TerrainCollider
Domborzat Collider (Most nem tárgyaljuk)
WheelCollider
Collider kifejezettek 3D kerekekhez (Most nem tárgyaljuk)

3D-ben is a téglatesttel, gömbbel és kapszulával a leggyorsabb a Unity-nek ütközést számolni.

Colliderek interakciója

Azt hogy milyen colliderek ütközhetnek milyen colliderekkel, azt a Globális (egész projektre értendő) beállítás tartalmazza:

(Felső menüsáv / Projekt Settings / Physics vagy Physics(2D) / Layer Collision Matrix)

Itt beállítható, hogy mely layer elemei léphetnek bármiféle interakcióba melyik layer-ekkel.

icon
Layer / réteg

A layer (réteg) egy beállítás, amit egy GameObject-hez tudunk rendelni.

Minden Unity GameObject-nek kötelezően van egy és csakis egy layer-e. Egy Unity projektben maximum 32 Layer-t definiálhatunk.

Ezen kívül egyedileg is definiálhatunk kivételeket, amikor kódból megadjuk két Collider-re, hogy nem ütközhetnek:

// 3D:
Physics.IgnoreCollision(collider1, collider2);          // A két collider nem ütközhet
Physics.IgnoreCollision(collider1, collider2, false);   // A két collider újra ütközhet

// 2D:
Physics2D.IgnoreCollision(collider3, collider4);        // A két collider nem ütközhet
Physics2D.IgnoreCollision(collider3, collider4, false); // A két collider újra ütközhet

Collision Detection

A Collision Detection egy beállítás a Rigidbody-n és azt határozza meg, hogyan történjen az ütközések detektálása:

  • Discrete: Csak FixedDeltaTime-onként van egy ütközésteszt. Ezáltal gyorsan mozgó és apró testek átmehetnek detektálás nélkül a vékonyabb falakon.
  • Continous: Drágább an számítható, de az esetek nagy részében meggátolja, hogy kimaradjon az ütközés detektálása a gyorsan mozgó testekre.
    1. 3D-ben a folytonos mód csak Sphere-, Capusle- és BoxCollider-ekkel működik.

      3D-ben van két extra módja a Continous Collision Detection-nek:

    2. Continuous: Ezt a beállítást kell alkalmazni azokre a Rigidbody-kra, amiken meg akarjuk gátolni, hogy átmenjenek a gyorsan mozgó testek.
    3. ContinuousDynamic: Ezt a beállítást kell alkalmazni azokre a Rigidbody-kra, amiken gyorsan mozogna.
    4. Continuous és ContinuousDynamic beállítások együttes használhatóak ezzel szemben a ContinuousSpeculative Önállóan használható.

    5. ContinuousSpeculative: Egyszerre használható gyorsan mozgó testekre és azokra is, amikkel ütköznek, emellett kinematikus beállításokkal is működik.
    6. A ContinuousSpeculative olcsóbb (gyorsabban számolható mint) a Continuous és ContinuousDynamic beállítások, de nem mindig ad 100%-os eredményt.

      Continuous és ContinuousDynamic beállítások együttes használata adja a legjobb eredményt.

Physics material

Van kettő fontos fizikai beállítás, ami nem magán a Rigidbody-n állítható, hanem a Collider-en, egészen pontosan egy külön fájlban, amit a Rigidbody-hoz lehet csatolni. Ez a fájl a PhysicsMaterial.

Ahogy a hagyományos Material az alakzat felületének megjelenítéséről tartalmaz információkat, úgy a PhysicsMaterial a felület fizikai tulajdonságairól:

  • Súrlódás
  • Pattogósság

A 3D és a 2D fizika részben eltérően működik ezért létezik PhysicsMaterial és PhysicsMaterial2D.

A 3D PhysicsMaterial némivel több beállítást tartalmaz, a PhysicsMaterial2D pedig ráköthető a Rigidbody2D-re is, nem csak a Collider-re.

Colliderek ütközésének detektálása kódból

Két Collider ütközése kódból detektálható, ha legalább az egyik Collider-t is tartlmazó GameObject-en, szerepel egy MonoBechaviour szkript is, amiben meg van valósítva a következő életciklus metódusok egyike:

A metódusok mindegyike tartalmaz egy paramétert, amiben a fizikai motor olyan hasznos információkat ad át az ütközéssel kapcsolatban, mint pl.:

  • Mi a másik collider, amivel az ütközés történt.
  • A tér melyik pontjában történt az ütközés.
  • Mekkora vot a két test relatív (egymáshoz képesti) sebessége az ütközés pontjában.
  • …

Triggerek

3D és 2D Collidereket egyaránt használhatunk, úgynevezett trigger-ekként, ha a Collider beállításai közt bejelöljük a megfelelő chechbox-ot.

Egy trigger sosem ütközik egy másik trigger-rel vagy Collider-rel, a testek átsiklanak egymáson, viszont az egymáshoz érés kódból detektálható MonoBehaviour életciklus metódusokon keresztül.

A metódusok mindegyike tartalmaz egy paramétert, ami megadja, mi a másik collider, amivel a trigger találkozott.

Ahhoz hogy a trigger detektálás megtörténjen két GameObject egymáshoz érése esetn, a következő feltételeknek kell teljesülnie:

  • Mindkét GameObject-en van Collider komponens (mindkettő Collider vagy Collider2D)
  • Legalább az egyik Collider egy trigger.
  • Legalább az egyik GameObject-en van egy RigidBody is.
  • Legalább az egyik GameObject-en van egy MonoBehaviour szkript, ami érzékeli az ütközést.
  • A két layer közötti ütközés megengedett a Collision Matrix-on.

Physics.Overlap

Le lehet kérdezni a Unity 2D vagy 3D fizikai motorjától, hogy egy térrésszel milyen RigidBody-k vannak fedésbe a következő módokon:

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
		// Ütközések detektálása 3D-ben    
		void OnCollisionEnter(Collision other) {}			// Ha egy Collider-rel ütközi
		void OnCollisionStay(Collision other) {}			// Ha egy Collider-en belül marad
		void OnCollisionExit(Collision other) {}			// Ha egy Collider-ből kilép

		// Ütközések detektálása 2D-ben    
		void OnCollisionEnter2D(Collision2D other) {}	// Ha egy 2D Collider-rel ütközi
		void OnCollisionStay2D(Collision2D other) {}	// Ha egy 2D Collider-en belül marad
		void OnCollisionExit2D(Collision2D other) {}	// Ha egy 2D Collider-ből kilép
		// Trigger-ek detektálása 3D-ben
		void OnTriggerEnter(Collider other) {}				// Ha egy Trigger-rel ütközik
		void OnTriggerStay(Collider other) {}					// Ha egy Trigger-ren belül maradt
		void OnTriggerExit(Collider other) {}					// Ha egy Trigger-ből kilép

		// Trigger-ek detektálása 2D-ben
		void OnTriggerEnter2D(Collider2D other) {}		// Ha egy 2D Trigger-rel ütközik
		void OnTriggerStay2D(Collider2D other) {}			// Ha egy 2D Trigger-ren belül maradt
		void OnTriggerExit2D(Collider2D other) {}			// Ha egy 2D Trigger-ből kilép
Vector3 point1;
Vector3 point2;
Vector3 size;
Vector3 extents = size / 2;
float radius;
float angle;
Quaternion rotation;
LayerMask layerMask;
CapsuleDirection2D dir = CapsuleDirection2D.Horizontal;

// ... Bemenő paraméterek dehiniálása ...

// 3D lekérdezések

bool overlap1 = Physics.CheckBox(point1, extents);
bool overlap2 = Physics.CheckBox(point1, extents, rotation);
bool overlap3 = Physics.CheckBox(point1, extents, rotation, layerMask);
Collider[] colliders = Physics.OverlapBox(point1, extents);
Collider[] colliders2 = Physics.OverlapBox(point1, extents, rotation);
Collider[] colliders3 = Physics.OverlapBox(point1, extents, rotation, layerMask);

bool overlap4 = Physics.CheckSphere(point1, radius);
bool overlap5 = Physics.CheckSphere(point1, layerMask);
Collider[] colliders4 = Physics.OverlapSphere(point1, radius);
Collider[] colliders5 = Physics.OverlapSphere(point1, radius, layerMask);

bool overlap6 = Physics.CheckCapsule(point1,point2, radius);
bool overlap7 = Physics.CheckCapsule(point1, point2,layerMask);
Collider[] colliders6 = Physics.OverlapCapsule(point1, point2, radius); 
Collider[] colliders7 = Physics.OverlapCapsule(point1, point2, radius, layerMask);

// 2D lekérdezések (Egyet is le lehet kérni, de többet is)

Collider2D collider1 = Physics2D.OverlapBox(point1, size, angle);
Collider2D collider2 = Physics2D.OverlapBox(point1, size, angle, layerMask);
Collider2D[] colliders8 = Physics2D.OverlapBoxAll(point1, size, angle);
Collider2D[] colliders9 = Physics2D.OverlapBoxAll(point1, size, angle, layerMask);

Collider2D collider3 = Physics2D.OverlapCircle(point1, radius);
Collider2D collider4 = Physics2D.OverlapCircle(point1, radius, layerMask);
Collider2D[] colliders10 = Physics2D.OverlapCircleAll(point1, radius);
Collider2D[] colliders11 = Physics2D.OverlapCircleAll(point1, radius, layerMask);

Collider2D collider5 = Physics2D.OverlapCapsule(point1, point2, dir, radius);
Collider2D collider6 = Physics2D.OverlapCapsule(point1, point2, dir, radius, layerMask);
Collider2D[] colliders12 = Physics2D.OverlapCapsuleAll(point1, point2, dir, radius);
Collider2D[] colliders13 = Physics2D.OverlapCapsuleAll
                                               (point1, point2, dir, radius, layerMask);

Collider2D collider7 = Physics2D.OverlapPoint(point1);
Collider2D collider8 = Physics2D.OverlapPoint(point1, layerMask);
Collider2D[] colliders14 = Physics2D.OverlapPointAll(point1);
Collider2D[] colliders15 = Physics2D.OverlapPointAll(point1, layerMask);

Collider2D collider9 = Physics2D.OverlapArea(point1, point2);
Collider2D collider10 = Physics2D.OverlapArea(point1, point2, layerMask);
Collider2D[] colliders16 = Physics2D.OverlapAreaAll(point1, point2);
Collider2D[] colliders17 = Physics2D.OverlapAreaAll(point1, point2, layerMask);

// Azon metódusoknak, amelyeknek a visszatérési értéke nem egy tömb,
// van egy másik változata is.
// Ezen másik változat nem visszatér, hanem feltölt egy paraméterben kapott tömböt
// és a talált colliderek számát adja vissza.

Collider[] colliders18 = new Collider[10];
int overlapCount1 = Physics.OverlapBoxNonAlloc(point1, extents, colliders18);
Collider2D[] colliders19 = new Collider2D[10];
int overlapCount2 = Physics2D.OverlapCircleNonAlloc(point1, radius, colliders19);

// Ezen metódusok előnye, hogy nem hoznak létre új tömböket,
// hanem a paraméterben kapott tömböt használják.
// ezáltal elérhető, hogy új memóriafoglalás nélkül
// végezzük el a keresést sokszor egymás után.