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

Wzór grawitacji w układzie współrzędnych

VPS Starter Arubacloud
+1 głos
796 wizyt
pytanie zadane 13 czerwca 2017 w C i C++ przez Ehlert Ekspert (212,630 p.)
edycja 13 czerwca 2017 przez Ehlert

Cześć,

podchodzi pod kategorię matematyka ale jest kod dlatego wstawiłem tutaj.

Problem jest następujący. Posiadam obiekt satelita który ma poruszać się ruchem prostoliniowym, zakrzywianym przez wpływ grawitacyjny innego obiektu.

Legenda:

  • body ciało satelity
  • rush prędkość satelity w px/sec
  • mum wskaźnik na obiekt posiadający wpływ grawitacyjny
  • gravity "moc" grawitacji
  • normalizeDirection zwraca wektor w postaci normalnej (długość wektora = 1)
  • delta.asSeconds przyrost czasu w ciągu jednej klatki
  • direction wektor ruchu prostoliniowego satelity; znormalizowany 
//update ruchu satelity podczas jednej klatki
sf::Vector2f straightMovement = sf::Vector2f(delta.asSeconds()*rush*direction.x, delta.asSeconds()*rush*direction.y);
float distanceToMum = vectorLength(body.getPosition()-mum->getPosition());
float powerDistanceGravity = std::pow(mum->gravity, 100/distanceToMum);
sf::Vector2f toMumMovement = normalizeDirection(mum->getPosition() - body.getPosition());
toMumMovement *= powerDistanceGravity;
body.move(straightMovement + toMumMovement); 

Metoda działa. Częściowo. Ruch rzeczywiście jest zakrzywiany, ale gdy satelita mija obiekt mum dość blisko, to zamiast zwiększać prędkość do niego i uderzyć, zmniejsza prędkość i oddala się. Jego droga przypomina bardzo rozwartą parabolę, zamiast pseudo elipsy. 

Any Ideas? wink

komentarz 14 czerwca 2017 przez draghan VIP (106,230 p.)
body.move() działa absolutnie czy inkrementalnie?
komentarz 14 czerwca 2017 przez Ehlert Ekspert (212,630 p.)
No to sfml. Inkrementalnie.
komentarz 14 czerwca 2017 przez draghan VIP (106,230 p.)

No to sfml

W zasadzie nie napisałeś, czym dokładnie jest body, więc wolałem się upewnić. :)

5 odpowiedzi

+1 głos
odpowiedź 13 czerwca 2017 przez mokrowski Mędrzec (155,460 p.)
Błędy wynikające z obliczeń na typie float :-) Jak to jest prosta symulacja, załóż że po minięciu "wystarczająco blisko", uderzył. Jak jest to niedopuszczalne to... zapraszam do czytania (i zrozumienia) pojęcia błędu różniczkowania numerycznego ;-)
komentarz 13 czerwca 2017 przez Ehlert Ekspert (212,630 p.)

Jeśli uderza to zostaje usunięty i znika z ekranu. Widzę to. Problem z implementacją to fakt że z dwukrotnym zwiększeniem odległości grawitacja powinna maleć czterokrotnie. 

Problemów z floatami nie ma. Zauważ, że dzielenia tu prawie nie ma (najmniejsza wartość distanceToMum to 55px, po czym satelita ginie), więc wartość NaN dla floata nigdzie nie wystąpi. 

float powerDistanceGravity = std::pow(mum->gravity, 100/distanceToMum);

Tu jest problem.

komentarz 13 czerwca 2017 przez mokrowski Mędrzec (155,460 p.)
Jeśli zrobię "smrodek edukacyjny" to przepraszam... Pierwsze z brzegu...

http://fulmanski.pl/zajecia/tippgk/zajecia_20142015/fixed_step/fixed_step.pdf

Problem analogiczny do kolizji "ze ścianą".
komentarz 13 czerwca 2017 przez Ehlert Ekspert (212,630 p.)

Nie musisz mnie uczyć aktualizować stanu gry, Wiem że kod jest do bani, mechanika leży bo robię tyle samo updateów stanu co frameów. Wiem co to pętla stałokrokowa i nie jednemu na tym forum tłukłem do głowy żeby używać.devil

Ten program był jednak skupiony na konkretnym problemie z dziedziny fizyki smiley

Gdyby nie to, nigdy w życiu nie użyłbym od tak pól publicznych. Problem leży we wzorze.

