Prosty ruch oparty na fizyce

Pracuję nad grą 2D, w której próbuję przyspieszyć obiekt do maksymalnej prędkości za pomocą podstawowego kodu fizyki.

Oto dla niego pseudokod:


const float acceleration = 0.02f;
const float friction     = 0.8f;  // value is always 0.0..1.0
      float velocity     = 0;
      float position     = 0;

move()
{
   velocity += acceleration;
   velocity *= friction;
   position += velocity;
}

Jest to bardzo uproszczone podejście, które nie opiera się na masie lub rzeczywistym tarciu (tarcie w kodzie jest tylko ogólną siłą działającą na ruch). Działa dobrze, ponieważ część "prędkość * = tarcie;" utrzymuje prędkość przed przekroczeniem określonego punktu. Jednak jest to prędkość maksymalna i jej związek z przyspieszenie i tarcie, gdzie jestem trochę zagubiony.

Chciałbym ustawić prędkość maksymalną i czas potrzebny na jej osiągnięcie, a następnie użyć ich do określenia wartości przyspieszenia i tarcia.

Tzn.,


const float max_velocity = 2.0; 
const int   ticks;       = 120; // If my game runs at 60 FPS, I'd like a 
                                // moving object to reach max_velocity in 
                                // exactly 2 seconds.
const float acceleration = ?
const float friction     = ?
Author: gnovice, 2009-03-20

6 answers

Uznałem to pytanie za bardzo interesujące, ponieważ niedawno wykonałem kilka prac nad modelowaniem ruchu pocisku za pomocą przeciągania.

Punkt 1: zasadniczo aktualizujesz pozycję i prędkość za pomocą jawnej / forward iteracji Eulera , gdzie każda nowa wartość dla Stanów powinna być funkcją starych wartości. W takim przypadku należy najpierw zaktualizować pozycję , a następnie zaktualizować prędkość.

Punkt 2: jest więcej realistyczne modele fizyki dla efektu tarcia hamulca . Jeden model (zaproponowany przez Adama Lissa [27]) zakłada siłę oporu, która jest proporcjonalna do prędkości (znany jako opór Stokesa, który zwykle stosuje się do sytuacji o małej prędkości). Ta, którą wcześniej zasugerowałem, polega na sile oporu, która jest proporcjonalna do kwadratu prędkości (znanej jako opór kwadratowy, który zwykle stosuje się do sytuacji z dużą prędkością). Zwrócę się do każdego z nich w odniesieniu do tego, jak ty wydedukowałoby formuły dla maksymalnej prędkości i czasu potrzebnego do skutecznego osiągnięcia maksymalnej prędkości. Zrezygnuję z pełnych wyprowadzeń, ponieważ są one raczej zaangażowane.


Drag Stokesa:

Równanie do aktualizacji prędkości będzie następujące:

velocity += acceleration - friction*velocity

, które reprezentuje następujące równanie różniczkowe:

dv/dt = a - f*v

Używając pierwszego zapisu w tej Całkowej tabeli , możemy znaleźć rozwiązanie (zakładając v = 0 przy t = 0):

v = (a/f) - (a/f)*exp(-f*t)

Maksymalna (tj. końcowa) prędkość występuje, gdy t > > 0, tak że drugi termin w równaniu jest bardzo bliski zeru i:

v_max = a/f

Jeśli chodzi o czas potrzebny do osiągnięcia maksymalnej prędkości, zauważ, że równanie nigdy tak naprawdę do niego nie dociera, ale zamiast tego asymptotuje w jego kierunku. Jednak, gdy argument wykładniczy jest równy -5, prędkość wynosi około 98% maksymalnej prędkości, prawdopodobnie wystarczająco blisko, aby uznać ją za równą. Można wtedy przybliżyć czas do prędkość maksymalna as:

t_max = 5/f

Można następnie użyć tych dwóch równań do rozwiązania dla f i a biorąc pod uwagę pożądany vmax i tmax.


Przeciąganie kwadratowe:

Równanie do aktualizacji prędkości będzie następujące:

velocity += acceleration - friction*velocity*velocity

, które reprezentuje następujące równanie różniczkowe:

dv/dt = a - f*v^2

Używając pierwszego wpisu w tej Całkowej tabeli , możemy znaleźć rozwiązanie (zakładając v = 0 przy t = 0):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

Maksymalna (tj. końcowa) prędkość występuje, gdy t > > 0, tak że Warunki wykładnicze są znacznie większe niż 1 i równanie zbliża się:

v_max = sqrt(a/f)

Jeśli chodzi o czas potrzebny do osiągnięcia maksymalnej prędkości, zauważ, że równanie nigdy tak naprawdę do niego nie dociera, ale zamiast tego asymptotuje w jego kierunku. Jednak, gdy argument wykładniczy jest równy 5, prędkość wynosi około 99% maksymalnej prędkości, prawdopodobnie wystarczająco blisko, aby uznać ją za równą. Możesz wtedy przybliżony czas do maksymalnej prędkości jako:

t_max = 2.5/sqrt(a*f)

Co jest również równoważne:

t_max = 2.5/(f*v_max)

