Kolizje i triggery w Unity 2D


#1

Colliders & Collisions in 2D

Wstęp

Collider jest to komponent w silniku Unity pozwalający na wykrywanie kolizji pomiędzy
obiektami gry. W silniku wyróżniamy dwa różne rodzaje kolizji odpowiednie do wymiaru (2D, 3D) z jakiego korzystamy. Jak pewnie się już domyślacie tworząc grę 2D wykorzystujemy Collider2D. Komponenty typu Collider możemy podzielić ze względu na kształt:

Same kolizje dzielimy natomiast na:

  • zwykłe kolizje
  • wyzwalacze (eng. triggery)

Zanim rozpoczniemy zabawę warto wspomnieć jakie właściwości posiada komponent Collider 2D z którego będziemy zaraz korzystać:

  • isTrigger – określa czy collider jest wyzwalaczem
  • Material – fizyczny materiał pozwalający na zmianę zachowania obiektu. Obiekt z takim materiał może imitować np. gumę, metal czy drewno.
  • Size – rozmiar collidera (Box Collider 2D)
  • Radius – promień wielkości collidera (Circle Collider 2D)
  • Points – zbiór puntów wyznaczających collider (Polygon i Edge Collider 2D)
  • Offset – jego przesunięcie w osi x i y względem pozycji obiektu gry
  • Used By Effector – pozwala na używanie komponentów Effector2D np. Platform Effector 2D

Przetestujmy zatem jak zdobyta wiedza sprawdzi się w zadaniu praktycznym.

Kolizje - Ćwiczenie 1

Utwórzmy pustą scenę i dodajmy 6 obiektów typu Cube. Standardowo posiadają one komponent
BoxCollider. Usuńmy go i nałóżmy zamiast niego BoxCollider2D. Dodaj również komponent
Rigidbody2D, aby obiekty te mogły korzystać z silnika fizycznego gry.

Porada: Możesz utworzyć jeden obiekt dodać do niego wymagane komponenty a następnie zduplikować go 5 razy za pomocą skrótu klawiszowego ctrl+D. Kiedy mamy już boxy ustaw je w ten sposób.

Po uruchomieniu gry zauważysz, że obiekty spadają w dół. To właśnie dzięki komponentowi Rigidbody2D odziałuje na nie siła grawitacji. Spróbujmy dodać teraz nowy cube, z Colliderem2D, który będzie emitował podłogę i ustawmy jego pozycję na (0,-3,0) oraz skalę na (200,1,1). Po uruchomieniu gry widzimy jak spadające obiekty zatrzymują się na naszej podłodze, dokładniej mówiąc pudełka wchodzą w kolizję z podłogą. Sprawdźmy teraz co dokładnie dzieje się dodając skrypt o nazwie Floor.cs. Jednak zanim to zrobimy warto wspomnieć, że kolizje posiadają 3 zdarzenia:

  • OnCollisionEnter2D – wyzwalane podczas rozpoczęcia kolizji między
    obiektami
  • OnCollisionStay2D – wyzwalane w trakcie trwania kolizji między
    obiektami
  • OnCollisionExit2D – wyzwalane w trakcie zakończenia kolizji między
    obiektami.

Sprawdźmy jak powyższe zdarzenia sprawdzą się w praktyce. Dodajmy do skryptu Floor.cs metodę, która wyświetli nam nazwę obiektu rozpoczynającego kolizję z podłogą wykorzystując do tego zdarzenie OnCollisionEnter2D:

void OnCollisionEnter2D(Collision2D col)
{
     Debug.Log(col.collider.name);
}

Po uruchomieniu gry w konsoli (możemy ją włączyć: Windows->Console) widzimy log, który wyświetla nazwy trzech cube’ów – dokładniej mówiąc dolnej warstwy naszej konstrukcji, która weszła w kolizję z podłogą.