komentarz 14 czerwca 2017 przez mokrowski Mędrzec (155,460 p.)
Ależ moją intencją nie było "uczenie jak się aktualizuje stan gry". Wskazuję raczej że to jest ten sam problem co wykrycie kolizji :-) Różniczkowanie funkcji ciągłej w sposób dyskretny. Błędy się nawarstwiają bo obliczenia wykonywane są w wybranych punktach w czasie i przy braku wykrycia kolizji dochodzi do "przeniknięcia przez ścianę". W przenośni to także u Ciebie występuje. Satelita "teleportuje się" na "drugą stronę planety" zachowując poprzedni wektor prędkości co do kierunku i modułu.

W miejscu w które wskazujesz (std::pow(...)), 2 argument 100/diistanceToMum, będzie dążył do ogromnych wartości w przypadku zbliżania się do 0 (+ lub -). Dokładność typu float wtedy spada drastycznie i pojawiają się nierealne wartości.

Nie wiem także czy nie zakładasz nieskończenie małych rozmiarów ciał (w sensie geometrycznym). Jeśli tak, nie dojdzie do zderzenia.

Mam nadzieję że teraz intencje są jasne :-)
komentarz 15 czerwca 2017 przez Pajdas Mądrala (5,930 p.)
trochę nie do pytania, ale przecież pętla stałokrokowa blokuje możliwość posiadania dużej ilości fps. Przecież w różnych grach, można mieć i 300 fps i 30 fps, czy wtedy występuje pętla zmiennokrokowa. Są też gry gdzie nie da się mieć więcej niż np. 60 fps.

Czy też może źle rozumuję. Fps to tylko odświeżanie grafiki a nie logiki i fizyki?
+1 głos
odpowiedź 14 czerwca 2017 przez draghan VIP (106,230 p.)

Spróbowałem odtworzyć Twój problem u siebie. Ale chyba nie za bardzo uwidacznia się on u mnie. :)

Na screencaście widać, że początkowe dążenie do źródła grawitacji jest poprawne. Przy zbliżeniu się do źródła grawitacji, wyrażenie potęgowe staje się źródłem problemu: 100/distanceToMum dąży do nieskończoności, co sprawia że po dotarciu do celu, satelita dostaje mega kopa na drugą stronę świata. Nie widzę u siebie tego powolnego lotu oddalania, więc stawiam że jeśli już, to błąd tkwi nie tutaj.

Zaaplikowałem niewielką prymitywną poprawkę, kontrolującą wartość wyrażenia potęgowego, ale wątpię że o to chodzi (sterowanie definem PATH).

Proszę wybaczyć marną jakość kodu - pisany na szybko na podstawie SFMLowego "Hello world" i jakichś zaślepek na Twoje obiekty. Generuję w nim plik, który zawiera parametry ruchu dla każdej klatki. Można z niego wyciągnąć jakieś wnioski.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <cmath>
#include <iostream>
#include <fstream>
#include <thread>

float vectorLength(const sf::Vector2f &v)
{
    return sqrt(v.x*v.x + v.y*v.y);
}

sf::Vector2f normalizeDirection(const sf::Vector2f &v)
{
    return sf::Vector2f{v/vectorLength(v)};
}

int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");

    // Create a graphical text to display
    sf::Font font;
    if (!font.loadFromFile("arial.ttf"))
        return EXIT_FAILURE;
    sf::Text text("Hello SFML", font, 50);

    // Start the game loop
    sf::Texture texture1;
    if (!texture1.loadFromFile("satelita.png"))
        return EXIT_FAILURE;
    sf::Texture texture2;
    if (!texture2.loadFromFile("mum.png"))
        return EXIT_FAILURE;
    sf::Sprite body(texture1);
    sf::Sprite mumy(texture2);

    sf::Clock clock;
    sf::Time delta = clock.restart();

    // PARAMETERS
    float rush = 0.1;
    sf::Vector2f direction{1,1};
    float gravity = 5;
    body.setPosition(0,0);
    mumy.setPosition(100, 200);

    direction = normalizeDirection(direction);
    sf::Sprite *mum = &mumy;

#define PATCH
#ifdef PATCH
    std::ofstream file("pos_patch.txt");
#else
    std::ofstream file("pos_original.txt");