Dla pożądanego vmax i tmax , drugie równanie dla tmax powie Ci, czym powinno być f , a następnie możesz podłączyć to do równania dla vmax , aby uzyskać wartość dla a .


Wygląda to na lekką przesadę, ale są to najprostsze sposoby modelowania przeciągania! Każdy, kto naprawdę chce zobaczyć kroki integracji może strzelać do mnie e-mail i wyślę je do ciebie. Są zbyt zaangażowani, aby pisać tutaj.

Inna kwestia: {[16] } nie zdawałem sobie z tego sprawy, ale aktualizacja prędkości nie jest już konieczna, jeśli zamiast tego użyjesz wzorów, które otrzymałem dla v (t) . Jeśli po prostu modelujesz przyspieszenie z odpoczynku i śledzisz czas od rozpoczęcia przyspieszenia, kod wyglądałby coś like:

position += velocity_function(timeSinceStart)

Gdzie "velocity_function" jest jednym z dwóch wzorów dla v (t) i nie potrzebujesz już zmiennej prędkości. Ogólnie rzecz biorąc, istnieje tutaj kompromis: obliczanie v (T) może być bardziej kosztowne obliczeniowo niż zwykłe aktualizowanie prędkości za pomocą schematu iteracyjnego (ze względu na warunki wykładnicze), ale jest gwarantowane, że pozostanie stabilne i ograniczone. Pod pewnymi warunkami (jak próba uzyskania bardzo krótkiego tmax) iteracja może stać się niestabilność i wybuchowość, częsty problem z forward ' ową metodą Eulera. Jednak utrzymywanie limitów zmiennych (takich jak 0 f

Ponadto, jeśli czujesz się nieco masochistycznie, możesz być w stanie zintegrować wzór dla v(t), aby uzyskać rozwiązanie formy zamkniętej dla p(T), w ten sposób rezygnując całkowicie z potrzeby iteracji Newtona. Zostawię to innym. =)

 36
Author: gnovice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 03:56:56

Warning: Partial Solution

Jeśli postępujemy zgodnie z fizyką, nie ma maksymalnej prędkości. Z czysto fizycznego punktu widzenia, Ustawiłeś przyspieszenie na stałą wartość, co oznacza, że prędkość zawsze rośnie.

Jako alternatywę, rozważ dwie siły działające na Twój obiekt:

  • stała siła zewnętrzna, F , która ma tendencję do jej przyspieszania i
  • siła oporu, d , która jest proporcjonalna do prędkość i ma tendencję do spowolnienia.

Więc prędkość w iteracji n staje się: vn = v0 + n F - dvn-1

Poprosiłeś o wybranie maksymalnej prędkości, vnmax , który występuje w iteracji nmax.

Zauważ, że problem jest pod ograniczeniami ; to znaczy F i d są ze sobą powiązane, więc możesz dowolnie wybrać wartość dla jeden z nich, a następnie obliczyć drugi.

teraz, gdy piłka się toczy, czy ktoś jest chętny do wzięcia matematyki?

Uwaga: jest brzydki i obejmuje serię mocy !


Edit: dlaczego ciąg n**F** w pierwszym równaniu pojawia się dosłownie, chyba że po n jest spacja?

 3
Author: Adam Liss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-20 22:00:22
velocity *= friction;
To nie przeszkadza prędkości w pewnym punkcie...

Tarcie rośnie wykładniczo (nie Cytuj mnie na ten temat) wraz ze wzrostem prędkości i będzie wynosić 0 w spoczynku. W końcu dojdziesz do punktu, w którym tarcie = przyspieszenie.

Więc chcesz coś takiego:

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

Gdzie wybierasz wartości a i b. b będzie kontrolować, jak długo trwa osiągnięcie maksymalnej prędkości, a a będzie kontrolować, jak gwałtownie wzrasta tarcie. (Ponownie, nie rób swojego własne badania na ten temat-wybieram się z tego, co pamiętam z fizyki klasy 12.)

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-20 17:11:49

To nie jest odpowiedź na twoje pytanie, ale jedna rzecz, której nie powinieneś robić w symulacjach takich jak ta, to zależeć od stałej liczby klatek na sekundę. Oblicz czas od ostatniej aktualizacji i użyj delta-T w równaniach. Coś w stylu:

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

Dobrze jest również sprawdzić, czy utracisz ostrość i przestaniesz aktualizować, a po uzyskaniu ostrości Ustaw lastUpdate na 0. W ten sposób nie będziesz miał wielkiego deltata do przetworzenia po powrocie.

 2
Author: GoatRider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-20 22:55:48

Jeśli chcesz zobaczyć, co można zrobić z Bardzo prostych modeli fizyki przy użyciu Bardzo prostej matematyki, spójrz na niektóre projekty Scratch na http://scratch.mit.edu / - możesz dostać kilka przydatnych pomysłów i na pewno będziesz się dobrze bawić.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-20 20:30:04

To prawdopodobnie nie jest to, czego szukasz, ale w zależności od tego, na jakim silniku pracujesz, może być lepiej użyć silnika zbudowanego przez kogoś innego, jak farseer (dla C#). Uwaga Codeplex jest wyłączony do konserwacji.

 1
Author: Diones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-20 20:50:00