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 |
|
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.djvuna stronie 16 masz artykuł o tym jak to zrobić, z przykładowym programem w Pascalu. 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. |
|
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. |
|
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: 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++ ) { 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. |
|
pekfos |
» 2013-05-29 18:48:14 wygląda na to, że y1 jest zarezerwowane przez kompilator. |
Yyy, co? |
|
Monika90 |
» 2013-05-29 19:05:18 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. 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. |
|
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ół :/ |
|
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: 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 { } };
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 ) { const double dt = 0.01; const double g = 0.000001; 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 ); const double fx = f * dx / r; const double fy = f * dy / r; sun.force( - fx, - fy, dt ); p1.force( fx, fy, dt ); } }
|
|
« 1 » 2 |