Bagaimana saya memindahkan karakter Dalam RPG dengan Bullet Physics / Ogre3D?

9

akhir-akhir ini saya mengalami masalah dengan memindahkan karakter saya di game Ogre3D saya. Pada dasarnya saya memindahkan karakter dengan RigidBody->translate()fungsi peluru , tetapi ketika melakukannya dan menabrak dinding, saya sedikit melewatinya dan kemudian bangkit kembali. Saya bertanya-tanya apakah ada cara lain yang baik untuk memindahkan karakter saya (yang memiliki bentuk benturan bola) di dalam dunia tipe-pesawat sederhana dengan dinding?

Perpustakaan yang saya gunakan yang relatif terhadap ini adalah 'Ogre3D' dan 'Bullet Physics'.

Molmasepic
sumber

Jawaban:

9

Walaupun saya belum pernah bekerja dengan mesin fisika peluru, saya telah melakukan sesuatu yang sangat mirip pada mesin fisika lain. Cara saya memecahkannya adalah dengan mengatur kecepatan linear tubuh kaku daripada menerjemahkannya secara langsung. Gerakan dan tabrakan kemudian secara otomatis ditangani oleh fase pembaruan mesin fisika.

Dari dokumentasi sepertinya ada btRigidBody::setLinearVelocitymetode yang dapat Anda gunakan. Jadi misalnya, jika Anda tidak ingin terjadi akselerasi, cukup atur kecepatan linier ke nilai yang sesuai setiap kali karakter bergerak, dan atur kembali ke (0,0,0) ketika karakter seharusnya berhenti (yaitu ketika pemain melepaskan kunci).

Adapun nilai yang digunakan, pendekatan yang biasa akan dimulai dengan kecepatan yang diinginkan dari karakter Anda (sebagai float / skalar) dan kemudian kalikan dengan vektor yang dinormalisasi yang menunjuk ke arah yang ingin Anda pindahkan. Dari apa yang saya lihat btVector3kelas sudah memiliki metode untuk semua ini.

Sebagai alternatif, Anda dapat mempertimbangkan memperlakukan karakter sebagai objek fisika lengkap, dan menangani gerakan menggunakan metode applyForceatau applyImpulse. Ini akan menghasilkan akselerasi tubuh, sehingga karakter Anda akan memiliki momentum dan hasilnya mungkin akan terlihat lebih baik dengan cara ini. Tetapi Anda perlu mengambil beberapa langkah tambahan, misalnya, dengan memastikan kecepatan linier tidak pernah melebihi batas tertentu, baik dengan menjepitnya atau bermain-main dengan redaman / gesekan. Jadi akan sedikit lebih sulit untuk mengimplementasikan dan finetune.

Percobaan dengan kedua pendekatan dan kemudian pilih salah satu yang berperilaku paling dekat dengan kebutuhan Anda.

David Gouveia
sumber
Baiklah, terima kasih atas jawaban cepatnya, saya akan segera mencoba ini.
Molmasepic
Trik LinearVelocity berfungsi seperti yang diharapkan seperti pesona! Ada beberapa ketegaran yang harus saya perbaiki tetapi ini bekerja 100% Terima kasih banyak atas jawabannya!
Molmasepic
9

Sebagai catatan, pengalaman saya dengan fisika menggunakan Chimpunk di mesin game 2D, tapi saya cukup yakin konsep ini diterjemahkan menjadi 3D.