Spróbujmy teraz przetestować pozostałe zdarzenia. W tym celu przerobimy naszą podłogę w wyrzutnię. Do tego będziemy potrzebowali tylko jeden box na naszej scenie. Następnie dodajmy do skryptu pozostałe zdarzenia oraz metodę wyrzucającą obiekt w powietrze. Cały skrypt powinien wyglądać następująco:

using UnityEngine;
using System.Collections;

public class Floor : MonoBehaviour{
     Rigidbody2D r2d;

     void OnCollisionEnter2D(Collision2D col)
     {
          Debug.Log("START kolizji " + col.collider.name);
          r2d = col.rigidbody;
          r2d.velocity = Vector2.zero;
          Invoke("AddForce", 2.0f);
     }

     void OnCollisionStay2D(Collision2D col)
     {
          Debug.Log("KOLIDUJĘ " + col.collider.name);
     }

     void OnCollisionExit2D(Collision2D col)
     {
          Debug.Log("STOP kolizji " + col.collider.name);
     }

     void AddForce()
     {
          r2d.AddForce( new Vector2(0, 600) );
     }
}

Po uruchomieniu gry widzimy, że przy starcie kolizji box wytraca swoją prędkość a następnie dzięki metodzie Invoke rozpoczyna się 2 sekundowe odliczanie, które spowoduje uruchomienie metody AddForce(). W tym czasie nasz obiekt przebywa w stanie OnCollisionStay2D. Przy wystrzeleniu jest uruchomione zdarzenie OnCollisionExit2D, gdyż obiekt przestaje kolidować z innym elementem. Poprawne działanie kolizji możemy zaobserwować dzięki logom w konsoli, która wyświetla obecny stan kolizji.

Całe wyżej opisane ćwiczenie znajduję się w niżej dołączonym projekcie w scenie Kolizje w folderze _Scenes.

Triggery - Ćwiczenie 2

Kolejnym typem kolizji są wyzwalacze. Aby nasz collider stal się wyzwalaczem musi mieć
zaznaczoną opcję isTrigger, którą znajdziemy w Inspektorze. Obiekty które są triggerem nie wchodzą z innymi z colliderami w zwykłe kolizje omówione w poprzednim przykładzie. Ponadto obiekty mogą przez nie przenikać.

Uwaga: I tu ważna informacja aby inny obiekt mógł aktywować wyzwalacz musi posiadać
komponent Rigidbody2D.

Na potrzeby tego przykładu wykorzystajmy postać gracza, którą znajdziemy w standardowych assetach oferowanych przez Unity. Zaimportujmy teraz paczkę (Unity Package) którą znajdziemy w Assets->Import Package->2D. Następnie z folderu Standard Assets/2D/Prefabs przenieśmy prefab CharacterRobotBoy na naszą scenę. Ustawmy jego pozycję na (0,0,0) oraz skalę na (1,1,1). Jak możesz zauważyć nasza postać posiada już komponenty Box, Circle Collider 2D oraz Rigidbody 2D. Dodajmy również podłogę tak jak w poprzednim przykładzie.

Udało się ! Mamy więc postać oraz podłoże, czas uruchomić grę i sprawdzić jak prezentuje się całość. Po uruchomieniu, widzimi jak robot zatrzymuje się na platformie – kolizje omówione wyżej działają poprawnie.

Sprawdźmy teraz różnicę między colliderem z triggerem oraz bez triggera. Dodajmy w tym
celu dwa cube’y na naszą scenę. Ponadto dodamy komponent BoxCollider2D tak jak to robiliśmy poprzednio. Pierwszemu z nich przypiszmy wartość isTrigger. Następnie umieśćmy je w naszej scenie jak na screenie poniżej:

