Detekcja kolizji – podstawy

Sierpień 29th, 2010

Detekcja kolizji jest jedną z fundamentalnych części wielu różnych aplikacji, w tym gier komputerowych. Nachodzenie na siebie obiektów jest często bowiem niepożądanym stanem. System wykrywania i naprawiania kolizji odpowiadać ma w swoim zamierzeniu za zapewnienie poprawnego i stabilnego stanu gry, wymuszając odpowiednie zachowanie obiektów w momencie wzajemnej interakcji. W grach komputerowych uniemożliwia postaciom przechodzenie przez ściany czy też upadanie poniżej poziomu podłogi. Dostarcza także możliwości takie, jak odpowiedź na pytanie czy jeden użytkownik może zobaczyć drugiego, bądź czy jest w zasięgu strzału wroga.

Wśród wszystkich problemów występujących w grach 3D, te odnoszące się do kolizji obarczone są najbardziej krytycznymi ograniczeniami czasowymi. W związku z tym stosuje się specjalne algorytmy do wykrywania kolizji pomiędzy nimi oraz wprowadza się pewne usprawnienia przyspieszające ich wykrywanie, takie jak struktury opisujące podział przestrzeni.

W skrócie: w grach, wykrywać można kolizje na wiele sposobów, w zależności od stopnia jej szczegółowości. Najczęściej opakowuje się obiekty w jakieś prostsze odpowiedniki typu sfera lub prostopadłościan i wykrywa kolizje jedynie dla nich (czas testu jest wtedy stały i nie zależy od stopnia skomplikowania siatki). Dla zobrazowania faktu, wklejam przykład z pewnej gry:

Okazuje się, że XNA wychodzi nam naprzeciw i dostarcza wiele spośród rozwiązań w swoim frameworku! Istnieją struktury i istnieją metody, które upraszczają wykrywania kolizji i to bardzo (wiem to, bo pisałem pracę magisterską z detekcji kolizji i mocno się namęczyłem implementując te algorytmy). W szczególności, w XNA każdy model zbudowany jest z modeli siatek (ModelMesh), które posiadają jako propertę BoundingSphere (sferę otaczającą daną siatkę).

Ja system detekcji kolizji zaimplementowałem zatem w swoim GameObjectsManagerze (dla przypomnienia jest to GameComponent) bardzo szybko. Patrząc przyszłościowo … zdefiniowałem najpierw interfejs wykrywający kolizję:

public interface ICollisionDetector
{
     //zwraca true, gdy pomiędzy dwoma obiektami gry istnieje kolizja
     bool DetectCollision(GameObject obj1, GameObject obj2, double tolerance);
}

i zaimplementowałem póki co detektor wykrywający kolizje na sferach:

public bool DetectCollision(GameObject obj1, GameObject obj2, double tolerance)
{
    //porównuje tutaj każdą z siatek każdego z dwóch obiektów
    foreach (ModelMesh mesh1 in obj1.Model.Meshes)
    {
        foreach (ModelMesh mesh2 in obj2.Model.Meshes)
        {
            //pobieram sferę z siatki
            BoundingSphere bs1 = mesh1.BoundingSphere;
            //...i muszę jeszcze przesunąć i przeskalować ją
            // zgodnie z reprezentacją (dla sfery wystarczy pozycja i skala)
            bs1.Center = obj1.Position;
            bs1.Radius *= obj1.Scale;
           
            BoundingSphere bs2 = mesh2.BoundingSphere;
            bs2.Center = obj2.Position;
            bs2.Radius *= obj2.Scale;
            //wreszcie metoda Intersects z frameworka XNA
            //(która może przyjmować też kilka innych ciekawych argumentów!)
            if (bs1.Intersects(bs2))
            {
                return true;
            }
        }
    }
    return false;
}

Ostatecznie, wystarczy wykorzystać go w GameObjectsManagerze w metodzie Update:

public override void Update(GameTime gameTime)
{
    foreach (GameObject obj in this.gameObjects)
    {
        //narazie, sprawdzam tylko kolizje z aktualnie poruszanym obiektem
        if (obj != this.activeObject)
        {
            if (sphereCollisionDetector.DetectCollision(obj, this.activeObject, 0))
            {
                 //tutaj kod odpowiadający przypadkowi, gdy zachodzi kolizja!
                 //może jakiś dźwięk zderzenia:)?
            }
        }
    }
    base.Update(gameTime);
}

Naprawdę wszystko dostarczone prawie jak na tacy. Jeśli chodzi o sytuację na scenie… mój helikopter już nigdy nie zderzy się niepostrzeżenie z samochodem, choć oczywiście tylko w przybliżeniu, co na daną chwilę graczom w zupełności wystarcza…

Comments are closed.