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.
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.
- Continuous: Ezt a beállítást kell alkalmazni azokre a Rigidbody-kra, amiken meg akarjuk gátolni, hogy átmenjenek a gyorsan mozgó testek.
- ContinuousDynamic: Ezt a beállítást kell alkalmazni azokre a Rigidbody-kra, amiken gyorsan mozogna.
- ContinuousSpeculative: Egyszerre használható gyorsan mozgó testekre és azokra is, amikkel ütköznek, emellett kinematikus beállításokkal is működik.
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:
Continuous és ContinuousDynamic beállítások együttes használhatóak ezzel szemben a ContinuousSpeculative Önállóan használható.
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:
// Ü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
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.
// 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
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:
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.