Popiol |
Wysłany: Czw 14:20, 09 Mar 2006 Temat postu: Fizyka w grach |
|
Opracowałem pewien model matematyczny jazdy samochodem. Wiem, że temat jest troche oderwany od tematu tego działu, ale wszakże samo zaprojektowanie samochodu 3D jest mało ciekawe dopóki ten samochód nie może jeździć. Dlatego przedstawie swój pomysł na wyliczanie położenia samochodu w czasie jazdy.
Samochód utożsamiamy w moim modelu z dwoma punktami (przód i tył samochodu) połączonymi krawędzią. Zakładam, że napęd jest na przednie koła, a więc na przód działa siła przyśpieszająca, potrzebna do uzyskania następującego przyśpieszenia:
Kod: | ax = vk*sin(kat+skret) - vx;
ay = vk*cos(kat+skret) - vy; |
gdzie vk to prędkość kół, kat to kąt pomiędzy osią x w układzie współrzędnych a krawędzią łączącą przód i tył samochodu, skret to kąt o jaki są skręcone koła, a (vx,vy) to aktualny wektor prędkości przodu samochodu. Takie przyśpieszenie będzie miał samochód, jeśli nie wpadnie w poślizg.
Generalnie zakładam, że samochód porusza się po płaszczyźnie, dlatego wektory prędkości i przyśpieszenia dzielę na składowe x i y. Co prawda samochód może jechać pod górę, ale w tym przypadku wystarczy uwzględnić dodatkową siłę, ściągającą samochód w dół.
Jeśli chodzi o tył samochodu to trzeba uwzględnić siłę tarcia, która sprawia, że koła nie przesuwają się w bok, tylko kręcą się do przodu, albo do tyłu (o ile nie wpadną w poślizg, ale o tym później). Przyśpieszenie powodowane tą siłą wyliczam następująco:
Kod: | dx = tg(kat);
dy = 1;
b = (vy*dx-vx*dy)/(dy^2+dx^2);
ax = b * dy;
ay = -b * dx; |
Co innego jeśli zaciągniemy ręczny, wtedy w każdym kierunku tarcie jest takie samo:
Trzeba zadbać także o to, aby siła działająca na jeden punkt oddziaływała również na drugi punkt. Realizuje to następująca funkcja:
Kod: | dx = x2 - x1;
dy = y2 - y1;
b = (dy*ay1+dx*ax1)/(dy^2+dx^2);
dax2 += b * dx;
day2 += b * dy; |
gdzie x1,y1 - położenie pierwszego punktu, ax1,ay1 - przyśpieszenie pierwszego punktu, dax2,day2 - zmiana przyśpieszenia drugiego punktu, x2,y2 - wiadomo, reszta to zmienne pomocnicze. Trzeba ten kod wykonać dwa razy: gdy przód jest pierwszym punktem, a tył drugim i na odwrót. Następnie trzeba dodać do wektorów przyśpieszenia wektory zmiany przyśpieszenia.
A teraz zajmiemy się wpadaniem w poślizg. Sprawa okazuje się całkiem prosta, trzeba sprawdzić czy siła tarcia działająca na przód i tył samochodu nie jest zbyt duża i jeśli jest to ją zmniejszyć. Wygląda to tak:
Kod: | if ( abs(ax) > us*g ) {
ax = sign(ax)*uk*g;
}
if ( abs(ay) > us*g ) {
ay = sign(ay)*uk*g;
} |
W całym modelu siła jest reprezentowana przez przyśpieszenie, które ta siła nadaje, na podstawie wzoru f = a*m. W powyższym kodzie występują dwa współczynniki tarcia: us (tarcie satyczne) i uk (tarcie kinetyczne). Współczynnik tarcia kinetycznego jest mniejszy od współczynnika tarcia statycznego, z regóły zachodzi mniej więcej zależność us = 1.25 * uk. Parametr g to przyśpieszenie ziemskie. Nie należy jednak przywiązywać zbyt dużej wagi do jednostek, a więc g nie musi wcale wynosić 9.81. W praktyce w moim modelu poślizg wygląda w miarę sensownie dla parametrów: g = 0.1, us = 0.5, uk = 0.4.
Mając tak wyliczone przyśpieszenie dodajemy je do aktualnych wektorów prędkości. Ostatnim etapem jest "poprawienie" wektorów prędkości tak, by przód i tył znjdowały się nadal w tej samej odległości. Realizuje to następujący kod:
Kod: | dx = x2 - x1;
dy = y2 - y1;
xv1 = x1 + vx1; yv1 = y1 + vy1;
xv2 = x2 + vx2; yv2 = y2 + vy2;
a = (m1+m2)*(m1+m2)*(dx*dx+dy*dy);
b = 2*(m1+m2)*((xv1-xv2)*dx+(yv1-yv2)*dy);
c = (xv1-xv2)*(xv1-xv2)+(yv1-yv2)*(yv1-yv2)-dx*dx-dy*dy;
delta = b*b-4*a*c;
if (delta < 0) w = 0;
else w = (-sqrt(delta)-b)/(2*a);
vx1 += w*m2*dx; vy1 += w*m2*dy;
vx2 -= w*m1*dx; vy2 -= w*m1*dy; |
x1,y1 - położenie pierwszego punktu, vx1,vy1 - prędkość pierwszego punktu, m1 - masa pierwszego punktu, analogicznie dla drugiego punktu, reszta to zmienne pomocnicze.
To jeszcze nie jest pełny model, bo trzeba jakoś wyliczać prędkość kół i kąt skręcenia kół. Jeśli chodzi o skręcanie kół to doszedłem do wniosku, że jadąc szybciej powinno się skręcać wolniej, bo po pierwsze gwałtowny ruch kierownicą przy dużej prędkości może spowodować wpadnięcie w poślizg, a po drugie siła odśrodkowa sprawia, że trudniej jest skręcić kierownicę (tak mi się wydaje). Dlatego wymyśliłem taki model skręcania kół:
Kod: | void skrec(float kierunek) {
if (sign(kierunek)*sign(skret) < 0) skret += kierunek*dodkret;
else skret += kierunek*dskret/(abs(vk)+1);
if (skret > max) skret = max;
else if (skret < -max) skret = -max;
} |
Pierwszy warunek sprawdza czy skręcamy czy odkręcamy kierownicę. Parametry dodkret i dskret określają jak szybko to robimy. Ustawiłem dla nich wartości: dodkret = 0.1, dskret = 0.05. Nie wiem czy mam rację, ale wydaje mi się, że skręcić koła jest trudniej niż odkręcić. Parametr max określa maksymalny kąt skręcenia kół. U mnie to 45 stopni.
Jeśli chodzi o wyliczanie prędkości kół to tego jeszcze dokładnie nie opracowałem. W najprostszej wersji przyśpiesza się i hamuje jednostanie, bez uwzględnienia biegów, ale to jest oczywiście kiepski model. |
|