#endif
    float oldDistance = vectorLength(body.getPosition()-mum->getPosition());


    while (window.isOpen())
    {
        delta = clock.restart();

        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window: exit
            if (event.type == sf::Event::Closed)
                window.close();
        }
        // Clear screen
        window.clear();


        //update ruchu satelity podczas jednej klatki
        sf::Vector2f straightMovement = sf::Vector2f(delta.asSeconds()*rush*direction.x, delta.asSeconds()*rush*direction.y);
        float distanceToMum = vectorLength(body.getPosition()-mum->getPosition());
        float epsilon = 0.000001;
        float powerDistanceGravity;
        float deltaDistance;
        deltaDistance = oldDistance - distanceToMum;
#ifdef PATCH
        if(deltaDistance < epsilon || distanceToMum < 2*deltaDistance)
            powerDistanceGravity = 0;
        else
            powerDistanceGravity = std::pow(gravity, 100/distanceToMum);
#else
        powerDistanceGravity = std::pow(gravity, 100/distanceToMum);
#endif
        sf::Vector2f toMumMovement = normalizeDirection(mum->getPosition() - body.getPosition());
        toMumMovement *= powerDistanceGravity;
        body.move(straightMovement + toMumMovement);
        file << "dist: " << distanceToMum;
        file << " old_dist: " << oldDistance;
        file << " delta_dist: " << deltaDistance;
        file << " straight: " << straightMovement.x <<" " << straightMovement.y;
        file << " toMum: " << toMumMovement.x <<" " << toMumMovement.y;
        file << " pos: " << body.getPosition().x << " " << body.getPosition().y << std::endl;

        window.draw(mumy);
        window.draw(body);

        window.display();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        oldDistance = distanceToMum;
    }
    return EXIT_SUCCESS;
}
dist: 223.607 old_dist: 223.607 delta_dist: 0 straight: 0.000486419 0.000486419 toMum: 0.918552 1.8371 pos: 0.919039 1.83759
dist: 221.552 old_dist: 223.607 delta_dist: 2.05458 straight: 0.00782916 0.00782916 toMum: 0.924702 1.84941 pos: 1.85157 3.69483
dist: 219.474 old_dist: 221.552 delta_dist: 2.07822 straight: 0.00706923 0.00706923 toMum: 0.931055 1.86219 pos: 2.78969 5.56409
dist: 217.383 old_dist: 219.474 delta_dist: 2.09146 straight: 0.00707199 0.00707199 toMum: 0.93762 1.87539 pos: 3.73439 7.44655
dist: 215.276 old_dist: 217.383 delta_dist: 2.1062 straight: 0.00707248 0.00707248 toMum: 0.944409 1.88903 pos: 4.68587 9.34265
dist: 213.155 old_dist: 215.276 delta_dist: 2.12144 straight: 0.00707255 0.00707255 toMum: 0.951434 1.90316 pos: 5.64437 11.2529
dist: 211.018 old_dist: 213.155 delta_dist: 2.13722 straight: 0.00707029 0.00707029 toMum: 0.958709 1.91778 pos: 6.61015 13.1777
dist: 208.864 old_dist: 211.018 delta_dist: 2.15355 straight: 0.00707227 0.00707227 toMum: 0.966249 1.93294 pos: 7.58347 15.1177
dist: 206.694 old_dist: 208.864 delta_dist: 2.17047 straight: 0.00707029 0.00707029 toMum: 0.974069 1.94866 pos: 8.56461 17.0735
dist: 204.506 old_dist: 206.694 delta_dist: 2.18805 straight: 0.00707128 0.00707128 toMum: 0.982188 1.96497 pos: 9.55387 19.0455
dist: 202.299 old_dist: 204.506 delta_dist: 2.20625 straight: 0.00707142 0.00707142 toMum: 0.990623 1.98193 pos: 10.5516 21.0345
dist: 200.074 old_dist: 202.299 delta_dist: 2.22519 straight: 0.00707121 0.00707121 toMum: 0.999395 1.99956 pos: 11.558 23.0411
dist: 197.829 old_dist: 200.074 delta_dist: 2.24489 straight: 0.00707128 0.00707128 toMum: 1.00853 2.01791 pos: 12.5736 25.0661
dist: 195.564 old_dist: 197.829 delta_dist: 2.2654 straight: 0.00707149 0.00707149 toMum: 1.01804 2.03703 pos: 13.5987 27.1102
dist: 193.277 old_dist: 195.564 delta_dist: 2.28674 straight: 0.00707142 0.00707142 toMum: 1.02797 2.05698 pos: 14.6338 29.1743
dist: 190.968 old_dist: 193.277 delta_dist: 2.30904 straight: 0.00707121 0.00707121 toMum: 1.03834 2.07781 pos: 15.6792 31.2592
dist: 188.636 old_dist: 190.968 delta_dist: 2.33229 straight: 0.00707142 0.00707142 toMum: 1.04918 2.09959 pos: 16.7354 33.3658
dist: 186.279 old_dist: 188.636 delta_dist: 2.35663 straight: 0.00706937 0.00706937 toMum: 1.06053 2.1224 pos: 17.803 35.4953
dist: 183.897 old_dist: 186.279 delta_dist: 2.3821 straight: 0.00707333 0.00707333 toMum: 1.07243 2.1463 pos: 18.8825 37.6487
dist: 181.488 old_dist: 183.897 delta_dist: 2.40881 straight: 0.00707135 0.00707135 toMum: 1.08492 2.1714 pos: 19.9745 39.8271
dist: 179.051 old_dist: 181.488 delta_dist: 2.43683 straight: 0.00707114 0.00707114 toMum: 1.09806 2.19778 pos: 21.0797 42.032
dist: 176.585 old_dist: 179.051 delta_dist: 2.46631 straight: 0.00707149 0.00707149 toMum: 1.11189 2.22557 pos: 22.1986 44.2646
dist: 174.088 old_dist: 176.585 delta_dist: 2.49734 straight: 0.00707071 0.00707071 toMum: 1.12648 2.25488 pos: 23.3322 46.5266
dist: 171.558 old_dist: 174.088 delta_dist: 2.53008 straight: 0.00707206 0.00707206 toMum: 1.1419 2.28585 pos: 24.4811 48.8195
dist: 168.993 old_dist: 171.558 delta_dist: 2.56471 straight: 0.00707135 0.00707135 toMum: 1.15823 2.31865 pos: 25.6465 51.1452
dist: 166.392 old_dist: 168.993 delta_dist: 2.60132 straight: 0.00707128 0.00707128 toMum: 1.17556 2.35346 pos: 26.8291 53.5058
dist: 163.751 old_dist: 166.392 delta_dist: 2.64021 straight: 0.00707142 0.00707142 toMum: 1.19399 2.39047 pos: 28.0301 55.9033
dist: 161.07 old_dist: 163.751 delta_dist: 2.68155 straight: 0.00707121 0.00707121 toMum: 1.21364 2.42993 pos: 29.2509 58.3403
dist: 158.344 old_dist: 161.07 delta_dist: 2.72565 straight: 0.00707149 0.00707149 toMum: 1.23465 2.47211 pos: 30.4926 60.8195
dist: 155.572 old_dist: 158.344 delta_dist: 2.77275 straight: 0.00707121 0.00707121 toMum: 1.25717 2.51733 pos: 31.7568 63.3439
dist: 152.748 old_dist: 155.572 delta_dist: 2.82329 straight: 0.00707326 0.00707326 toMum: 1.28138 2.56595 pos: 33.0453 65.9169
dist: 149.871 old_dist: 152.748 delta_dist: 2.87761 straight: 0.00706944 0.00706944 toMum: 1.30752 2.61842 pos: 34.3599 68.5424
dist: 146.934 old_dist: 149.871 delta_dist: 2.9362 straight: 0.00707149 0.00707149 toMum: 1.33582 2.67525 pos: 35.7028 71.2247
dist: 143.935 old_dist: 146.934 delta_dist: 2.99969 straight: 0.00707114 0.00707114 toMum: 1.3666 2.73705 pos: 37.0764 73.9689
dist: 140.866 old_dist: 143.935 delta_dist: 3.06874 straight: 0.00707156 0.00707156 toMum: 1.40024 2.80457 pos: 38.4837 76.7805
dist: 137.722 old_dist: 140.866 delta_dist: 3.14418 straight: 0.00707128 0.00707128 toMum: 1.43718 2.87872 pos: 39.928 79.6663
dist: 134.495 old_dist: 137.722 delta_dist: 3.22702 straight: 0.00707135 0.00707135 toMum: 1.47798 2.96062 pos: 41.413 82.634
dist: 131.176 old_dist: 134.495 delta_dist: 3.31851 straight: 0.00707135 0.00707135 toMum: 1.52333 3.05165 pos: 42.9434 85.6927
dist: 127.756 old_dist: 131.176 delta_dist: 3.42022 straight: 0.00707142 0.00707142 toMum: 1.57412 3.15359 pos: 44.5246 88.8534
dist: 124.222 old_dist: 127.756 delta_dist: 3.53411 straight: 0.00707128 0.00707128 toMum: 1.63147 3.26871 pos: 46.1632 92.1292
dist: 120.559 old_dist: 124.222 delta_dist: 3.66273 straight: 0.00707071 0.00707071 toMum: 1.69688 3.39998 pos: 47.8671 95.5362
dist: 116.75 old_dist: 120.559 delta_dist: 3.80939 straight: 0.00707192 0.00707192 toMum: 1.77234 3.5514 pos: 49.6465 99.0947
dist: 112.771 old_dist: 116.75 delta_dist: 3.97856 straight: 0.00707142 0.00707142 toMum: 1.86056 3.72845 pos: 51.5142 102.83
dist: 108.595 old_dist: 112.771 delta_dist: 4.17638 straight: 0.00707128 0.00707128 toMum: 1.96542 3.93887 pos: 53.4867 106.776
dist: 104.183 old_dist: 108.595 delta_dist: 4.41148 straight: 0.00707248 0.00707248 toMum: 2.09258 4.19404 pos: 55.5863 110.977
dist: 99.4868 old_dist: 104.183 delta_dist: 4.69658 straight: 0.00707022 0.00707022 toMum: 2.25075 4.5114 pos: 57.8441 115.496
dist: 94.4357 old_dist: 99.4868 delta_dist: 5.05116 straight: 0.00707192 0.00707192 toMum: 2.45401 4.91923 pos: 60.3052 120.422
dist: 88.9288 old_dist: 94.4357 delta_dist: 5.50686 straight: 0.00707086 0.00707086 toMum: 2.72696 5.46687 pos: 63.0392 125.896
dist: 82.8101 old_dist: 88.9288 delta_dist: 6.11874 straight: 0.00707142 0.00707142 toMum: 3.11689 6.24918 pos: 66.1632 132.152
dist: 75.8172 old_dist: 82.8101 delta_dist: 6.99284 straight: 0.00707128 0.00707128 toMum: 3.72852 7.47623 pos: 69.8988 139.636
dist: 67.4533 old_dist: 75.8172 delta_dist: 8.36388 straight: 0.00707107 0.00707107 toMum: 4.85074 9.7276 pos: 74.7566 149.37
dist: 56.5739 old_dist: 67.4533 delta_dist: 10.8794 straight: 0.00707156 0.00707156 toMum: 7.67416 15.3918 pos: 82.4378 164.769
dist: 39.3656 old_dist: 56.5739 delta_dist: 17.2083 straight: 0.00707142 0.00707142 toMum: 26.6102 53.3819 pos: 109.055 218.158
dist: 20.2906 old_dist: 39.3656 delta_dist: 19.075 straight: 0.00706937 0.00706937 toMum: -1242.77 -2492.1 pos: -1133.71 -2273.94
dist: 2764.49 old_dist: 20.2906 delta_dist: -2744.2 straight: 0.00707333 0.00707333 toMum: 0.473021 0.948545 pos: -1133.22 -2272.98
dist: 2763.42 old_dist: 2764.49 delta_dist: 1.06934 straight: 0.00707128 0.00707128 toMum: 0.473031 0.948567 pos: -1132.74 -2272.03
dist: 2762.35 old_dist: 2763.42 delta_dist: 1.06958 straight: 0.00707142 0.00707142 toMum: 0.47304 0.948589 pos: -1132.26 -2271.07
dist: 2761.28 old_dist: 2762.35 delta_dist: 1.06934 straight: 0.00707121 0.00707121 toMum: 0.47305 0.948611 pos: -1131.78 -2270.11
dist: 2760.21 old_dist: 2761.28 delta_dist: 1.06934 straight: 0.00707241 0.00707241 toMum: 0.473059 0.948633 pos: -1131.3 -2269.16
dist: 2759.14 old_dist: 2760.21 delta_dist: 1.06958 straight: 0.00707036 0.00707036 toMum: 0.473069 0.948655 pos: -1130.82 -2268.2
dist: 2758.07 old_dist: 2759.14 delta_dist: 1.06958 straight: 0.00707078 0.00707078 toMum: 0.473079 0.948677 pos: -1130.34 -2267.25
dist: 2757 old_dist: 2758.07 delta_dist: 1.06982 straight: 0.00707177 0.00707177 toMum: 0.473088 0.948699 pos: -1129.86 -2266.29
dist: 2755.93 old_dist: 2757 delta_dist: 1.06958 straight: 0.00707149 0.00707149 toMum: 0.473098 0.948721 pos: -1129.38 -2265.34

 

