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

[SFML] Ruch po orbicie

Ostatnio zmodyfikowano 2013-05-31 18:01
Autor Wiadomość
kipi999
Temat założony przez niniejszego użytkownika
[SFML] Ruch po orbicie
» 2013-05-28 10:23:10
Witam wszystkich. Mam pewien problem, otóż musimy na fizykę zrobić program w którym ustawia się parametry planety i obiektu, a następnie puszczamy obiekt z jakąś prędkością i leci on wokół planety. Według praw fizyki, jeżeli będzie leciał za wolno, to w końcu spadnie na planetę. Z odpowiednią prędkością będzie poruszał się po orbicie w kształcie elipsy. Jeżeli będzie poruszał się zbyt szybko, to wyleci poza orbitę.

Cały interfejs graficzny razem z ustawianiem parametrów jest już gotowy, z obliczeniami jest już dużo gorzej xd Przedstawię co mam do tej pory.

r1 i r2 to promienie planety i obiektu, ale to tylko kwestia estetyczna.
g - grawitacja
v - prędkość początkowa
h - początkowa odległość planety od obiektu
dh - to już zmieniona odległość, która zmienia się na bieżąco
m i m2 - masa planety i obiektu

To tyle z podstawowych zmiennych. Teraz obliczenia

dh wyliczam z Pitagorasa
if(px > x && py > y) dh = sqrt(pow(py - y,2) + pow(px - x,2));
if(px < x && py < y) dh = sqrt(pow(y - py,2) + pow(x - px,2));
if(px > x && py < y) dh = sqrt(pow(px - x,2) + pow(y - py,2));
if(px < x && py > y) dh = sqrt(pow(x - px,2) + pow(py - y,2));
px,py - pozycja planety. x,y - pozycja obiektu

Grawitacja
g = Cg*(m*m2)/(dh*dh); - Przy czym Cg jest stałą = 0.0000000000667



Teraz trzeba jakoś ustalić pozycję obiektu przy każdym obiegu pętli. Mam ustawione parametry dla rzutu poziomego i chciałem je później zmodyfikować pod orbitowanie, ale okazało się, że jest to ponad moje siły 

x = x + (v*i);
y = y + ((g*(i*i))/2);

Przy czym 'i' jest licznikiem w pętli i robi za czas.

Mam nadzieję, że jasno określiłem swój problem. Będę bardzo wdzięczny za pomoc :D
P-84168
Monika90
» 2013-05-28 12:56:43
Rozumiem, że chcesz użyć metody Eulera, czy tak? Czy to ma być w 2D, czy 3D?
W tej gazecie http://www.atarionline.pl/biblioteka/czasopisma/Bajtek /Bajtek_1995_03.djvu
na stronie 16 masz artykuł o tym jak to zrobić, z przykładowym programem w Pascalu.

C/C++
if( px > x && py > y ) dh = sqrt( pow( py - y, 2 ) + pow( px - x, 2 ) );

if( px < x && py < y ) dh = sqrt( pow( y - py, 2 ) + pow( x - px, 2 ) );

if( px > x && py < y ) dh = sqrt( pow( px - x, 2 ) + pow( y - py, 2 ) );

if( px < x && py > y ) dh = sqrt( pow( x - px, 2 ) + pow( py - y, 2 ) );

Nie używaj pow do podnoszenia do kwadratu i nie powtarzaj w kółko tego smego kodu - definiuj własne funkcje.
P-84170
Mrovqa
» 2013-05-29 08:11:59
@kipi999 jak masz wyliczoną grawitację to później możesz obliczyć siłę działającą na planetę, a ona z kolei modyfikuje wektor prędkości, na podstawie którego określasz przemieszczenie. Można by też pokusić się o wykorzystanie gotowego silnika fizycznego, jak np. Box2D czy Bullet Physics, ale jeśli wcześniej z tego nie korzystałeś, to już wygodniej, szybciej i zrozumialej dla Ciebie będzie wykorzystać to, co napisałem zdanie wcześniej.
P-84251
kipi999
Temat założony przez niniejszego użytkownika
» 2013-05-29 18:27:23
Okej, ta metoda Eulera jest dosyć zrozumiała. Co do poprzedniego pytania, robię to w 2d. Niestety w tej gazecie nie było opisane jak zrobić to z osią y, więc zrobiłem analogicznie. Niestety obiekt robi mi jakieś zygzaki :/

Oto mój kod:

