Как перенести персонажа в RPG с помощью Bullet Physics /Ogre3D?

В последнее время у меня были проблемы с перемещением моего персонажа в моей игре Ogre3D. В основном я перемещаю персонажа с помощью функции RigidBody->translate() пули, но когда вы делаете это и натыкаетесь на стену, я немного пропускаю ее, а затем получаю возвращаться. Мне интересно, есть ли еще один хороший способ перенести моего персонажа (который имеет сферическую форму столкновения) вокруг в простом мире типа Plane со стенами?

Библиотеки, которые я использую, относятся к этому: «Ogre3D» и «Bullet Physics».

9 голосов | спросил Molmasepic 1 MaramThu, 01 Mar 2012 08:09:57 +04002012-03-01T08:09:57+04:0008 2012, 08:09:57

3 ответа


9

Хотя я не работал с движком физики пули, я сделал что-то очень похожее в другом физическом движке. Способ, которым я решил это, - установить линейную скорость жесткого тела, а не переводить его напрямую. Затем движение и столкновения автоматически обрабатывались фазой обновления физического ядра.

Из документации , похоже, есть btRigidBody::setLinearVelocity, который вы можете использовать. Например, если вам не нужны какие-либо ускорения, просто установите линейную скорость в соответствующее значение всякий раз, когда символ движется, и установите его обратно на (0,0,0), когда символ должен остановиться (т. Е. когда игрок отпускает ключ).

Что касается используемых значений, обычным подходом было бы начать с желаемой скорости вашего персонажа (как float /scalar), а затем умножить его на нормализованный вектор, указывающий в направлении, которое вы хотите переместить. Из того, что я вижу, у класса btVector3 уже есть методы для всего этого.

В качестве альтернативы вы можете рассмотреть обращение к символу как к полному физическому объекту и обработать движение, используя либо applyForce, либо applyImpulse. Это приведет к ускорению тела, поэтому ваши персонажи будут иметь импульс, и результаты, вероятно, будут выглядеть лучше. Но вам нужно предпринять некоторые дополнительные меры, например, убедившись, что линейная скорость никогда не превышает определенного предела, либо зажав ее, либо играя с демпфированием /трением. Таким образом, это будет немного сложнее реализовать и завершить.

Экспериментируйте с обоими подходами, а затем выберите тот, который будет наиболее близким к вашим потребностям.

ответил David Gouveia 1 MaramThu, 01 Mar 2012 08:24:06 +04002012-03-01T08:24:06+04:0008 2012, 08:24:06
9

Для записи мой опыт работы с физикой использует Chimpunk в 2D игровом движке, но я уверен, что эта концепция полностью преобразуется в 3D.

Я предполагаю, что ваш персонаж - физическое тело с весом и таковым. Лучший способ сделать это - сделать очень упрощенную симуляцию ходьбы. Подумайте об этом так: если вы стоите, у ваших ног много трения, поэтому вы не просто скользите. Когда вы двигаетесь, это примерно эквивалентно устранению этого трения (поскольку вы не сопротивляетесь движению ногами) и применяете силу направления. Я не , говоря, что вы должны индивидуально имитировать каждую ногу, толкающую землю - жесткое тело - это то, что вы хотите.

  • Когда ваш персонаж не будет активно пытаться двигаться, сделайте их скорость демпфирования высокой, чтобы они оставались неподвижными.
  • Когда ваш персонаж движется, опускайте свое демпфирование скорости и применяйте силу в направлении движения. Установите затухание и силу так, чтобы персонаж двигался с разумной скоростью.
  • Если персонаж находится в воздухе, установите затухание очень, очень низко. Если вы хотите быть реалистичными, не позволяйте им применять какую-либо силу для изменения своего направления в воздухе. Вы можете поразить счастливую среду здесь, разрешив им применять гораздо меньшую силу, предоставляя им ограниченную способность корректировать траекторию движения в воздухе.

Вот где get становится немного сложнее:

  • Если персонаж уже движется и они меняют направление, вам нужно будет компенсировать свой импульс, настроив направление, в котором вы применяете силу. Например, если ваш персонаж движется из-за севера и поворачивается на восток, вам нужно применить силу в направлении, которое находится на полпути между противоположностью текущего направления движения персонажа и предполагаемым направлением движения. По мере изменения направления движения, отрегулируйте силу так, чтобы она всегда находилась на полпути между ними, и ваш персонаж быстро и плавно менял направления.

Если вы настроите свою силу и демпфирование правильно, применение силы всегда даст вам наиболее реалистичный результат, особенно если персонаж будет толкать предметы вокруг. Перевод будет худшим способом сделать это, так как физический движок не считает, что это движение. Настройка скорости непосредственно несколько лучше, но, по моему опыту, лучшие результаты могут быть получены с помощью силы и демпфирования.

Надеюсь, я объяснил это достаточно хорошо. Не стесняйтесь спрашивать, нуждаетесь ли вы в разъяснении. :)

ответил Lendrick 1 MaramThu, 01 Mar 2012 08:46:46 +04002012-03-01T08:46:46+04:0008 2012, 08:46:46
0

Для пули 2.87, по-видимому, правильным методом является обратный вызов тика, который обновляется при частоте обновления внутреннего моделирования (возможно, много 100 Гц), и setWorldTransform () в кинематических телах плавно обновляет положение:

Эта часть находится в руководстве:

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

Эта часть была более сложной, чтобы понять:

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

Это была полезная документация в btRigidBody.h https : //github.com/bulletphysics/bullet3/blob/master/src/BulletDynamics/Dynamics/btRigidBody.h :

  

///- C) Кинематические объекты, которые являются объектами без массы, но пользователь может их перемещать. Существует одностороннее взаимодействие, и Bullet вычисляет скорость, основанную на временном и предыдущем и текущем мировом преобразовании.

setLinearVelocity () не работает для кинематических объектов (возможно, он использовался в более ранних версиях?). Но мир динамики поймет setWorldTransform (), и вызовы getLinearVelocity () на кинематическом объекте вернут скорость, установленную в обратном вызове tick (это, вероятно, возвращает среднее значение, если эти скорости должны были измениться с внутреннего тика на галочку).

https://github.com/bulletphysics/bullet3/issues/1204 - плакат с вопросами имеет правильную идею, но ответ не помогает.

ответил Lucas W 18 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 18 Sep 2018 17:38:22 +0300 2018, 17:38:22

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132