1
komentarz 15 czerwca 2017 przez obl Maniak (51,280 p.)
edycja 15 czerwca 2017 przez obl

To jest dość proste, choć wymaga dopracowania. W modelu powinno się wykorzystać wzór https://wikimedia.org/api/rest_v1/media/math/render/svg/3566ff0a6866e59c9a189dc60a424445c2a4590d

po użyciu tego wzoru należy podzielić uzyskany wektor przez masę obiektu otrzymując wektor przyspieszenia. Wektor przyspieszenia pomnożony przez dt daje wektor prędkości Vg teraz wektor prędkości początkowej obiektu V sumuję z wektorem prędkości grawitacyjnej Vg otrzymując tym samym nowy wektor prędkości chwilowej. Teraz (zakładając słaby model, ale oddający jako tako rzeczywistość) otrzymany wektor prędkości pomnożony przez dt daje w wyniku przemieszczenie S, które należy dodać do wektora położenia obiektu. Uproszczony wzór (na którym to wszystko u mnie działa) wygląda tak:

dPoint2D grVel(dPoint2D obj1,double mass,dPoint2D obj2){
	double l = (obj2 - obj1).GetDistToPoint2D(0,0);
	double ag = G * mass / (l * l);
	return (obj1 - obj2) * (ag / l);
}

