Chcę stworzyć realistyczny ruch samochodu za pomocą wektorów

12

Gogglowałem, jak to zrobić i znalazłem ten http://www.helixsoft.nl/articles/circle/sincos.htm Próbowałem , ale większość pokazanych funkcji nie działa, po prostu mam błędy ponieważ oni nie istnieli. Patrzyłem na funkcje cos i sin, ale nie rozumiem, jak ich używać ani jak sprawić, by ruch samochodu działał poprawnie za pomocą wektorów. Nie mam kodu, ponieważ nie jestem pewien, co zrobić przepraszam.

Każda pomoc jest mile widziana.

EDYTOWAĆ:

Mam ograniczenia, że ​​muszę używać silnika TL do mojej gry, nie wolno mi dodawać żadnego silnika fizyki. Musi być zaprogramowany w c ++. Oto próbka tego, co udało mi się podążać za tym, co zostało zrobione w linku, który podałem.

if(myEngine->KeyHeld(Key_W))
    {
        length += carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_S))
    {
        length -= carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_A))
    {
        angle -= carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_D))
    {
        angle += carSpeedIncrement;
    }

    carVolocityX = cos(angle);
    carVolocityZ = cos(angle);

    car->MoveX(carVolocityX * frameTime);
    car->MoveZ(carVolocityZ * frameTime);
bobthemac
źródło
Sprawdź tę stronę pod kątem zachowań sterujących: red3d.com/cwr/steer
MichaelHouse
Musisz zdefiniować „realistyczny ruch samochodu”
Maik Semder
1
Zakładam, że twój kąt może pochodzi od kierownicy. Długość powinna być wielkością twojej prędkości. Więc ostatni fragment kodu może być coś na wzór: carVecloityX = length* cos(angle);, carVelocityZ = length *sin(angle);, poza tym, proszę powiedzieć jakie jest twoje wejście i jak samochód powinien zachowywać. W tej chwili powinien sterować w płaszczyźnie naziemnej, ale znowu, to wcale nie jest ogólne. Właśnie
wykonałeś dla nas prosty

Odpowiedzi:

23

Nie jest trudno stworzyć dość dobry ruch samochodowy (ale ten post będzie dość długi). Musisz „zasymulować” kilka podstawowych sił, aby samochód poruszał się fizycznie.

(Wszystkie próbki kodu są pseudokodami).

Przyśpieszenie

Po pierwsze, oczywiście potrzebujesz przyspieszenia. Zrobiłoby to coś tak prostego, jak następujący wiersz:

acceleration_vector = forward_vector * acceleration_input * acceleration_factor
  • forward_vector - Wektor wskazujący w tym samym kierunku co samochód.
  • acceleration_input - Dane wejściowe powinny znajdować się w przedziale [-1, 1].
  • acceleration_factor - Wartość przyspieszenia (w pikselach na sekundę ^ 2 lub dowolnych jednostkach).

Sterowniczy

Sterowanie jest również dość proste. Zasadniczo wystarczy obrócić wektor do przodu samochodu, aby skierować go w innym kierunku.

steer_angle = steer_input * steer_factor
new_forward_vector = rotate_around_axis(forward_vector, up_vector, steer_angle)

Możesz jednak napotkać tutaj komplikację. Jeśli wprowadzasz dane za pomocą klawiatury, wartość będzie wynosić -1 lub 1, co oznacza, że ​​samochód skręci natychmiast. Możesz to naprawić za pomocą bardzo prostej interpolacji liniowej (lerping):

 amount = time_since_last_frame * steer_lerp_factor
 forward_vector = lerp(forward_vector, new_forward_vector, amount)

Kwota powinna zależeć od czasu, tak aby ruch nie zależał od liczby klatek na sekundę. Ilość powinna wynosić między [0, 1] a im jest mniejsza, tym płynniejsze będzie przejście między starymi i nowymi wektorami.

(W tym momencie przekonasz się, że samochód będzie kierował, nawet jeśli stoi w miejscu. Aby temu zapobiec, pomnóż steer_angleprzez to current_speed / max_speed, gdzie max_speedzdefiniowana jest stała.)

W ruchu

Teraz zastosujemy przyspieszenie i przesuniemy samochód o określoną liczbę pikseli na podstawie jego prędkości, przyspieszenia i układu kierowniczego. Będziemy także chcieli ograniczyć prędkość samochodu, aby nie poruszał się nieskończenie szybko.

current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
    velocity_vector += acceleration_vector * time_since_last_frame
}

position_vector += velocity_vector * time_since_last_frame

Twój samochód się teraz ślizga

Jeśli mam rację, twój samochód powinien się teraz ślizgać za każdym razem, gdy skręcasz, jakby był na lodzie. Wynika to z braku tarcia. W prawdziwym samochodzie występuje duże tarcie boczne (z powodu niemożności obracania się kół na boki: P).

Musisz zmniejszyć prędkość boczną. Nie zmniejszając go całkowicie, możesz sprawić, że samochód będzie wyglądał, jakby dryfował.

 lateral_velocity = right_vector * dot(velocity_vector, right_vector)
 lateral_friction = -lateral_velocity * lateral_friction_factor 