Saya berasumsi bahwa karakter Anda adalah tubuh fisika dengan berat dan semacamnya. Cara terbaik untuk melakukan ini adalah melakukan simulasi berjalan yang sangat sederhana. Pikirkan seperti ini: Jika Anda berdiri, kaki Anda memiliki banyak gesekan, jadi Anda tidak hanya meluncur. Saat bergerak, kira-kira sama dengan menghilangkan gesekan itu (karena Anda tidak menahan gerakan dengan kaki) dan menerapkan gaya arah. Saya tidak mengatakan bahwa Anda harus secara individual mensimulasikan setiap kaki yang mendorong ke tanah - tubuh yang kaku adalah yang Anda inginkan.

  • Ketika karakter Anda tidak secara aktif mencoba bergerak, buat kecepatannya redam tinggi sehingga mereka akan tetap diam.
  • Saat karakter Anda bergerak, turunkan peredaman kecepatannya dan berikan gaya ke arah gerakan. Atur redaman dan kekuatan Anda sehingga karakter bergerak dengan kecepatan yang masuk akal.
  • Jika karakter ada di udara, atur redaman sangat, sangat rendah. Jika Anda ingin bersikap realistis, jangan biarkan mereka menerapkan kekuatan apa pun untuk mengubah arah saat berada di udara. Anda dapat menyerang media yang bahagia di sini dengan memungkinkan mereka untuk menerapkan kekuatan yang jauh lebih kecil, memberi mereka beberapa kemampuan terbatas untuk menyesuaikan lintasan mereka saat mengudara.

Di sinilah menjadi sedikit rumit:

  • Jika karakter sudah bergerak dan mereka berubah arah, Anda harus mengimbangi momentum Anda dengan menyesuaikan arah di mana Anda menerapkan gaya. Misalnya, jika karakter Anda bergerak ke utara dan berbelok ke timur, Anda perlu menerapkan kekuatan Anda ke arah yang setengah jalan antara kebalikan dari arah perjalanan karakter saat ini dan arah perjalanan yang dituju. Saat arah perjalanan berubah, sesuaikan gaya sehingga selalu setengah jalan di antara keduanya, dan karakter Anda akan dengan cepat dan lancar mengubah arah.

Jika Anda menyesuaikan kekuatan dan redaman dengan benar, menerapkan gaya akan selalu memberi Anda hasil yang paling realistis, terutama jika karakter akan mendorong benda-benda. Menerjemahkan akan menjadi cara terburuk untuk melakukannya, karena mesin fisika tidak benar-benar menganggap itu sebagai gerakan. Mengatur kecepatan secara langsung agak lebih baik, tetapi dalam pengalaman saya, hasil terbaik dapat diperoleh dengan menggunakan gaya dan redaman.

Semoga saya menjelaskan ini dengan cukup baik. Jangan ragu untuk bertanya apakah Anda perlu klarifikasi. :)

Lendrick
sumber
0

Untuk bullet 2.87 tampaknya metode yang tepat adalah memiliki tick callback yang memperbarui pada kecepatan pembaruan simulasi internal (mungkin banyak 100-an Hz), dan setWorldTransform () pada badan kinematik akan dengan lancar memperbarui posisi:

Bagian ini ada di manual:

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

Bagian ini lebih sulit untuk dipahami:

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);

Ini adalah dokumentasi yang bermanfaat di btRigidBody.h https://github.com/bulletphysics/bullet3/blob/master/src/BulletDynamics/Dynamics/btRigidBody.h :

/// - C) Objek kinematik, yang merupakan objek tanpa massa, tetapi pengguna dapat memindahkannya. Ada interaksi satu arah, dan Bullet menghitung kecepatan berdasarkan timestep dan transformasi dunia sebelumnya dan saat ini.

setLinearVelocity () tidak berfungsi untuk objek kinematik (mungkin dulu di versi sebelumnya?). Tetapi dunia dinamika akan memahami setWorldTransform () dan panggilan untuk getLinearVelocity () pada objek kinematik akan mengembalikan kecepatan yang ditetapkan dalam tick callback (ini mungkin mengembalikan rata-rata jika kecepatan itu berubah dari tick internal ke tick).

https://github.com/bulletphysics/bullet3/issues/1204 - poster masalah memiliki ide yang tepat tetapi responsnya tidak membantu.

Lucas W
sumber