Marek Winiarski

Unity3d QuickTip #2 – Jak wykrywać kolizje i zdarzenia?

Unity3d QuickTip – czyli szybkie porady, rozwiązania częstych problemów i sztuczki w Unity3d!

Dzisiejszy odcinek: Jak wykrywać kolizje i zdarzenia?

Uwaga! Jest to poradnik typu QuickTip. Zatem skupia się on na osiągnięciu założonego celu. Zatem zakładamy że użytkownik zna na tyle program Unity3d, aby samodzielnie wykonać najprostsze czynności, jak np. dodanie modelu kostki do sceny czy dodanie modelowi jakiegoś komponentu. Jeżeli brakuje Ci tej podstawowej wiedzy, zapraszam do tutoriala:
Unity Tutorial – Podstawy

Teoria

W świecie Unity3d mamy 3 metody wykrywania kolizji. Warto się zapoznać z każdą z nich, ponieważ mają one różne zastosowania. Wyróżniamy 3 główne typy wykrywania kolizji:

Same kolizje są narzędziem kluczowym. Możemy ich używać dzięki komponentowi Collider (Dostępny w menu: Component->Physics). Jak łatwo można zauważyć mamy klika typów colliderów: Box, Sphere, Capsule, Mesh, Wheel, Terrain.

Nasuwa się pytanie: Jakiego typu collidera użyć? Jeżeli chodzi o kolizje zwykłe, naturalnym wyborem wydawałby się Mesh Collider. Ale jednak nie zawsze będzie to wybór najlepszy. Czemu? Bo zużywa więcej zasobów komputera.Więc jeśli mamy drzwi o wymyślnej fakturze i nałożymy na nie zwykłego box collidera, gracz nawet nie zwróci uwagi, a my zmniejszamy wymagania naszej gry. Ogólnie powinniśmy dążyć do jak największego uproszczenia kształtów colliderów.

Jeżeli chodzi o wyzwolenia. Tutaj Mesh collider również się nie sprawdzi. Ponieważ collidery tego typu są z reguły większe od samego obiektu. Jeżeli wykorzystujemy go np. do zbierania przedmiotów z ziemi, powinien być nawet przesadnie za duży, aby gracz mógł łatwo zebrać przedmiot, a nie musiał jak głupi biegać w kółko, żeby jakimś cudem trafić w nasz collider.

Collidery w scenie Unity3d oznaczone są za pomocą zielonych linii na obiekcie.

Collider i Trigger Collider w Unity3d
Collider i Trigger Collider w Unity3d

Zwykła kolizja (Collision)

Wygląd komponentu Collider

Najpierw omówmy sobie parametry naszego komponentu.

Korzystając z jednej z metod dodania komponentu, dodajemy sobie Box Collider do ustawionego na scenie obiektu (U mnie sześcian). I… właściwie tyle! Jeżeli uruchomimy grę i spróbujemy przejść przez nasz Sześcian, nie powinno nam się to udać.

Oczywiście to nie wszystko co możemy zrobić. Możemy przechwycić wydarzenia.

void OnCollisionEnter(Collision collision) {
    // Tutaj kod wykonywany po wykryciu kolizji
}

void OnCollisionStay(Collision collisionInfo) {
    // Tutaj kod wykonywany co klatkę, w czasie trwania kolizji
}

void OnCollisionExit(Collision collisionInfo) {
    // Tutaj kod wykonywany w momencie "opuszczania" kolizji
}
function OnCollisionEnter(collision : Collision) {
    // Tutaj kod wykonywany po wykryciu kolizji
}

function OnCollisionStay(collisionInfo : Collision) {
    // Tutaj kod wykonywany co klatkę, w czasie trwania kolizji
}

function OnCollisionExit(collisionInfo : Collision) {
    // Tutaj kod wykonywany w momencie "opuszczania" kolizji
}

Zdarzenie – wyzwalacz (Trigger)

Wygląd komponentu Collider

Jak łatwo zauważyć, żeby zmienić zwykły collider w wyzwalający, wystarczy zaznaczyć checkboxa Is Trigger. Zwiększyłem też rozmiar, abyśmy wykrywali wejście w obszar, zanim dotkniemy obiektu. Reszta zostaje bez zmian.