gdzie:

mass - masa obiektu oddziałującego

obj1, obj2 - współrzędne obiektów oddziałujących na siebie

ag - przyspieszenie (które przy założeniu dt na sztywno jako 1s staje się z automatu prędkością)

G - stała grawitacyjna G = 6.674286464646464e-11

l - wyliczona odległość za pomocą metody obiektu klasy dPoint2D o nazwie GetDistToPoint2D

zwracana wartość to wektor prędkości związany z oddziaływaniem grawitacyjnym.

Ten wektor sumujesz z wektorem bieżącego położenia. Tak przynajmniej to wygląda u mnie.

Edit

Tak wygląda efekt animacji trzech obiektów wzajemnie na siebie oddziałujących:

Trzy obiekty rysują swoją trajektorię ruchu różnymi kolorami.

Edit

Poprawiłem moje literówki żeby nie było.

komentarz 15 czerwca 2017 przez Ehlert Ekspert (212,630 p.)
#include <SFML/Graphics.hpp>
#include <iostream>

class Sun : public sf::CircleShape
{
public:

    float gravity;

    Sun()
        :sf::CircleShape(50,50)
    {
        setPosition(350,350);
        setOrigin(50,50);
        setFillColor(sf::Color::White);
        gravity = 2.f;
    }

};

