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

[SFML] Kolizja i co potem?

Ostatnio zmodyfikowano 2012-11-02 15:14
Autor Wiadomość
Zyper
Temat założony przez niniejszego użytkownika
» 2012-11-02 12:08:22
No ja już wcześniej zaimplementowałem sobie Box2D, ale skasowałem, bo doszedłem do wniosku, że lepiej będzie samemu się czegoś nauczyć.
Już samo SFML wydaje mi się za dużym ułatwieniem :P


No dobra, myślę, że nikt lepiej tego problemu nie rozwiąże niż ja sam.

Żegnam :)


ps.
Jeśli uda mi się rozwiązać TEN problem, to podam rozwiązanie.
P-68164
diego997
» 2012-11-02 12:25:32
Btw jak zaimplementujesz 2d Boxa to daj znac mi sie nigdy nie udalo ;p





A co do kolizji to moze sproboj wykrywac w taki sposob, ze jezeli obiekt znajduje sie po prawej stronie to sprawdzasz kolizje tylko miedzy prawa krawedzia i nim, tzn jak poruszasz sie w prawo to non stop sprawdzasz kolizje miedzy prawa krawedzia a obiektami, jak natrafisz na kolizje to blokujesz poruszanie w prawo, natomiast w lewo mozesz isc bo wykrywasz kolizje analogicznie czyli po lewej stronie nic nie stoi :D Ja tak zawsze wykrywam tzn to ma tylko zastosowanie dla czworokatow im wiecej katow tym gorzej ;p
P-68168
Zyper
Temat założony przez niniejszego użytkownika
» 2012-11-02 12:39:43
Implementacja Box2D jest taka sama jak SFML.
Ładujesz po prostu wszystkie pliki, z tym, że Box2D nie ma statycznych bibliotek, więc chyba trzeba pliki dll wrzucać do folderu z grą. W internecie na pewno jest pełno poradników :P

Co do tego pomysłu Twojego, to próbowałem coś takiego zrobić, ale 4 maski to za mało. Jeśli jest ściana bloków z jednej strony musiałbym używać po 2 maski na jedną stronę.

http://i.snag.gy/ZNWKm.jpg

Nie wiem czy to dobre rozwiązane, zajmuje dużo czasu takie bawienie się z IntRect :P

P-68174
akwes
» 2012-11-02 13:44:35
Ok. Ogólnie to nie rozumiem całego problemu :P 

Jeżeli mam listę bloków, które są równo i postać to jestem w stanie sprawdzić wszystkie kolizje, które zachodzą. Trzeba przelecieć po całej liście i nie przerywać tego przechodzenia gdy już wpadniemy na jakąś kolizję, a jedynie danemu klockowi ustawiać flagę kolizji. Kolizję należy sprawdzać przed ruchem. Jeżeli stoję obok ściany to mogę iść (nie naciskam na nią - nie ma kolizji).

Przed chwilą nawet naskrobałem prosty przykład tego :P Taka sama kolizja jak w prostych platformówkach.
P-68185
Zyper
Temat założony przez niniejszego użytkownika
» 2012-11-02 14:26:23
Serio?
No ja też myślałem tak jak Ty, ale pojawiły się jakieś dziwne komplikacje...

Może problemem u mnie nie jest teoria, ale praktyczne zastosowanie pomysłu w kodzie.

Jak masz też przykład, to poproszę :P


