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ę:
{
//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:
{
//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:
{
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…