Ponieważ mówimy o tarciu, możesz również chcieć mieć siłę (tarcia), która zmniejsza twoją prędkość, tak że gdy przestaniesz przyspieszać, twój samochód w końcu się zatrzyma.

 backwards_friction = -velocity_vector * backwards_friction_factor

Twój kod do przemieszczania samochodu powinien teraz wyglądać następująco:

// Friction should be calculated before you apply the acceleration
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
backwards_friction = -velocity_vector * backwards_friction_factor
velocity_vector += (backwards_friction + lateral_friction) * time_since_last_frame


current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{ 
    velocity_vector += acceleration_vector * time_since_last_frame
}

position_vector += velocity_vector * time_since_last_frame

Notatki końcowe

Wspomniałem, w jaki sposób powinieneś zastosować Lerping do sterowania; Myślę, że możesz potrzebować zrobić to samo dla przyspieszenia i ewentualnie także dla kąta skrętu (będziesz musiał zapisać ich wartości z poprzedniej klatki i lerp z tego). Również wszystkie wektory w stosunku do samochodu (do przodu, w prawo, w górę) powinny mieć długość 1.

Ponadto tarcie jest nieco bardziej skomplikowane niż tutaj pokazałem. Zawsze należy upewnić się, że jego długość nigdy nie jest większa niż przyspieszenie potrzebne do zatrzymania samochodu (w przeciwnym razie tarcie spowodowałoby, że samochód poruszałby się w przeciwnym kierunku). Więc powinieneś mieć coś takiego:

dt = time_since_last_frame
backwards_friction.resize(min(backwards_friction.norm(), velocity_vector.norm() / dt))
lateral_friction.resize(min(lateral_friction.norm(), lateral_velocity.norm() / dt))
Paul Manta
źródło
Wow, to świetna odpowiedź!
ezolotko,
0

Sądząc z twojego pytania, zakładam, że jesteś stosunkowo nowy w programowaniu (co jest w porządku!). Sugerowałbym użycie istniejących ram, ponieważ realistyczna symulacja samochodu jest jednym z najtrudniejszych aspektów fizyki.

Nie wspomniałeś o ograniczeniach 2D / 3D, więc zamierzam zaproponować pobranie zestawu Havok SDK (darmowego do użytku niekomercyjnego) i uruchomienie prostej wersji demonstracyjnej (faktycznie mają wersje demonstracyjne, które zaczynają się od razu po wyjęciu z pudełka [pobierz skompilowany w twoim systemie, cały kod tam jest], nie musisz nic robić, aby go skompilować ... po prostu otwórz projekt i wciśnij build).

Kiedy już będziesz mieć pojęcie o kulisach fizyki samochodu (chociaż nie zobaczysz faktycznej implementacji fizyki, która jest ukryta, zobaczysz interfejsy), wierzę, że będziesz w lepszej sytuacji zrobić to dobrze, kiedy zaczynasz samodzielnie.

Niedawno zadałem również podobne pytanie . Linki tam również mogą pomóc. A oto kolejny link .


Po spojrzeniu na swoją edycję wydaje się, że chcesz po prostu zmienić prędkość samochodu w zależności od obliczonych kątów (to nie jest realistyczne btw, więc powinieneś zmienić oryginalne pytanie, aby to odzwierciedlić). Jeśli kąty są częścią pytania (których nie możesz zmienić) i musisz użyć kątów do obliczenia nowej prędkości, to idź z tym, co @teodron umieścił w komentarzach.

Innym sposobem jest użycie tylko wektorów. Istnieje wiele podejść wykorzystujących wektory, zamierzam przedstawić jedno.

Prędkość jest wielkością kierunek * (gdzie wielkość jest prędkością, a kierunek jest znormalizowanym wektorem). Oblicz aktualną prędkość i kierunek samochodu. Wybierz kierunek i dodaj do niego wektor (nazwijmy go D'), który jest do niego prostopadły. Spowoduje to zmianę prędkości samochodu. Brak kątów, z którymi można by się popsuć (chociaż można użyć kątów, aby określić długość wektora prostopadłego, którym może być współczynnik obrotu [patrz poniżej])

Jak obliczyćD' : Aby znaleźć wektor prostopadły, obierz kierunek pierwotnej prędkości, przecinaj go z wektorem kierunku zbliżającym się do ekranu, gdzie kolejność przecinania wektorów określa kierunek wektora prostopadłego. Następnie pomnóż ten czynnik prostopadły z pewnym współczynnikiem skrętu, który określa szybkość skręcania samochodu.

Samaursa
źródło
Chciałbym, ale nie wolno mi używać silnika fizyki, gra jest trójwymiarowa i wszystko, co muszę zmienić, to wektory X i Z, muszę tylko ustalić, jakie są.
bobthemac
@bobthemac: Czy to pytanie do pracy domowej? Jeśli tak, edytuj swoje pytanie, aby wskazać ograniczenia, które masz, i może opublikuj odpowiedni kod, abyśmy mieli coś do zbudowania. Btw, ostatni link może być tym, czego szukasz pod względem zrozumienia funkcjonalności.
Samaursa,
Dodałem informacje, o które prosiłeś, i przejrzałem podane linki, ale nadal ich nie rozumiem.
bobthemac
@bobthemac: Zobacz moją edycję
Samaursa,