C/C++
if( ready == true )
{
    win.setFramerateLimit( 10 );
    x1 = 1024 / 2 - r1;
    ya1 = 768 / 2 - r1;
    x2 = 1024 / 2 - r2;
    y2 = 768 / 2 - r2 - h;
    for( int i = 1;; i++ )
    {
        // OBLICZANIE
        gx =( Cg * m1 * m2 ) /( x1 - x2 ) * 2;
        gy =( Cg * m1 * m2 ) /( ya1 - y2 ) * 2;
       
        ax1 = gx / m1;
        ax2 = gx / m2;
        ay1 = gy / m1;
        ay2 = gy / m2;
       
        vx1 = vx1 + ax1 * i;
        vx2 = vx2 + ax2 * i;
        vy1 = vy1 + ay1 * i;
        vy2 = vy2 + ay2 * i;
       
        x1 = x1 + vx1 * i;
        x2 = x2 + vx2 * i;
        ya1 = ya1 + vy1 * i;
        y2 = y2 + vy2 * i;
       
       
       
        //----------------
       
        win.draw( Background );
       
        c1.setPosition( x1, ya1 );
        c1.setRadius( r1 );
        win.draw( c1 );
        c2.setPosition( x2, y2 );
        c2.setRadius( r2 );
        win.draw( c2 );
        win.display();
    }
   
}
Użyta jest zmienna ya1, a nie y1 bo wygląda na to, że y1 jest zarezerwowane przez kompilator.
P-84275
pekfos
» 2013-05-29 18:48:14
wygląda na to, że y1 jest zarezerwowane przez kompilator.
Yyy, co?
P-84276
Monika90
» 2013-05-29 19:05:18
C/C++
gx =( Cg * m1 * m2 ) /( x1 - x2 ) * 2;
gy =( Cg * m1 * m2 ) /( ya1 - y2 ) * 2;
we wzorze w mianowniku jest r kwadrat, a ty masz mnożenie licznika przez 2.

C/C++
vx1 = vx1 + ax1 * i;
vx2 = vx2 + ax2 * i;
vy1 = vy1 + ay1 * i;
vy2 = vy2 + ay2 * i;

x1 = x1 + vx1 * i;
x2 = x2 + vx2 * i;
ya1 = ya1 + vy1 * i;
y2 = y2 + vy2 * i;
i
 to u ciebie zmienna całkowita, która na dodatek ciągle rośnie, w artykule jest to stała zmiennoprzecinkowa o niewielkiej wartości, np. 0.01.
P-84281
kipi999
Temat założony przez niniejszego użytkownika
» 2013-05-29 19:34:44
Rzeczywiście ten kwadrat był dużym niedopatrzeniem z mojej strony. Teraz już tak nie zygzakuje, ale nadal nie jest tak jak być powinno. Nawet jak nie nadaję obiektowi żadnej prędkości i powinien on spaść w dół, to porusza się łukiem w prawo i jak już zniży się poniżej poziomu planety to jakby przestała na niego działać grawitacja i leci po linii prostej gdzieś na dół :/
P-84283
Monika90
» 2013-05-29 22:44:30
Niestety w tej gazecie nie było opisane jak zrobić to z osią y, więc zrobiłem analogicznie.
Było opisane. Muisz policzyć odległośc z Pitagorasa, i na podstawie tego policzyć siłę, następnie rozkładasz tę siłe na dwie składowe x i y.
Przykład:
C/C++
struct Body
{
    const double mass;
    double x, y, vx, vy;
   
    void force( double fx, double fy, double dt )
    {
        vx += fx * dt / mass;
        vy += fy * dt / mass;
        x += vx * dt;
        y += vy * dt;
    }
   
    void draw() const { /*rysowanie ciala*/ }
};

//warunki poczatkowe
Body sun = { 1000000, 150, 150, 0, 0 };
Body p1 = { 1, 200, 150, - 0.1, 0.1 };

void frame()
{
    sun.draw();
    p1.draw();
   
    for( int i = 0; i < 500; ++i ) //ile krokow na klatke animacji
    {
        const double dt = 0.01; //krok czasowy
        const double g = 0.000001; //stala grawitacji
        const double dx = sun.x - p1.x;
        const double dy = sun.y - p1.y;
        const double r = std::sqrt( dx * dx + dy * dy );
        const double f = g * sun.mass * p1.mass /( r * r ); //sila grawitacji
        const double fx = f * dx / r; //jej skladowa x
        const double fy = f * dy / r; //skladowa y
        sun.force( - fx, - fy, dt );
        p1.force( fx, fy, dt );
    }
}
P-84307
« 1 » 2
  Strona 1 z 2 Następna strona