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

[SDL, C++] Kolizja w klasie

Ostatnio zmodyfikowano 2011-12-29 22:56
Autor Wiadomość
mostrom
Temat założony przez niniejszego użytkownika
[SDL, C++] Kolizja w klasie
» 2011-12-29 22:49:33
Witam!
Napisałem sobie klasę do obsługi ludzika w grze typu Dyna. Ponieważ dążę do uniwersalności, zamieściłem tam też funkcję zwracającą kierunek, w który ludzik nie może pójść, gdy nastąpi kolizja. Męczę się już z tym drugi dzień, i za każdą próbą jestem tylko o krok od doskonałości, jednak ten krok okazuje się nie do ogarnięcia przezemnie Klasa wygląda mniej więcej tak:
C/C++
//plik nagłówkowy
class Ludek
{
public:
    void idz(); //idzie w kierunku _kierunek
    void pokaz( SDL_Surface * gdzie );
    int kolizja( SDL_Rect blok );
    void podajKierunek( int kierunek ) { _kierunek = kierunek; }
    int kierunek() { return _kierunek; }
    void update();
private:
    int _kierunek;
    int _posX;
    int _posY;
    int _wysokosc;
    int _szerokosc;
    SDL_Rect reLudek;
    SDL_Surface * surLudek;
};

C/C++
//implementacja
int Ludek::kolizja( SDL_Rect blok ) {
   
    int goraA, goraB;
    int dolA, dolB;
    int prawoA, prawoB;
    int lewoA, lewoB;
   
    goraA = _posY; goraB = blok.y;
    dolA = _posY + _wysokosc; dolB = blok.y + blok.h;
    prawoA = _posX + _szerokosc; prawoB = blok.x + blok.w;
    lewoA = _posX; lewoB = blok.x;
   
    if( dolA > goraB && goraA < dolB ) {
        if( prawoA >= lewoB && lewoA < lewoB )
             return 2; //prawo
        else
        if( lewoA <= prawoB && prawoA > prawoB )
             return 3; //lewo
       
    }
   
    if( prawoA > lewoB && lewoA < prawoB ) {
        if( dolA >= goraB && dolA < dolB )
             return 0; //dol
       
        if( goraA <= dolB && dolA > dolB )
             return 1; //gora
       
    }
    //jeśli nie występuje kolizja, zwróć neutralną liczbę
    return 5;
}

void Ludek::idz() {
    switch( _kierunek ) {
    case 0:
        reLudek.y += 1;
        break;
    case 1:
        reLudek.y -= 1;
        break;
    case 2:
        reLudek.x += 1;
        break;
    case 3:
        reLudek.x -= 1;
        break;
    default:
        break;
    }
}

C/C++
//main.cpp

SDL_Rect bloczek; //jakies tam wymiary przeszkody
while( !koniec ) {
    if( keystate[ SDLK_RIGHT ] ) {
        if( ludek.kolizja( bloczek ) != 2 )
             ludek.podajKierunek( 2 );
        else continue;
       
        ludek.idz();
    }
    if( keystate[ SDLK_LEFT ] ) {
        if( ludek.kolizja( bloczek ) != 3 )
             ludek.podajKierunek( 3 );
        else continue;
       
        ludek.idz();
    }
    if( keystate[ SDLK_UP ] ) {
        if( ludek.kolizja( bloczek ) != 1 )
             ludek.podajKierunek( 1 );
        else ludek.podajKierunek( 0 );
       
        ludek.idz();
    }
    if( keystate[ SDLK_DOWN ] ) {
        if( ludek.kolizja( bloczek ) != 0 )
             ludek.podajKierunek( 0 );
        else ludek.podajKierunek( 1 );
       
        ludek.idz();
    }
}

Nie mam pojęcia dlaczego (pewnie przez continue;), ale gdy się naciśnie naraz klawisz w górę i w dół i przy tym występuje kolizja, to moj ludek idzie w bok o jakies 20000 pixeli

Raz zamknąłem metodę Ludek::kolizja() i używałem jej w publicznej metodzie Ludek::idz(); Jednak ta metoda okazałą się doskonałą tylko dla jedenj przeszkody. Kiedy próbowałem to samo rozwiązanie zastosować do tablicy kafelków SDL_Rect mapa[13][13], to kolizja nie działałą jak należy. Dlatego podałem wyżej wymieniony kod, bo uważam że jest najbardziej czytelny; 
P-46660
malan
» 2011-12-29 22:55:29
Pytanie natury organizacyjnej: czemu zmieniłeś kolorowanie składni (po mojej poprawce)? :/
P-46662
mostrom
Temat założony przez niniejszego użytkownika
» 2011-12-29 22:56:55
Przepraszam, najwyraźniej edytowaliśmy w tym samym momencie, bo musiałem dodać kilka linijek :(

Poradziłem sobie z tym problemem, zmieniając moment wykrycia kolizji na styczne zetknięcie się powierzchni. Nowa treść funkcji Ludek::kolizja(SDL_Rect przeszkoda):
C/C++
if( prawoA > lewoB && lewoA < prawoB ) {
    if( dolA == goraB && goraA < goraB )
         return 0; //dol
   
    if( goraA == dolB && dolA > dolB )
         return 1; //gora
   
}
if( dolA > goraB && goraA < dolB ) {
    if( prawoA == lewoB && lewoA < lewoB )
         return 2; //prawo
   
    if( lewoA == prawoB && prawoA > prawoB )
         return 3; //lewo
   
}

return 5;

Teraz chciałbym całą klasę uruchomić dla mapy kafelkowej, gdzie ludek porusza się po pikselach, i nie wiem jak zamieścić odpowiednie pętle for. Narazie mam taki niepoprawnie działający algorytm

C/C++
if( keystate[ SDLK_RIGHT ] ) {
    ludek.podajKierunek( 2 );
   
    for( int y = 0; y < 13; y++ ) {
        for( int x = 0; x < 13; x++ ) {
           
            if(( x + 1 ) % 2 == 0 &&( y + 1 ) % 2 == 0 ) { // tylko dla kafelków znajdujących się od siebie nawzajem 2 kratki
                if( ludek.kolizja( mapa[ x ][ y ] ) != ludek.kierunek() ) {
                    if( x == 11 && y == 11 )
                         ludek.idz();
                   
                }
            }
           
        } //for x
    } //for y
}
Chciałbym, aby ludek się zatrzymał na przeszkodzie. Tymczasem kod powyżej zwraca kolizję tylko na chwilkę i idzie dalej.
P-46663
« 1 »
  Strona 1 z 1