Jak przenieść postać w grze RPG z Bullet Physics / Ogre3D?


9

ostatnio miałem problemy z przenoszeniem mojej postaci w mojej grze Ogre3D. Zasadniczo poruszam postacią z RigidBody->translate()funkcją pocisku , ale kiedy to robię i wpadam na ścianę, przechodzę przez nią lekko, a potem odbijam się z powrotem. Zastanawiam się, czy istnieje inny dobry sposób na poruszanie moją postacią (która ma kształt kolizji kuli) w prostym świecie typu samolot ze ścianami?

Biblioteki, których używam, są do tego względne, to „Ogre3D” i „Bullet Physics”.

Odpowiedzi:


9

Chociaż nie pracowałem specjalnie z silnikiem fizyki pocisków, zrobiłem coś bardzo podobnego w innym silniku fizyki. Sposób, w jaki to rozwiązałem, polegał na ustawieniu prędkości liniowej ciała sztywnego zamiast bezpośredniego tłumaczenia. Ruch i kolizje były następnie automatycznie obsługiwane przez fazę aktualizacji silnika fizyki.

Z dokumentacji wynika, że istnieje btRigidBody::setLinearVelocitymetoda, której można użyć. Na przykład, jeśli nie chcesz, aby miały miejsce żadne przyspieszenia, po prostu ustaw prędkość liniową na odpowiednią wartość za każdym razem, gdy postać się porusza, i ustaw ją z powrotem na (0,0,0), kiedy postać ma się zatrzymać (tj. kiedy gracz zwolni klawisz).

Jeśli chodzi o to, jakich wartości użyć, typowym podejściem byłoby rozpoczęcie od pożądanej prędkości twojej postaci (jako liczby zmiennoprzecinkowej / skalarnej), a następnie pomnożenie jej przez znormalizowany wektor, który wskazuje w kierunku, w którym chcesz się poruszać. Z tego, co widzę, btVector3klasa ma już metody do tego wszystkiego.

Alternatywnie możesz rozważyć potraktowanie postaci jako kompletnego obiektu fizyki i obsługę ruchu za pomocą metod applyForcelub applyImpulse. Spowodowałoby to przyspieszenie ciała, więc twoje postacie będą miały pęd, a wyniki prawdopodobnie będą wyglądać ładniej w ten sposób. Ale musisz podjąć dodatkowe środki, na przykład upewniając się, że prędkość liniowa nigdy nie przekracza określonego limitu, albo poprzez zaciskanie go, albo zabawę z tłumieniem / tarciem. Będzie to więc trudniejsze do wdrożenia i dokładniejszego.

Eksperymentuj z obiema metodami, a następnie wybierz tę, która zachowuje się najbliżej twoich potrzeb.


W porządku, dzięki za szybką odpowiedź. Zamierzam wypróbować to od razu.
Molmasepic

Sztuczka LinearVelocity działała tak, jak się spodziewano, jak urok! Było kilka problemów, które musiałem naprawić, ale działa 100% Dzięki bardzo za odpowiedź!
Molmasepic

9

Dla przypomnienia, moje doświadczenie z fizyką polega na korzystaniu z Chimpunk w silniku gier 2D, ale jestem pewien, że ta koncepcja dobrze przekłada się na 3D.

Zakładam, że twoja postać jest ciałem fizycznym o wadze i tym podobnych. Najlepszym sposobem na to jest bardzo uproszczona symulacja chodzenia. Pomyśl o tym w ten sposób: jeśli stoisz, twoje stopy mają duże tarcie, więc nie tylko się ślizgasz. Kiedy się poruszasz, w przybliżeniu odpowiada to usunięciu tarcia (ponieważ nie opierasz się ruchowi stopami) i przyłożeniu siły kierunkowej. Ja nie mówiąc, że należy indywidualnie symulować każdą stopę pchającą na ziemi - ciało sztywne jest to, co chcesz.

  • Kiedy twoja postać nie próbuje aktywnie się poruszać, zwiększ jej tłumienie prędkości, aby pozostała nieruchoma.
  • Kiedy twoja postać się porusza, zmniejsz jej tłumienie prędkości i zastosuj siłę w kierunku ruchu. Ustaw swoje tłumienie i siłę, aby postać poruszała się z rozsądną prędkością.
  • Jeśli postać jest w powietrzu, ustaw bardzo niskie tłumienie. Jeśli chcesz być realistą, nie pozwól im przykładać żadnej siły, aby zmienić kierunek w powietrzu. Możesz uderzyć tutaj w szczęśliwe medium, pozwalając im przyłożyć znacznie mniejszą siłę, co daje im ograniczoną możliwość dostosowania trajektorii podczas lotu.

