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

[C++, allegro] Ludek zacina się po kolizji z przeszkodą

Ostatnio zmodyfikowano 2012-09-10 10:28
Autor Wiadomość
kubawal
Temat założony przez niniejszego użytkownika
[C++, allegro] Ludek zacina się po kolizji z przeszkodą
» 2012-09-07 21:27:50
Witam oto kod:
C/C++
#include <allegro.h>

inline int randint( int max ) { return rand() % max; }
inline int randint( int min, int max ) { return randint( max - min ) + min; }

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;
   
};
END_OF_FUNCTION();

void Game();

int main( void )
{
    allegro_init();
    install_keyboard();
    set_color_depth( 16 );
    set_gfx_mode( GFX_AUTODETECT_WINDOWED, 600, 600, 0, 0 );
    set_palette( default_palette );
    clear_to_color( screen, makecol( 255, 0, 255 ) );
   
    Game();
   
    allegro_exit();
    return 0;
}
END_OF_MAIN();

void Game()
{
    BITMAP * bufor = NULL;
    BITMAP * przeszkoda = NULL, * ludek = NULL;
    int ludekX = 300, ludekY = 300;
    int przeszkodaX, przeszkodaY;
   
    bufor = create_bitmap( 600, 600 );
   
    ludek = load_bmp( "C:\\lib\\ludek.bmp", default_palette );
    przeszkoda = load_bmp( "C:\\lib\\przeszkoda.bmp", default_palette );
    if( !ludek || !przeszkoda || !bufor )
    {
        set_gfx_mode( GFX_TEXT, 0, 0, 0, 0 );
        textout_ex( screen, font, "Nie udało się załadować bitmap", 0, 0, makecol( 0, 0, 0 ), 0 );
        rest( 5000 );
    }
   
    przeszkodaX = randint( 0, 600 - przeszkoda->w );
    przeszkodaY = randint( 0, 600 - przeszkoda->h );
   
    while( !key[ KEY_ESC ] )
    {
        clear_to_color( screen, makecol( 255, 0, 255 ) );
        //przesuwanie
        if( !kolizja(
        ludekX, ludekY, ludek->w, ludek->h, przeszkodaX, przeszkodaY, przeszkoda->w, przeszkoda->h ) )
        {
            if( key[ KEY_UP ] ) ludekX++;
           
            if( key[ KEY_DOWN ] ) ludekX--;
           
            if( key[ KEY_RIGHT ] ) ludekY++;
           
            if( key[ KEY_RIGHT ] ) ludekY--;
           
        }
       
        //rysuj ludka i przeszkodę na buforze
        masked_blit( ludek, bufor, 0, 0, ludekX, ludekY, 800, 800 );
        masked_blit( przeszkoda, bufor, 0, 0, przeszkodaX, przeszkodaY, 800, 800 );
       
        //kopiuj na ekran
        blit( bufor, screen, 0, 0, 0, 0, 800, 800 );
       
        rest( 20 );
    }
   
    //usuń niepotrzebne
    destroy_bitmap( ludek );
    destroy_bitmap( przeszkoda );
    destroy_bitmap( bufor );
   
}
END_OF_FUNCTION();

Problem jest taki, że ludek po wjechaniu na przeszkodę zacina się. Wiem że to skutek tego, że gdy koliduje z przeszkodą,
nie zbiera zdarzeń z klawiatury. Aby móc go np. cofnąć muszę znać, z którego boku przeszkody(przeszkoda to zwykły kwadrat) uderzyłem.
No i właśnie nie wiem jak to zrobić.
Proszę o pomoc.
P-64542
diego997
» 2012-09-08 12:23:15
Wiesz kiedyś sam miałem z tym problem pewnie są inne rozwiązania co do kolizji ale znam tylko jedno.

Masz dwie klasy Player i Enemy w klasie Enemy dodatkowo trzymasz zmienną:

C/C++
int edge;

która przyjmuje wartości załóżmy od 1 do 4 (kwadrat ma 4 boki)

Spójrz na screen poniżej powinno się nieco rozjaśnić, tzn powinieneś załapać sens jak nie to pytaj :D Chyba że ktoś widzi jakieś przeciwskazania co do tego sposobu to niech napisze :)

Screen: http://imageshack.us/photo/my-images/840/screenlal.png/



Podczas sprawdzania kolizji najpierw wykrywane są te linie jeżeli edge = 1 to znaczy że klocek jest po lewej stronie i kiedy faktycznie dojdzie miedzy nimi do kolizji to wiadomo że z lewej strony :D
P-64567
RazzorFlame
» 2012-09-08 14:43:14
A może dlatego że kiedy wjedzie w przeszkode to już z niej nie wyjdzie :)

Edit:
diego a gdyby był 5 kątny hmm? Wiem że wszystko da się zrobić ale takie rozwiązanie moim zdaniem jest bardzo ciężkie do napisania. Już chyba lepiej by było trzymać w vectorze linie (2 punkty na 1 linie ofc).