class Satelite : public sf::Drawable
{
public:

    sf::CircleShape body;
    sf::Vector2f direction;
    float rush;
    bool collision = false;
    bool alive  = false;
    Sun * mum;

    Satelite(sf::Vector2f start, Sun * gravity)
        :body (sf::CircleShape(5,50)),
         mum    (gravity)
    {
        body.setOrigin(5,5);
        body.setFillColor(sf::Color::Red);
        body.setPosition(start);
    }

    void wakeUp(sf::Vector2f end)
    {
        sf::Vector2f dire = body.getPosition() - end;
        direction = normalizeDirection(dire);
        rush = std::sqrt(std::pow(dire.x, 2) + std::pow(dire.y, 2));
    }

    void update(sf::Time _dt)
    {
        moveSatelite(_dt);
        checkExisting();
    }

    virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const{
        sf::Vertex lineToMum[2];
        if (alive) {
            float distanceToMum = vectorLength(body.getPosition()-mum->getPosition());
            sf::Uint8 color = (sf::Uint8)(255 * (1 - (distanceToMum / 2000)));
            lineToMum[0] = sf::Vertex(mum->getPosition(), sf::Color(0, color, color));
            lineToMum[1] = sf::Vertex(body.getPosition(), sf::Color(color, 0, color));
            target.draw(lineToMum, 2, sf::Lines);
        }
        target.draw(body);
    }

private:

    sf::Vector2f normalizeDirection(const sf::Vector2f & _source) {
        sf::Vector2f result;
        result.x = (_source.x / vectorLength(_source));
        result.y = (_source.y / vectorLength(_source));
        if (result.x != result.x)
            result.x = 0;
        if (result.y != result.y)
            result.y = 0;
        return result;
    }