ps.
Musiałem pisać drugi raz wiadomość, bo po kliknięciu "Zapisz zmiany" chyba poprzedniej nie wysłało :(
P-68192
akwes
» 2012-11-02 14:42:35

VS2012, SFML 2.0
C/C++
#include <SFML/Graphics.hpp>
#include <list>
// Klasa, która reprezentuje kwadrat, zdolny do
// zmiany koloru w zależności od stanu kolzji.
class CRect
{
    sf::Color Color;
    sf::RectangleShape Rect;
public:
    CRect( sf::Vector2f size, sf::Color col, sf::Vector2f Pos )
        : Rect( size )
        , Color( col )
    {
        Rect.setFillColor( Color );
        Rect.setPosition( Pos );
    }
    sf::FloatRect GetRectToColide()
    {
        return Rect.getGlobalBounds();
    }
    void SetPosition( float x, float y )
    {
        Rect.setPosition( x, y );
    }
    // Zmiana koloru na kolor kolizyjny
    void SetColide()
    {
        Rect.setFillColor( sf::Color::Red );
    }
    // Zmiana koloru na wlasny
    void SetFree()
    {
        Rect.setFillColor( Color );
    }
    void Draw( sf::RenderWindow & app )
    {
        app.draw( Rect );
    }
};

// Klasa, która obsłuugje rysowanie wszystkich dodanych do niej kwadratów
class CRectList
{
public:
    // Aby nie komplikować przykładu z pobieraniem listy itd,
    // tutaj zmienna będzie wyjątkowo publiczna
    std::list < CRect * > Items;
   
    void Add( CRect * rect )
    {
        Items.push_back( rect );
    }
    ~CRectList()
    {
        // jakieś tam zwolnieine zasoboów
    }
    void Draw( sf::RenderWindow & app )
    {
        std::list < CRect * >::iterator it = Items.begin();
        while( it != Items.end() )
        {
            ( * it )->Draw( app );
            it++;
        }
    }
};
// Klasa obsługująca gracza
class CPlayer
{
    sf::RectangleShape Rect;
public:
    CPlayer( const sf::Vector2f & vec )
        : Rect( vec )
    {
        Rect.setFillColor( sf::Color::Yellow );
        Rect.setPosition( 400, 300 );
    }
    sf::FloatRect GetRectToColide()
    {
        return Rect.getGlobalBounds();
    }
    void Move( sf::Vector2f Vec )
    {
        Rect.move( Vec );
    }
    // Funckja zwracająca teoretyczny ruch
    sf::Vector2f Move( float time )
    {
        sf::Vector2f vec;
        if( sf::Keyboard::isKeyPressed( sf::Keyboard::W ) )
        {
            vec.y -= 1;
        }
        if( sf::Keyboard::isKeyPressed( sf::Keyboard::S ) )
        {
            vec.y += 1;
        }
        if( sf::Keyboard::isKeyPressed( sf::Keyboard::A ) )
        {
            vec.x -= 1;
        }
        if( sf::Keyboard::isKeyPressed( sf::Keyboard::D ) )
        {
            vec.x += 1;
        }
        // mnożenie przez 200 jest dlatego, żeby obiekt sie nie ślimaczył
        return sf::Vector2f( vec.x * 200 * time, vec.y * 200 * time );
    }
    void Draw( sf::RenderWindow & app )
    {
        app.draw( Rect );
    }
};
class CColider
{
public:
    static bool IsCol( sf::FloatRect c1, sf::FloatRect c2 )
    {
        if( c1.left + c1.width >= c2.left )
        if( c1.left <= c2.left + c2.width )
        if( c1.top + c1.height >= c2.top )
        if( c1.top <= c2.top + c2.height )
             return true;
       
        return false;
    }
    static void Colide( CPlayer & pl, sf::Vector2f Move, CRectList & List )
    {
        sf::FloatRect tmp = pl.GetRectToColide();
        tmp.left += Move.x;
        sf::FloatRect tmp2 = pl.GetRectToColide();
        tmp2.top += Move.y;
       
        std::list < CRect * >::iterator it = List.Items.begin();
        bool Colided1 = false;
        bool Colided2 = false;
        while( it != List.Items.end() )
        {
            if( IsCol( tmp,( * it )->GetRectToColide() ) )
            {
                ( * it )->SetColide();
                // 1
                Colided1 = true;
            }
            else if( IsCol( tmp2,( * it )->GetRectToColide() ) )
            {
                ( * it )->SetColide();
                // 2
                Colided2 = true;
            }
            else
            {
                ( * it )->SetFree();
            }
           
            it++;
        }
       
        // W zależności od ilości FPS może zacząć się pojawiać przerwa
        // mniejsza bądź większa, między klockami. Jeżeli nie będą to
        // kwadraty a jakieś sprity to problem będzie niewidoczny.
        // Jeżeli zależy komuś na dokładności, to wtedy trzeba by
        // w punktach 1 i 2 obliczać odległość obiektu od miejsca kolizji
        // i pamiętać najmniejszą z tych odległości, a potem o tą najmniejszą
        // (zamiast pełnego ruchu) przesunąć obiekt. Mamy wtedy pewność,
        // że taki obiekt nie będzie kolidował.
       
        // Niewielkim kosztem można również zrobić aby gracz napierając na
        // ścianę, zamiast stać w miejscu to aby przesuwał się w którąś stronę
        if( !Colided1 )
             pl.Move( sf::Vector2f( Move.x, 0 ) );
       
        if( !Colided2 )
             pl.Move( sf::Vector2f( 0, Move.y ) );
       
    }
};

int main()
{
    sf::RenderWindow App( sf::VideoMode( 800, 600 ), "SFML works!" );
    sf::Clock Clock;
    float time = 0;
    CPlayer Player( sf::Vector2f( 50.f, 50.f ) );
    CRectList RList;
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::Blue, sf::Vector2f( 150, 70 ) ) );
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::Green, sf::Vector2f( 150, 120 ) ) );
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::White, sf::Vector2f( 150, 170 ) ) );
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::Cyan, sf::Vector2f( 130, 220 ) ) );
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::Magenta, sf::Vector2f( 230, 150 ) ) );
    RList.Add( new CRect( sf::Vector2f( 50, 50 ), sf::Color::Magenta, sf::Vector2f( 340, 150 ) ) );
    while( App.isOpen() )
    {
        sf::Event event;
        while( App.pollEvent( event ) )
        {
            if( event.type == sf::Event::Closed )
                 App.close();
           
        }
       
        App.clear();
       
        // Logic
        CColider::Colide( Player, Player.Move( time ), RList );
       
        // Drawing
        RList.Draw( App );
        Player.Draw( App );
        App.display();
        // Frametime
        time = Clock.restart().asSeconds();
    }
   
    return 0;
}

Kod jest roboczy :P Jak Ci zależy na detalach to sobie pozmieniaj
sf::Vector2f
 na
const sf::Vector2f &
itd :P
P-68197
diego997
» 2012-11-02 14:58:48
Zyper dziekuje ci najmocniej za napisanie tego posta dzieki tobie akwes wyslal program w ktory porusza blokami bez przycinania masakra.

Pierwszy raz widze zeby poruszajacy obiekt nie przycinal nie wierze w to ;d
P-68201
Zyper
Temat założony przez niniejszego użytkownika
» 2012-11-02 15:14:16
Spoko, mam to samo :)
Nie mi dziękuj ;)

Dzięki Ci akwes, nawet nie wiedziałem, że istnieje taka fajna lista. Ja się na tablicach męczyłem...
No dobra, będzie analizowania przykładu na tydzień. Temat zamykam, dziękuję wszystkim (a szczególnie akwesowi) za pomoc.

Pozdrawiam, Zyper
P-68207
1 « 2 »
Poprzednia strona Strona 2 z 2