Włączmy naszą grę i spróbujmy przejść bohaterem przez ściany. Jak zaobserwujesz bohater przenika przez ścianę z triggerem zaś druga go zatrzymuje. Triggerów możemy używać np. jako przełączników w grze, które uruchamiają pewne interakcje lub zdarzenia. Podobnie jak w przypadku kolizji triggery posiadają 3 zdarzenia:

  • OnTriggerEnter2D – wywoływana, gdy obiekt wchodzi do wyzwalacz
  • OnTriggerStay2D – wywoływana, gdy obiekt pozostaje w wyzwalaczu
  • OnTriggerExit2D – wywoływania, gdy obiekt opuszcza wyzwalacz.

Utwórzmy teraz minigrę zadaniem gracza będzie otworzyć drzwi przełącznikiem. Cube z triggerem
bedzie przełącznikiem zaś drugi cube zostanie drzwiami. Dodajmy jeszcze platformę na którą musi
wskoczyć gracz aby wcisnąć przełącznik. Platforma wygląda tak jak na screenie poniżej.

Posiada ona komponent BoxCollider2D oraz dodatkowo ma zaznaczoną opcję Used By Effector
oraz dodany komponent Platform Effector 2D. W Platform Effector 2D mamy zaznaczoną opcję
Use One Way – pozwala ona na wskakiwanie na platformy “od dołu” tak jak w wielu klasycznych
platformówkach. Bez tego komponentu normalnie plarforma blokowała by naszego bohatera
podczas wskakiwania.

Spróbujmy teraz uruchomić grę, wskoczyć na platformę i wejść w nasz wyzwalacz (trigger). Jak pewnie zauważysz nic się nie dzieje. Jest to spowodowane brakiem skryptu obsługującego naszą akcję. Dodajmy zatem skrypt Trigger do naszego wyzwalacza. W skrypcie będziemy poprzebowali referencji do naszych drzwi. Dodajmy publiczną zmienną Transform do skryptu a następnie przeciągnij drzwi do skryptu w obiekcie Switch.

Dodajmy teraz zdarzenia OnTriggerEnter2D oraz OnTriggerExit2D. Jak możesz zauważyć w odróżnieniu od metod OnCollision argumentem jest tu Collider2D a nie Collision2D. W metodzie OnTriggerEnter2D będziemy otwierać gry a po opuszczeniu triggera w OnTriggerExit2D – będziemy je zamykać. Cały skrypt powinien wyglądać następująco:

public class Trigger:MonoBehaviour{
     public Transform door;

     void OnTriggerEnter2D(Collider2D col)
     {
          door.transform.position = new Vector3(3.85f, 2f, 0);
     }

     void OnTriggerExit2D(Collider2D col)
     {
          door.transform.position = new Vector3(3.85f, 0, 0);
     }
}

Po uruchomieniu widzimy, że wszystko działa jak trzeba lecz niestety nie mamy możliwości
otworzenia drzwi na stałe gdyż po opuszczeniu przełącznika drzwi zamykają się. Musimy wspomóc
bohatera. Uwórzmy boxa, który bohater będzie musiał przesunąć na nasz przełącznik. Ustawmy Boxa w pozycji (-1,1,0) dodaj do niego komponenty Box Collider 2D oraz Rigidbody 2D. Aby pudełko bardziej kleiło się do podłoża i nie wypadło z platformy dodajmy do jego collidera materiał fizyczny Sticky. Znajdziesz go w folderze Standard Assets/2D/PhysicsMaterials. Dodatkowo w
komponencie Rigidbody2D zwiększ masę obiektu do 50. Uruchom grę teraz możesz przesunąć
pudełko i przejść przez drzwi. Świetna robota! Cały przykład znajdziesz w scenie Triggery w
folderze _Scenes.

Zakończenie

Powyższy artykuł jest jedynie wstępem do komponentów kolizji jakie oferowane są w Unity. Jeśli chciałbyś poszerzyć swoją wiedzę rozpocznij od odwiedzenia poniższych stron, na pewno będzie to dobry kolejny krok w kierunku tworzenia gier.

Powodzenia !

Materiały do artykułu: Colliders&Collisions.zip (5.4 MB)