Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Algorytm na wykrywanie kolizji - prostokąty

Ostatnio zmodyfikowano 2013-06-04 21:02
Autor Wiadomość
Berux
Temat założony przez niniejszego użytkownika
[C++] Algorytm na wykrywanie kolizji - prostokąty
» 2013-06-04 19:39:03
Witam. Wiem, że tych tematów jest bardzo dużo, ale nie mogę znaleźć żadnego dobrego algorytmu na wykrywanie kolizji. Tylko nie odsyłajcie mnie do google, bo tam już byłem :P. Z góry dzięki.


PS Wcześniej korzystałem z tego algorytmu(Easykodera):
C/C++
bool kolizja( int x1, int y1, int s1, int w1, int x2, int y2, int s2, int w2 )
{
    if( x2 <= x1 + s1 && x2 > x1 && y2 >= y1 && y2 <= y1 + w1 ) return true; else
    if( x2 <= x1 + s1 && x2 > x1 && y2 + w2 >= y1 && y2 + w2 <= y1 + w1 ) return true; else
    if( x2 + s2 <= x1 + s1 && x2 + s2 > x1 && y2 >= y1 && y2 <= y1 + w1 ) return true; else
    if( x2 + s2 <= x1 + s1 && x2 + s2 > x1 && y2 + w2 >= y1 && y2 + w2 <= y1 + w1 ) return true;
    else return false;
   
};
Nie działa on jednak prawidłowo.
P-84844
wojownik266
» 2013-06-04 19:44:45
Bardzo prosty kod kolizji który stosowałem w sfml 1.6
C/C++
bool kolizja( float & x, float & y, float & x1, float & y1 )
{
    if( abs( x - x1 ) > 20 || abs( y - y1 ) > 20 )
         return false;
    else
         return true;
   
}
P-84845
Berux
Temat założony przez niniejszego użytkownika
» 2013-06-04 19:49:36
Nie chce coś u mnie zadziałać :(. Może coś mam w kodzie źle:

C/C++
/**Copyright by Michał Tomczyk**/
/**Prawa autorskie zastrzeżone**/

#include <cmath>
#include <SFML/Graphics.hpp>
#include <windows.h>
/************************************************************************************************/
class OBIEKT
{
public:
    float x; //pozycja obiektu w osi x
    float y; //pozycja obiektu w osi y
    int w; //szerokosc obiektu
    int h; //wysokosc obiektu
    sf::Texture textura; //textura obiektu
    sf::Sprite grafika; //grafika obiektu
};
/************************************************************************************************/
inline void ladowanieTextury( sf::Texture & tekstura, std::string sciezka )
{
    tekstura.loadFromFile( sciezka );
}
/************************************************************************************************/
bool kolizja( float & x, float & y, float & x1, float & y1 )
{
    if( abs( x - x1 ) > 20 || abs( y - y1 ) > 20 )
         return false;
    else
         return true;
   
}
/************************************************************************************************/
int main()
{
    bool czyStrzelac = false;
    bool wyswietlicWroga = true;
   
    sf::RenderWindow okno; //zdefiniowanie zmiennej, która jest oknem
    okno.create( sf::VideoMode( 800, 600, 32 ), "First game's Michał Tomczyk" ); //utworzenie okna
   
    OBIEKT stickman, wrog, luk, strzala;
   
    /**ladowanie textur**/
    ladowanieTextury( stickman.textura, "stickman.png" );
    ladowanieTextury( wrog.textura, "wrog.png" );
    ladowanieTextury( luk.textura, "luk.png" );
    ladowanieTextury( strzala.textura, "strzala.png" );
   
    /**wypelnianie grafik texturami**/
    ( stickman.grafika ).setTexture( stickman.textura );
    ( wrog.grafika ).setTexture( wrog.textura );
    ( luk.grafika ).setTexture( luk.textura );
    ( strzala.grafika ).setTexture( strzala.textura );
   
    /**przypisywanie odpowiednich wartosci metodom(pozycje w osiach, wysokosc,szerokosc)**/
    //stickman:
    stickman.w = 113;
    stickman.h = 203;
    stickman.x = 0;
    stickman.y =( 600 - stickman.h );
    //wrog:
    wrog.w = 113;
    wrog.h = 203;
    wrog.x =( 800 - wrog.w );
    wrog.y =( 600 - wrog.h );
    //luk:
    luk.w = 32;
    luk.h = 72;
    luk.x = stickman.w; //na ostatnim polu szerokosci stickmana
    luk.y =( stickman.y +( 102 - luk.h / 2 ) ); //600 - 203, to wysokosc ta sama co u stickmana |102 - na tym pixelu jest reka stickmana
    //strzala:
    strzala.w = 32;
    strzala.h = 15;
    strzala.x = stickman.w;
    strzala.y =( stickman.y +( 102 - luk.h / 2 + 32 ) ); //600 - 203, to wysokosc ta sama co u stickmana |102 - na tym pixelu jest reka stickmana|32 - na tym polu znajduje sie strzala w texturze luku
   
    /**ustalanie poczatkowych pozycji obiektow**/
    ( stickman.grafika ).setPosition( stickman.x, stickman.y ); //ustawienie sprajta na odpowiedniej pozycji
    ( wrog.grafika ).setPosition( wrog.x, wrog.y ); //ustawienie sprajta na odpowiedniej pozycji
    ( luk.grafika ).setPosition( luk.x, luk.y ); //ustawienie sprajta na odpowiedniej pozycji
    ( strzala.grafika ).setPosition( strzala.x, strzala.y ); //ustawienie sprajta na odpowiedniej pozycji
   
    /**petla glowna programu**/
    while( okno.isOpen() )
    {
        sf::Event zdarzenie;
       
        /**petla ze zdarzeniami**/
        while( okno.pollEvent( zdarzenie ) )
        {
            if( zdarzenie.type == sf::Event::Closed ||( zdarzenie.type == sf::Event::KeyPressed && zdarzenie.key.code == sf::Keyboard::Escape ) )
            {
                okno.close();
            } //zamykanie okna
           
            if( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) )
            {
                //stickman:
                ( stickman.grafika ).move( 0, - 3 );
                stickman.x += 0;
                stickman.y -= 3;
               
                //luk:
                ( luk.grafika ).move( 0, - 3 );
                luk.x += 0;
                luk.y -= 3;
               
                //strzala:
                ( strzala.grafika ).move( 0, - 3 );
                strzala.x += 0;
                strzala.y -= 3;
            } //strzałka w górę
           
            if( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) )
            {
                //stickman:
                ( stickman.grafika ).move( 0, 3 );
                stickman.x += 0;
                stickman.y += 3;
               
                //luk:
                ( luk.grafika ).move( 0, 3 );
                luk.x += 0;
                luk.y += 3;
               
                //strzala:
                ( strzala.grafika ).move( 0, 3 );
                strzala.x += 0;
                strzala.y += 3;
            } //strzałka w dół
           
            if( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) )
            {
                //stickman:
                ( stickman.grafika ).move( - 3, 0 );
                stickman.x -= 3;
                stickman.y += 0;
               
                //luk:
                ( luk.grafika ).move( - 3, 0 );
                luk.x -= 3;
                luk.y += 0;
               
                //strzala:
                ( strzala.grafika ).move( - 3, 0 );
                strzala.x -= 3;
                strzala.y += 0;
            } //strzałka w lewo
           
            if( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) )
            {
                //stickman:
                ( stickman.grafika ).move( 3, 0 );
                stickman.x += 3;
                stickman.y += 0;
               
                //luk:
                ( luk.grafika ).move( 3, 0 );
                luk.x += 3;
                luk.y += 0;
               
                //strzala:
                ( strzala.grafika ).move( 3, 0 );
                strzala.x += 3;
                strzala.y += 0;
            } //strzałka w prawo
           
            if( zdarzenie.type == sf::Event::KeyPressed && zdarzenie.key.code ==( sf::Keyboard::Space ) )
            {
                strzala.x = stickman.w;
                strzala.y =( stickman.y +( 102 - luk.h / 2 + 32 ) );
               
                ( strzala.grafika ).setPosition( strzala.x, strzala.y );
               
                czyStrzelac = true;
            } //ctrl
        } //zdarzenia
       
       
        if( czyStrzelac )
        {
            ( strzala.grafika ).move( 600, 0 );
            czyStrzelac = false;
        }
       
        if( kolizja( strzala.x, strzala.y, wrog.x, wrog.y ) )
        {
            wyswietlicWroga = false;
        }
       
        okno.clear( sf::Color( 0, 128, 0 ) ); //czyszczenie ekranu na kolor ciemno-zielony
        okno.draw( stickman.grafika ); //wyświetlenie obiektu: stickman
       
        if( wyswietlicWroga )
        {
            okno.draw( wrog.grafika ); //wyświetlenie obiektu: wróg
        }
       
        okno.draw( luk.grafika ); //wyświetlenie obiektu: łuk
        okno.draw( strzala.grafika ); //wyświetlenie obiektu: strzała
       
       
       
        okno.display(); //wyświetlanie okna
    } //pętla główna
    return 0;
} //funkcja główna (main)