    void moveSatelite(sf::Time delta)
    {
        sf::Vector2f straightMovement = sf::Vector2f(delta.asSeconds()*rush*direction.x, delta.asSeconds()*rush*direction.y);
        float distanceToMum = vectorLength(body.getPosition()-mum->getPosition());
        float powerDistanceGravity =  std::pow(mum->gravity,100 /  distanceToMum);
        sf::Vector2f toMumMovement = normalizeDirection(mum->getPosition() - body.getPosition());
        toMumMovement *= powerDistanceGravity;
        body.move(straightMovement + toMumMovement);
    }

    float vectorLength(sf::Vector2f vec) const
    {
        return std::sqrt(std::pow(vec.x, 2) + std::pow(vec.y, 2));
    }

    void checkExisting()
    {
        if (vectorLength(body.getPosition()-mum->getPosition()) < 55) {
            collision = true;
            return;
        }
        if (body.getPosition().x != body.getPosition().x) {
            collision = true;
            return;
        }
        if (vectorLength(body.getPosition()-mum->getPosition()) > 2000) {
            collision = true;
            return;
        }
    }
};

int main()
{
    sf::RenderWindow app(sf::VideoMode(700,700), "Fucking Gravity");
    app.setFramerateLimit(70);
    sf::Event event;
    sf::Clock timer;
    sf::Time fps;

    Sun blackSun;
    std::vector<Satelite> satelites;
    sf::Vector2f    clicked,
                    released;

    sf::Vertex forcePointer[2];
    bool drawForcePointer = false;

    while(app.isOpen())
    {
        fps = timer.restart();
        app.clear(sf::Color::Black);

        while (app.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                app.close();
            else if (event.type == sf::Event::MouseButtonPressed)
            {
                clicked = sf::Vector2f(sf::Mouse::getPosition(app).x, sf::Mouse::getPosition(app).y);
                satelites.push_back(Satelite(clicked, &blackSun));
                drawForcePointer = true;
            } else if (event.type == sf::Event::MouseButtonReleased) {
                drawForcePointer = false;
                (satelites.end()-1)->alive = true;
                (satelites.end()-1)->body.setFillColor(sf::Color::Cyan);
                (satelites.end()-1)->wakeUp(sf::Vector2f(sf::Mouse::getPosition(app).x, sf::Mouse::getPosition(app).y));
            }
        }

        satelites.erase(std::remove_if(
                satelites.begin(),
                satelites.end(),
                [](const Satelite& x) { return x.collision;}
        ), satelites.end());

        for (auto &satelite : satelites) {
            if (satelite.alive)
                satelite.update(fps);
            app.draw(satelite);
        }

        if (drawForcePointer)
        {
            forcePointer[0] = sf::Vertex(clicked, sf::Color::Green);
            forcePointer[1] = sf::Vertex(sf::Vector2f(sf::Mouse::getPosition(app).x, sf::Mouse::getPosition(app).y), sf::Color::Green);
            app.draw(forcePointer, 2, sf::Lines);
        }

        app.draw(blackSun);
        app.display();
    }
}
1
komentarz 15 czerwca 2017 przez niezalogowany

Jeżeli rush to prędkość satelity to czemu jest ona stała przez cały czas? Tak samo z direction. To tak jakby satelita poruszał się dodatkowo w poruszającym się ośrodku... Gdzie jest wzór na grawitację? Ja zrobiłbym to wg kroków:

1. Ciało klasy satelita:
 

class Satelite
{
    float mass;
    float x, y; // wektor aktualnego położenia. Możesz zapisać jako Vector2f
    float vx, vy; // wektor aktualnej prędkości - będzie zmienna przez cały czas działania programu, ale będzie zależeć od wartości startowej.
    float ax, ay; // wektor przyspieszenia
    // możesz zapisywać wartość i wersor, ale pominę to
};

2) Oblicz wektor przyśpieszenie tego obiektu wg wzoru na wektorowe przyśpieszenie grawitacji, który podawałem ja i obl:

void GravitySystem::gravity()
{
    reset_acceleration();
    for(int i=0; i<size(); i++) // petla obliczania przyspieszenia dla kazdego ciała
    {
        for(int j=0; j<size(); j++) // petla obliczania oddzialywania kazdego ciala z kazdym
        {
            if(j!=i) // zeby planeta nie przyciagala sama siebie, bo wyjdzie wtedy dzielenie przez 0!
            {
                double xx = objects[j].x - objects[i].x;
                double yy = objects[j].y - objects[i].y;
                double rr = sqrt(xx*xx + yy*yy);
                double r3 = pow(rr, 3);
                double mj = objects[j].m;
                
                // przyspieszenie grawitacyjne z wektorowego prawa Newtona
                // przyspieszenie to wektor, wiec mamy dwa rownania:
                objects[i].ax += G*mj*xx/r3;
                objects[i].ay += G*mj*yy/r3;
            }
        }
    }
}

