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 = ?
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.
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.
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. =)
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?
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.)
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.
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ć.
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.
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