• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Kolizja w grze platformowej 2D

Object Storage Arubacloud
+1 głos
536 wizyt
pytanie zadane 16 października 2015 w C i C++ przez GameProgrammer Obywatel (1,140 p.)
edycja 16 października 2015 przez GameProgrammer
Witam, od pewnego czasu próbuję napisać kolizję do gry platformowej 2D.

Najpierw próbowałem rozwiązania, gdzie sprawdza się player.x + player.width > tile.x, itd. Ale gdy na gracza działa grawitacja to wynikają z tego problemy, bo jeżeli gracz jest na górze bloku to ta kolizja również może być aktywna.

Próbowałem też zrobić 8 punktów na sprite postaci, po 2 na każdy bok, i one sprawdzały czy zachodzi kolizja z jakimiś obiektami, kolizja w ten sposób działała dobrze, ale też zdarzały się drobne błędy. Jeżyk to C++, biblioteka SFML 2.

Macie jakieś rozwiązanie, jak napisać dobrą kolizję w grze platformowej 2D, klocki są różnej wielkości ale zawsze jest to prostokąt.

Kod: http://wklej.org/id/1818508/

6 odpowiedzi

+1 głos
odpowiedź 16 października 2015 przez Patrycjerz Mędrzec (192,320 p.)

Jakoś mi się nudziło...

#include <SFML/Graphics.hpp>
#include <iostream>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "TEST");
    window.setFramerateLimit(100);

    sf::Event event;

    sf::Clock clock;
    sf::Time time;

    sf::RectangleShape figure_1(sf::Vector2f(50, 50));
    figure_1.setFillColor(sf::Color::Red);
    sf::RectangleShape figure_2(sf::Vector2f(200, 200));
    figure_2.setPosition(sf::Vector2f(300, 200));
    figure_2.setFillColor(sf::Color::Green);

    sf::FloatRect rectangle_1(0, 0, 50, 50);
    sf::FloatRect rectangle_2(300, 200, 200, 200);

    sf::Vector2f velocity;

    bool up = false;
    bool down = false;
    bool left = false;
    bool right = false;

    while(window.isOpen())
    {
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            up = true;
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            down = true;
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            left = true;
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            right = true;

        velocity.x = 0;
        velocity.y = 0;

        if(up)
        {
            velocity.y = -500;
            up = false;
        }
        if(down)
        {
            velocity.y = 500;
            down = false;
        }
        if(left)
        {
            velocity.x = -500;
            left = false;
        }
        if(right)
        {
            velocity.x = 500;
            right = false;
        }

        figure_1.move(time.asSeconds() * velocity.x, 0);
        rectangle_1.left += time.asSeconds() * velocity.x;
        if(rectangle_1.intersects(rectangle_2))
        {
            if(velocity.x < 0)
            {
                figure_1.setPosition(figure_2.getPosition().x + figure_2.getSize().x, figure_1.getPosition().y);
                rectangle_1.left = rectangle_2.left + rectangle_2.width;
                std::cout << "Lewo" << std::endl;
            }
            if(velocity.x > 0)
            {
                figure_1.setPosition(figure_2.getPosition().x - figure_1.getSize().x, figure_1.getPosition().y);
                rectangle_1.left = rectangle_2.left - rectangle_1.width;
                std::cout << "Prawo" << std::endl;
            }
        }

        figure_1.move(0, time.asSeconds() * velocity.y);
        rectangle_1.top += time.asSeconds() * velocity.y;
        if(rectangle_1.intersects(rectangle_2))
        {
            if(velocity.y < 0)
            {
                figure_1.setPosition(figure_1.getPosition().x, figure_2.getPosition().y + figure_2.getSize().y);
                rectangle_1.top = rectangle_2.top + rectangle_2.height;
                std::cout << "Gora" << std::endl;
            }
            if(velocity.y > 0)
            {
                figure_1.setPosition(figure_1.getPosition().x, figure_2.getPosition().y - figure_1.getSize().y);
                rectangle_1.top = rectangle_2.top - rectangle_1.height;
                std::cout << "Dol" << std::endl;
            }
        }

        window.clear();
        window.draw(figure_1);
        window.draw(figure_2);
        window.display();

        time = clock.getElapsedTime();
        clock.restart();
    }
    return 0;
}

Jeśli czegoś nie będziesz rozumiał, to pisz śmiało wink

komentarz 16 października 2015 przez GameProgrammer Obywatel (1,140 p.)
Co w przypadku gdy platforma się porusza a my stoimy w miejscu a velocity jest zerowe?
komentarz 16 października 2015 przez Patrycjerz Mędrzec (192,320 p.)
Wiem, że ktoś mi dał łapkę w dół, po podałem gotowca, ale sądzę, że wielu początkującym się po prostu nie chce tego wymyślać i wolą poznać sprawdzony sposób. A jeśli się im nie chce, to i też tracą chęci do nauki i programowania.