/edit:
Czy ta wartość dwadzieścia to szerokość/wysokość któregoś obiektu?
P-84849
RazzorFlame
» 2013-06-04 20:04:48
Kod wojownika266 sprawdza czy odległość od pozycji jest mniejsza niż 20 (od każdej z 2 osi w 2D). Nie sprawdzi się to gdy masz inne rozmiary/wielkości obiektów. Pomyśl. Kolizja zachodzi gdy:
- prawy bok ob. A >= lewy bok ob. B
- lewy bok ob. A <= prawy bok ob. B
- dolny bok ob. A >= górny bok ob. B
- górny bok ob. A <= dolny bok ob. B
W pierwszych dwóch warunkach bierzemy pod uwagę oś X. Do obliczenia pozycji prawego boku używamy wzoru: "prawyBok = X+W" gdzie W to szerokość. Do lewego używamy samego X.
W trzecim i czwartym warunku bierzemy pod uwagę oś Y. Analogicznie jak u góry tylko wzór na dolny bok: "dolnyBok = Y+H" gdzie H to wysokość. Do górnego boku bierzemy same Y.
Oczywiście zadziała to jeżeli X i Y wskazują na prawy górny róg danego obiektu. Jeśli nie to wyznaczamy X i Y prawego górnego rogu i działamy tak jak u góry. Jeśli chcesz wykryć z którego boku nastąpiła kolizja to musisz jeszcze troche pomyśleć (podpowiedź. sprawdzaj który bok jest najbardziej zagłębiony w boku przeciwnym innego obiektu). Licze że po tych informacjach, znając instrukcje warunkowe dasz sobie rade :)
P-84854
Berux
Temat założony przez niniejszego użytkownika
» 2013-06-04 20:10:24
Dzięki za odpowiedź. Jeszcze nad tym pomyślę. Aha, mam jeszcze jedno pytanie, mianowicie czy nie prościej byłoby mi wykryć kolizję na mapie kafelkowej?
P-84856
DejaVu
» 2013-06-04 20:36:04
Każdy algorytm ma inne własności więc w zasadzie wszystko zależy od rodzaju gry jaką piszesz.

Algorytm do wykrywania kolizji - prostokąty:
http://cpp0x.pl/forum/temat/?id=8864
http://cpp0x.pl/forum/temat/?id=134
http://cpp0x.pl/forum/temat/?id=126&p=3
P-84862
Berux
Temat założony przez niniejszego użytkownika
» 2013-06-04 20:56:00
Popróbowałem z tym algorytmem, do którego dałeś linki, ale coś mi nie wychodzi :( Kolizja zachodzi, ale nie zostaje wykryta przez funkcję.

C/C++
if( kolizja( strzala.x, strzala.y, strzala.w, strzala.h, wrog.x, wrog.y, wrog.w, wrog.h ) )
{
    return 0;
}

Mimo, że kolizja zachodzi, program się nie zamyka.
P-84868
pekfos
» 2013-06-04 21:00:52
Pokaż kod funkcji kolizja().
P-84872
« 1 » 2
  Strona 1 z 2 Następna strona