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

[SFML] Kolizje oraz wzajemne odpychanie się obiektów

Ostatnio zmodyfikowano 2024-02-11 19:02
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML] Kolizje oraz wzajemne odpychanie się obiektów
» 2024-02-10 14:35:42
Witam.
W jaki sposób wykryć wszystkie kolizje, przechować ich stan oraz obliczyć "odepchnięcie" dla obiektów.
Obrazek niżej przedstawia problem, który próbuję rozwiązać.

P-180708
pekfos
» 2024-02-10 14:57:30
Możesz dla każdego obiektu obliczyć wektor przesunięcia by usunąć taką jedną kolizję, zrobić to dla wszystkich kolizji i zsumować. Proces trzeba by iterować wielokrotnie żeby znaleźć rozwiązanie, jeśli takie istnieje, bo raczej nie pytasz o dwa koła w próżni tylko o N obiektów na mapie z innymi nieruchomymi przeszkodami.
P-180711
tBane
Temat założony przez niniejszego użytkownika
» 2024-02-10 15:01:08
czyli mhm..
dla każdego obiektu utworzyć listę elementów z którymi koliduje, następnie obliczyć dla niego wektor przesunięcia... no i właśnie, skąd wiadomo jaki ma być wektor przesunięcia - jaki wzór ?

Jeszcze zastanawiam się, jak zachowa się wtedy dany obiekt, gdy jednocześnie będzie miał taką kolizję oraz będzie przemieszczany (ruch do celu)

P-180712
pekfos
» 2024-02-10 15:18:46
no i właśnie, skąd wiadomo jaki ma być wektor przesunięcia - jaki wzór ?
Z twojego własnego rysunku wynika. Niech A i B to punkty środkowe tych kół o promieniach r1 i r2... Dodanie wektora BA (długości d) do A przesunie koło A tak że A=B, więc chcesz przesunąć się w przeciwną stronę, o -BA. Ale nie o odległość d, lecz o różnicę odległości między tymi rysunkami, podzieloną na 2, bo drugi obiekt zrobi to samo i pokryje drugą połowę dystansu. Na drugim koła są styczne więc d' = r1 + r2. Czyli wektor to -BA * (r1 + r2 - d) / 2d.
A jak w szkole była geometria analityczna, to było "po co mi to w życiu".. Właśnie po to ;)

Jeszcze zastanawiam się, jak zachowa się wtedy dany obiekt, gdy jednocześnie będzie miał taką kolizję oraz będzie przemieszczany (ruch do celu)
Według sposobu który proponuję, oba obiekty będą się przesuwać więc jednostka kiedyś osiągnie cel. Bardziej bym się martwił stałymi przeszkodami. Jeśli wektor odepchnięcia będzie w osi z kierunkiem do celu, to możesz nigdy nie osiągnąć celu, chyba że dopchasz przeszkodę do niego.
P-180713
tBane
Temat założony przez niniejszego użytkownika
» 2024-02-10 15:30:07
mhm .. nie miałem geometrii analitycznej w szkole :-/ zresztą w szkołach z matmy nie uczą myślenia a przekształcania wzorów i prostych obliczeń matematycznych. Spróbuję sklecić ten wzór w kod.
P-180714
pekfos
» 2024-02-10 15:46:24
Takie demo napisałem, na wszelki wypadek. Jak ustawisz dt=1 na stałe to efekty będą względnie natychmiastowe. Wynik w jednym przebiegu raczej nie jest dokładny dla wielu obiektów, ale kolejne aktualizacje stanu gry poprawiają wynik i nie widać tego za bardzo.
C/C++
#include <SFML/Graphics.hpp>
#include <vector>


int main()
{
   
sf::RenderWindow okno( sf::VideoMode( 720, 480 ), "Kurs SFML 2.0 - http://cpp0x.pl" );
   
   
std::vector < sf::CircleShape > circles;
   
const float R = 30;
   
   
sf::Clock stoper;
   
while( okno.isOpen() )
   
{
       
sf::Event event;
       
while( okno.pollEvent( event ) )
       
{
           
if( event.type == sf::Event::Closed )
               
 okno.close();
           
           
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left )
           
{
               
sf::CircleShape cs( R );
               
cs.setOutlineColor( sf::Color::Red );
               
cs.setOutlineThickness( 1 );
               
cs.setFillColor( sf::Color::Transparent );
               
cs.setOrigin( R, R );
               
cs.setPosition( event.mouseButton.x, event.mouseButton.y );
               
circles.push_back( cs );
           
}
        }
//while
       
       
std::vector < sf::Vector2f > vects( circles.size() );
       
// optymalizacje zostawiam jako ćwiczenie dla czytelnika
       
for( size_t i = 0; i < circles.size(); ++i )
       
for( size_t j = i + 1; j < circles.size(); ++j )
       
{
           
auto A = circles[ i ].getPosition();
           
auto B = circles[ j ].getPosition();
           
           
float d = sqrt(( A.x - B.x ) *( A.x - B.x ) +( A.y - B.y ) *( A.y - B.y ) );
           
if( d < R * 2 && d > 0 )
           
{
               
sf::Vector2f v =( A - B ) *( R + R - d ) /( d * 2 );
               
vects[ i ] += v;
               
vects[ j ] -= v;
           
}
        }
       
       
// dla demonstracji, przesuwaj powoli
       
float dt = 5 * stoper.restart().asSeconds();
       
for( size_t i = 0; i < circles.size(); ++i )
           
 circles[ i ].move( vects[ i ] * dt );
       
       
okno.clear();
       
       
for( auto & cs: circles )
           
 okno.draw( cs );
       
       
okno.display();
   
} //while
   
return 0;
}
P-180715
tBane
Temat założony przez niniejszego użytkownika
» 2024-02-10 15:57:19
o mistrzu o to właśnie chodziło :-) przeanalizuję ten kod i spróbuję zaimplementować ten algorytm w swoim projekcie.
P-180716
tBane
Temat założony przez niniejszego użytkownika
» 2024-02-10 16:17:06
C/C++
void updateVillagers()
{
   
// odpychanie sie
   
for( auto & v1: villagers )
   
for( auto & v2
        : villagers )
   
{
       
float d = sqrt( pow( v1->x - v2->x, 2.0f ) + pow( v1->y - v2->y, 2.0f ) );
       
if( d < v1->radius + v2->radius && d > 0.0f )
       
{
           
// wzór na odpychanie się
            // sf::Vector2f v = (v1 - v2) * (v1->radius + v2->radius - d) / (d * 2);
           
           
v1->x +=( v1->x - v2->x ) *( v1->radius + v2->radius - d ) /( d * 2 );
           
v1->y +=( v1->y - v2->y ) *( v1->radius + v2->radius - d ) /( d * 2 );
           
           
v2->x -=( v1->x - v2->x ) *( v1->radius + v2->radius - d ) /( d * 2 );
           
v2->y -=( v1->y - v2->y ) *( v1->radius + v2->radius - d ) /( d * 2 );
           
       
}
    }
   
// odpychanie się
   
    // update
   
for( auto & v: villagers )
       
 v->update();
   
}
P-180717
« 1 »
  Strona 1 z 1