Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Piotr Szawdyński
Inne artykuły

Jak stwierdzić, czy obiekt A jest w polu widzenia obiektu B

[artykuł] Niniejszy artykuł zawiera istotne fragmenty kodu dzięki którym można ustalić czy obiekt A jest w polu widzenia obiektu B w przestrzeni 3D.
Pisząc gry 2D lub 3D bardzo często chcemy stwierdzić czy:
  • obiekt jest w polu widzenia;
  • obiekt jest w zasięgu np. strzału.
Aby rozwiązać ten problem należy wykorzystać w tym celu kilka prostych wzorów matematycznych. Tłumaczyć wzorów nie zamierzam, więc podam funkcje, które wykonują określone operacje. Jeżeli będziesz dociekliwy sam podejmiesz ich analizę - niemniej jednak wszystkie wynikają z własności matematycznych i nie jest to jakiś mój autorski patent, więc niektóre rzeczy trzeba po prostu zaakceptować :) Jak już wspomniałem funkcje przedstawię w postaci krótkiego kodu, tak więc oto one:
C/C++
#include <cmath>

struct SPunkt3D
{
    double x;
    double y;
    double z;
};
struct SObiekt
{
    SPunkt3D pozycja;
    SPunkt3D kierunekPatrzenia;
};

double DlugoscWektora( SPunkt3D wektor )
{
    return sqrt( wektor.x * wektor.x +
    wektor.y * wektor.y +
    wektor.z * wektor.z );
}

double KatMiedzyWektorami( SPunkt3D p1, SPunkt3D p2 )
{
    double obliczenia =( p1.x * p2.x + p1.y * p2.y + p1.z * p2.z ) /( DlugoscWektora( p1 ) * DlugoscWektora( p2 ) );
    return std::acos( obliczenia ) *( 180 / M_PI ); //w stopniach
}

bool CzyWidoczny( SObiekt radar, SObiekt cel, double katWidzeniaRadaru )
{
    SObiekt oblicz = radar;
    oblicz.pozycja.x -= cel.pozycja.x;
    oblicz.pozycja.y -= cel.pozycja.y;
    oblicz.pozycja.z -= cel.pozycja.z;
    double kat = KatMiedzyWektorami( oblicz.pozycja, oblicz.kierunekPatrzenia );
    return( kat <= katWidzeniaRadaru / 2.0 );
}
To co Ciebie interesuje to de'facto funkcja CzyWidoczny(). Pierwszym argumentem jest radar czyli obiekt, który patrzy. Radar zawiera swoje położenie i kierunek patrzenia (dokładniej punkt, w który patrzy się ze swojej pozycji). Drugim argumentem jest położenie obiektu, który chcemy sprawdzić czy jest w polu widzenia radaru. Oczywiście aby funkcja była kompletna należy również określić jaki kąt widzenia jest radaru. Kąt widzenia radaru jest ostatnim argumentem funkcji. Omówiona funkcja posiada więc następujące własności:
  • ograniczony kąt widzenia;
  • nieograniczony zasięg widzenia.
Nieograniczony zasięg widzenia bardzo często nie jest pożądany tak więc wypadałoby go jakoś skrócić. Z pomocą przychodzi kolejny wzór matematyczny, który został zaimplementowany w postaci kolejnej funkcji. Oto kod:
C/C++
bool CzyW_Zasiegu( SObiekt radar, SObiekt cel, double zasieg )
{
    SObiekt oblicz = radar;
    oblicz.pozycja.x -= cel.pozycja.x;
    oblicz.pozycja.y -= cel.pozycja.y;
    oblicz.pozycja.z -= cel.pozycja.z;
    return DlugoscWektora( oblicz.pozycja ) <= zasieg;
}
Pierwsze dwa argumenty funkcji CzyW_Zasiegu() są Ci już dobrze znane. Pierwszym z nich jest radar, natomiast drugim jest cel. Ostatnim argumentem jest zasięg widzenia obiektu. Zwróć uwagę, że teraz nie interesuje nas kąt widzenia - innymi słowy funkcja sprawdza odległość dwóch podanych punktów od siebie i jeżeli są one w odległości mniejszej lub równej podanemu zasięgowi to znaczy, że jest cel w zasięgu radaru.

Jeżeli teraz chcemy sprawdzić czy obiekt jest widziany i w określonym zasięgu wystarczy wywołać dwie funkcje w następujący sposób:
C/C++
if( CzyWidoczny( obiekt1, obiekt2, 130 ) && CzyW_Zasiegu( obiekt1, obiekt2, 1000 ) )
{
    //INFO: obiekt2 jest w polu widzenia obiekt1 i jednocześnie jest w zasiegu 1000 jednostek.
    //(...) tu jakaś akcja związana z zadaniem.
}

Dodatkowo do problemu załączam rysunek, który powinien być Ci pomocny w zrozumieniu omówionego zagadnienia.