Oto, gdzie trochę się komplikuje:

  • Jeśli postać już się porusza i zmieni kierunek, musisz zrekompensować pęd, dostosowując kierunek, w którym przykładasz siłę. Na przykład, jeśli twoja postać porusza się na północ i skręca na wschód, musisz przyłożyć swoją siłę w kierunku, który jest w połowie drogi między przeciwnym kierunkiem obecnego kierunku podróży a zamierzonym kierunkiem podróży. W miarę zmiany kierunku podróży dostosuj siłę, tak aby zawsze znajdowała się w połowie drogi między nimi, a Twoja postać szybko i płynnie zmieni kierunek.

Jeśli odpowiednio wyregulujesz swoją siłę i tłumienie, zastosowanie siły zawsze zapewni najbardziej realistyczny wynik, szczególnie jeśli postać będzie popychać przedmioty. Tłumaczenie będzie najgorszym sposobem na to, ponieważ silnik fizyki tak naprawdę nie uważa tego za ruch. Bezpośrednie ustawienie prędkości jest nieco lepsze, ale z mojego doświadczenia wynika, że ​​najlepsze wyniki można uzyskać za pomocą siły i tłumienia.

Mam nadzieję, że wyjaśniłem to wystarczająco dobrze. Zapytaj, czy potrzebujesz wyjaśnień. :)


0

W przypadku punktu 2.87 wydaje się, że właściwą metodą jest wywołanie zwrotne zaznaczenia, które aktualizuje się z wewnętrzną częstotliwością aktualizacji symulacji (być może wielu 100 Hz), a setWorldTransform () na obiektach kinematycznych płynnie aktualizuje pozycję:

Ta część znajduje się w instrukcji:

// set the rigid body as kinematic
rigid_body->setCollisionFlags(
    rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
rigid_body->setActivationState(DISABLE_DEACTIVATION);
...

Ta część była trudniejsza do zrozumienia:

void externalTickCallback(btDynamicsWorld *world, btScalar timeStep)
{
  // get object passed into user data point
  Foo* foo = static_cast<Foo*>(world->getWorldUserInfo());
  ... loop through all the rigid bodies, maybe foo has them
  {
    if (rigid_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT)
    {
      btVector3 kinematic_linear_vel = ... // get velocity from somewhere
      btTransform trans;
      rigid_body->getMotionState()->getWorldTransform(trans);
      trans.setOrigin(trans.getOrigin() + kinematic_linear_vel * time_step);
      // TODO support angular velocity
      rigid_body_->getMotionState()->setWorldTransform(trans);
    }
  }
}
...
my_dynamics_world->setInternalTickCallback(tickCallback, static_cast<void*>(this), true);

To była pomocna dokumentacja w btRigidBody.h https://github.com/bulletphysics/bullet3/blob/master/src/BulletDynamics/Dynamics/btRigidBody.h :

/// - C) Obiekty kinematyczne, które są obiektami bez masy, ale użytkownik może je przenosić. Istnieje interakcja jednokierunkowa, a Bullet oblicza prędkość na podstawie pomiaru czasu oraz poprzedniej i bieżącej transformacji świata.

setLinearVelocity () nie działa dla obiektów kinematycznych (być może kiedyś we wcześniejszych wersjach?). Ale świat dynamiki zrozumie setWorldTransform () i wywołania getLinearVelocity () na obiekcie kinematycznym zwrócą prędkość ustawioną w wywołaniu zwrotnym tiku (prawdopodobnie zwraca średnią, jeśli prędkości te miałyby się zmienić z wewnętrznego tiku na tik).

https://github.com/bulletphysics/bullet3/issues/1204 - plakat z problemami ma dobry pomysł, ale odpowiedź nie jest pomocna.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.