Pokazałem tutaj sposób z wykorzystaniem wektora prędkości. Jego obecność ułatwia wiele rzeczy. Bez niego kod mógłby być bardziej skomplikowany.
komentarz 16 października 2015 przez Patrycjerz Mędrzec (192,320 p.)
Program, który podałem, przedstawia sytuację, w której występuje obiekt statyczny i dynamiczny. Ten kod tak naprawdę powinien być wywoływany dla każdego obiektu dynamicznego w jakieś pętli. To jest tylko przykład z dwoma obiektami, przy większej ich liczbie ilość kodu zwiększa się.

Jeśli platforma się porusza, to ten kod będzie dotyczyć także jej.
komentarz 16 października 2015 przez GameProgrammer Obywatel (1,140 p.)
Można też w sumie dodać wektor prędkości to ruchomego bloku, i zmieniać pozycję gracza, podobnie jak teraz.
komentarz 16 października 2015 przez Patrycjerz Mędrzec (192,320 p.)
Czyli tak naprawdę fragmenty kodu odpowiedzialne za ruch i kolizje powinny być wywoływane dla wszystkich obiektów, które się poruszają (można dla wszystkich, ale jest to marnotrawstwo zasobów i czasu). Dla statycznych (statycznych zawsze, nie np. postać gracza, która stoi) ten kod nie obowiązuje.
+1 głos
odpowiedź 17 października 2015 przez milosz503 Początkujący (270 p.)
Tutaj jest fajnie opisana podstawowa kolizja na prostokątach, można to potem łatwo rozbudować:

http://quirinnos.pl/kurs-sfml-2-1-8-kolizje/

A tutaj jest bardziej zaawansowane z różnymi kształtami, pokazany jest ciekawy schemat, może w przyszłości się przyda ;).

http://gamedev.stackexchange.com/questions/70871/how-to-architect-collision-detection-in-sfml
0 głosów
odpowiedź 16 października 2015 przez Patrycjerz Mędrzec (192,320 p.)

W SFML masz metody contains i intersects (sf::Rect), które umożliwiają sprawdzenie kolizji pomiędzy, odpowiednio, punktem i prostokątem oraz prostokątem i prostokątem: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Rect.php.

komentarz 16 października 2015 przez GameProgrammer Obywatel (1,140 p.)

Używam jej do sprawdzenia czy kolizja między dwoma obiektami zachodzi, jeśli tak to potem sprawdzam z której strony, czy któryś z tych 8 punktów koliduje z tym blokiem.

Ale ta funkcja contains i intersects, sama w sobie nie daje odpowiedzi z której strony kolizja następuje by potem ustalić czy pozycje gracza ustawić na górze pola, czy z jego prawej strony itd.

Ja szukam rozwiązania, gdzie bez zbędnych udziwnień tak jak te z 8 punktami obiektu sf::RectangleShape, gdy grawitacja działa na gracza, można te kolizję stworzyć.

0 głosów
odpowiedź 16 października 2015 przez endriuh28 Użytkownik (920 p.)
Napisz kod, to może uda się pomóc.
komentarz 16 października 2015 przez GameProgrammer Obywatel (1,140 p.)
0 głosów
odpowiedź 16 października 2015 przez ZakosiliMiNeta Nałogowiec (30,870 p.)
Troszkę za mało informacji dałeś do problemu. Czy obiekty mogą się obracać? Bo jeśli tak to trzeba trzymać współżedne wierzchołków -> wyliczyć wzor funkcji ( między dwoma wierzchołkami ) ->  sprawdzić czy punkt nachodzi / przechodzi przez funkcję.
komentarz 16 października 2015 przez GameProgrammer Obywatel (1,140 p.)
Nie mogą się obracać, będą jedynie ruchome platformy w 8 kierunkach, ale bez rotacji.
komentarz 16 października 2015 przez ZakosiliMiNeta Nałogowiec (30,870 p.)
Defakto pomysł działa bez obracania obiektów ale to szczegół. W takim razie bierzesz  4 odcinki ( masz 4 współżedne i z nich tworzych te odcinki czyli 4-1, 1-2, 2-3 , 3-4 )  i sprawdzasz  czy jakiś punkt przekracza odcinek, a następnie spełnia wymagania wysokości i szerokości obiektu.
0 głosów
odpowiedź 16 października 2015 przez niezalogowany
Niech twoje obiekty składają się z dwóch colliderów: 1 do wykrywania podłoża, 2. do kolizji pomiędzy przeciwnikami

Podobne pytania

0 głosów
7 odpowiedzi 265 wizyt
pytanie zadane 14 listopada 2015 w Offtop przez Qweit Nowicjusz (120 p.)
+3 głosów
2 odpowiedzi 301 wizyt
0 głosów
1 odpowiedź 632 wizyt
pytanie zadane 8 lutego 2019 w Offtop przez Kerry Początkujący (340 p.)

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...