Często zdarza się że dany obiekt posiada dwa collidery. Jeden zwykły, a drugi wyzwalający. Można takie rozwiązanie zastosować np. w kodzie automatycznych drzwi. Collider wyzwalający odpowiada za to żeby drzwi się automatycznie otwierały, kiedy zwykły odpowiada za to żeby nie dało się przez nie przeniknąć.

O ile w zwykłym colliderze jego obecność jest często wystarczająca, tutaj meritum jest kod, ponieważ wyzwolenia baz kodu robiącego cokolwiek, nawet nie zauważymy.

 

void OnTriggerEnter(Collider other) {
    // Tutaj kod wykonywany po wejściu w obszar
}

void OnTriggerStay(Collider other) {
    // Tutaj kod wykonywany co klatkę, w czasie obecności obiektu w obszarze
}

void OnTriggerExit(Collider other) {
    // Tutaj kod wykonywany w momencie opuszczania obszaru
}
function OnTriggerEnter(other : Collider) {
    // Tutaj kod wykonywany po wejścia w obszar
}

function OnTriggerStay(other : Collider) {
    // Tutaj kod wykonywany co klatkę, w czasie obecności obiektu w obszarze
}

function OnTriggerExit(other : Collider) {
    // Tutaj kod wykonywany w momencie opuszczenia obszaru
}

Mamy 3 decydujące zdarzenia. Enter – wejście, Stay – w czasie, Exit – wyjście. Każda funkcja jako parametr otrzymuje obiekt typu Collider. Teraz pod zmienną other mamy obiekt, który wszedł w interakcję. Załóżmy że nasz kod przypisujemy przeciwnikowi i chcemy żeby po zauważeniu gracza, obrócił się w jego stronę. Oczywiście zauważenie to funkcja OnTriggerEnter. Teraz możemy przypisać jakiś tag naszemu graczowi i rozpoznać go po tagu:

void OnTriggerEnter(Collider other) {
    if(other.tag == "Player") {
        gameObject.LookAt(other.transform);
    }
}

Jest to prosty przykład. Ale za pomocą odpowiedniego oprogramowaniach tych zdarzeń, możemy zbudować coś w rodzaju sztucznej inteligencji dla naszych przeciwników.

Rzucanie promieni (Raycasting)

Ostatni typ odbywa się wyłącznie w kodzie. Jeżeli trzymamy się przykładu przeciwnika. W poprzednim przykładzie kod jak collider przypisany byłby do przeciwnika. Jeśli teraz tworzymy np. strzelanie, to kod z użyciem raycastingu znajdzie się w kodzie gracza.

RaycastHit hit;
if(Physics.Raycast(transform.position, transform.forward, out hit, 3)) {
    if(hit.collider.gameObject.tag == "opponent") {
        // Tutaj kod w przypadku trafienia promieniem w obiekt o tagu opponent
    }
}
var hit : RaycastHit;
if(Physics.Raycast(transform.position, transform.forward, hit, 3)) {
    if(hit.collider.gameObject.tag == "opponent") {
        // Tutaj kod w przypadku trafienia promieniem w obiekt o tagu opponent
    }
}

Najpierw tworzymy promień w postaci zmiennej hit typu RaycastHit. Następnie wykonujemy rzutowanie promienia. Dzięki temu że wstawiliśmy go w ifa, dalszy ciąg kodu wykona się tylko jeśli w coś trafiliśmy.

Szybki rzut oka na parametry funkcji Physics.Raycast():

W C# przed hit dodajemy słowo kluczowe out. Pojawia się ono dlatego, abyśmy mogli otrzymać w zmiennej dane, które uzyskała wewnątrz funkcji Physics.Raycast().

Podsumowanie

Poznaliśmy dziś 3 metody wykrywania kolizji, oraz możliwości związane z tym. Jest to jeden z najczęściej wykorzystywanych mechanizmów w środowisku Unity3d jak i ogólnie w grach. Warto jednak mądrze korzystać z tego mechanizmu żeby nie przeciążyć zasobów komputera.

Jeżeli masz jakieś pytanie zadaj je w komentarzu. :)

Exit mobile version