void GravitySystem::reset_acceleration()
{
    for(int i=0; i<size() ; i++)
    {
        objects[i].ax = 0;
        objects[i].ay = 0;
    }
}

objects to tablica obiektów. Słońce też może być obiektem. Wszystkie obiekty się przyciągają.

3. Obliczasz nową prędkość (na podstawie przyśpieszenia i starej prędkości), obliczasz nowe położenia (na podstawie aktualnej prędkości i starego położenia):

void GravitySystem::euler_method(double dt) // dt krok czasowy pomiędzy klatkami
{
    for(int i=0; i<size(); i++) // petla dla kazdego ciala
    {
        // Obliczanie wektora predkosci (2D) v+=dv, dv = a*dt
        objects[i].vx += objects[i].ax*dt;
        objects[i].vy += objects[i].ay*dt;
        // Obliczanie wektora nowego polozenia (2D) s+=ds, ds=v*dt
        objects[i].x += objects[i].vx*dt;
        objects[i].y += objects[i].vy*dt;
    }
}

0. Nie opisuj zmiennych długimi nazwami, bo ciężko się czyta i odnajduje fizyczne reguły. Łatwiej będzie Ci później zapisać zasady zachowania pędu czy energii, albo nadawanie prędkości kosmicznych. 

0 głosów
odpowiedź 14 czerwca 2017 przez niezalogowany
edycja 15 czerwca 2017

Może mógłbyś podać coś więcej? Startowe wektory położenia obiektów i startowa prędkość satelity i masy są jak najbardziej w cenie. Jeżeli tor jest paraboliczny to może prędkość jest za duża? Może przekracza prędkość ucieczki, a może jest za mała i obiekt zbliża się niebezpiecznie do planety? Zbyt bliskie przejście może powodować błędy - odległość maleje do zera, przyśpieszenie zależne od odległości odwrotnie prop z kw daje dzielenie przez 0. Czyli przyśpieszenie może okazać zbyt duże i obiekt zostanie wyrzucony z prędkością światła. Warto sprawdzić przy okazji czy symulacja spełnia w czasie zasadę zachowania pędu i energii. Przy powyższej sytuacji energia całkowita i pęd układu w momencie wyrzucenia satelity może skoczyć do dużej liczby (co będzie czymś niemożliwym fizycznie). Zakładam, że z punktu aplikacji fizyki zrobiłeś wszystko dobrze. Możesz porównać z moim kodem ideowym, który kiedyś pisałem: klik 

0 głosów
odpowiedź 14 czerwca 2017 przez obl Maniak (51,280 p.)
Zastanawiam się nad taką jedną rzeczą, piszesz, że chcesz zrobić model grawitacji. W grawitacji ważnym czynnikiem jest masa obiektów oddziałujących na siebie. Gdzie jest twoja masa? To co potrzebujesz:

wektory położenia środków mas oddziałujących na siebie

wektory początkowe prędkości obiektów

masy obiektów

Dalej obliczasz siłę oddziaływania grawitacyjnego i dla danego dt obliczasz wektor prędkości opadania. Sumujesz wektor prędkości opadania + wektor prędkości początkowej i uzyskujesz nowy wektor prędkości. Obliczasz przemieszczenie po nowym wektorze prędkości przy danym dt. Kiedyś napisałem taki programik według tych zasad i działał (a nawet działa). Zamodelowałem ruch trzech ciał krążących względem siebie i wzajemnie na siebie oddziałujących (coś jak układ krążących blisko siebie gwiazd + jedna planeta). Jak będę miał czas to może wygrzebię kawałek kodu z fizyką.
0 głosów
odpowiedź 14 czerwca 2017 przez CzikaCarry Szeryf (75,340 p.)
Problem może być w tym, że punkt, w którym siła grawitacji jest największa, może nie do końca pokrywać się ze środkiem satelity (czyt. Może być poza satelitą). To by tłumaczyło spadek prędkości.

Podobne pytania

0 głosów
0 odpowiedzi 157 wizyt
pytanie zadane 18 października 2016 w JavaScript przez Alterwar Dyskutant (7,650 p.)
+1 głos
1 odpowiedź 179 wizyt
+10 głosów
2 odpowiedzi 1,636 wizyt

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 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!

...