Edit x2:
LooooooooooooooooL ja sie pomyliłem i myślałem że akwes nade mną napisał WTF xd
P-64571
diego997
» 2012-09-08 15:28:44
@Razzor masz racje to jest "dobre" rozwiązanie tylko w przypadku czworokąta ;p Gdybym miał inną figurę to nie wiem. Wykrywanie kolizji to jedna sprawa a odpowiednie zareagowanie to druga ;p
P-64576
kubawal
Temat założony przez niniejszego użytkownika
» 2012-09-10 10:28:05
Dzięki Diego!
Zrobiłem to tak:
Są zmienne opisujące pozycje wszystkich wierzchołków obiektu o nazwach: o1, o2, o3, o4.
Są też zmienne opisujące pozycje wierzchołków bitmapy ludka o nazwach: p1, p2, p3, p4.
I teraz sprawdzam czy: p3 lub p4 nie koliduje z linią o1-o2, p4 lub p1 z linią o2-o3, p1 lub p2 z linią o3-o4, p3 lub p4 z linią o4-o1.

Oto kod:

Kolizje.h:
C/C++
#include <allegro.h>
#include <string>

using namespace std;


inline int randint( int max ) { return rand() % max; }

inline int randint( int min, int max ) { return randint( max - min ) + min; }

#define K_1_2 1
#define K_2_3 2
#define K_3_4 3
#define K_4_1 4
#define K_NOT 0

bool kolizja( int x1, int y1, int s1, int w1, int x2, int y2, int s2, int w2 );



class Object
{
   
public:
    int X, Y;
    int W, H;
    BITMAP * bmp;
   
    Object( string name, int xX = 0, int yY = 0 )
        : bmp( load_bmp( name.c_str(), default_palette ) )
        , X( xX )
        , Y( yY )
        , W( bmp->w )
        , H( bmp->h )
    { }
   
    virtual bool collision( Object & o );
};

class Enemy;

class Player
    : public Object
{
    struct Pos // struktura pomocnicza dla funkcji edges()
    {
        int x, y;
        Pos( int xx, int yy )
            : x( xx )
            , y( yy )
        { }
    };
    int edges( Object & o );
public:
    int HP;
    int edge;
   
    Player( string name = "ludek.bmp", int xX = 300, int yY = 300 )
        : Object( name, xX, yY )
        , HP( 100 )
        , edge( 0 )
    { }
   
    bool collision( Object & o );
};

class Enemy
    : public Object
{
    Enemy( string name = "przeszkoda.bmp", int xX = - 1, int yY = - 1 )
        : Object( name )
    {
        if( xX = - 1 )
             X = randint( 0, 600 - W );
        else
             X = xX;
       
        if( yY = - 1 )
             Y = randint( 0, 600 - H );
        else
             Y = yY;
       
    }
   
};
Kolizje.cpp:
C/C++
#include "kolizje.h"

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;
   
};

bool Object::collision( Object & o )
{
    if( kolizja( X, Y, W, H, o.X, o.Y, o.W, o.H ) || kolizja( o.X, o.Y, o.W, o.H, X, Y, W, H ) )
         return true;
    else return false;
   
}

bool Player::collision( Object & o )
{
    if( Object::collision( o ) )
    {
        edge = edges( o );
        return true;
    }
    else return false;
   
}

int Player::edges( Object & o )
{
    Pos o1( o.X, o.Y ), o2( o.X + o.W, o.Y ), o3( o.X + o.W, o.Y + o.H ), o4( o.X, o.Y + o.W ); // wierzchołki obiektu
    Pos p1( X, Y ), p2( X + W, Y ), p3( X + W, Y + H ), p4( X, Y + W ); // wierzchołki Playera
   
    if( o1.y == p3.y &&(( p3.x >= o1.x && p3.x <= o2.x ) ||( p4.x >= o1.x && p4.x <= o2.x ) ) )
    //p3 lub p4 koliduje z o na lini o1-o2 lub na jego krawędziach 1 i 2
         return K_1_2;
   
    if( o2.x == p2.x &&(( p1.y >= o2.y && p1.y <= o3.y ) ||( p4.y >= o2.y && p4.y <= o3.y ) ) )
    //p4 lub p1 koliduje z o na lini o4-o1 lub na jego krawędziach 2 i 3
         return K_2_3;
   
    if( o3.y == p1.y &&(( p1.x >= o3.x && p1.x <= o4.x ) ||( p2.x >= o3.x && p2.x <= o4.x ) ) )
    //p2 lub p3 koliduje z o na lini o4-o1 lub na jego krawędziach 4 i 1
         return K_3_4;
   
    if( o4.x == p2.x &&(( p2.y >= o4.y && p2.y <= o1.y ) ||( p3.y >= o4.y && p3.y <= o1.y ) ) )
    //p4 lub p1 koliduje z o na lini o4-o1 lub na jego krawędziach 2 i 3
         return K_4_1;
   
    return K_NOT;
}
  Czy to jest dobrze?
P-64753
« 1 »
  Strona 1 z 1