如何使用Bullet Physics / Ogre3D在RPG中移动角色?


9

最近,我在Ogre3D游戏中移动角色时遇到了问题。基本上,我使用子弹的RigidBody->translate()功能来移动角色,但是当这样做并撞到墙上时,我会略微穿过它,然后弹回去。我想知道是否有另一种好的方法可以在一个带有墙壁的简单平面世界中移动我的角色(具有球形碰撞形状的角色)?

我正在使用的与此相对的库是“ Ogre3D”和“子弹物理学”。

Answers:


9

尽管我没有专门使用子弹物理引擎,但在另一个物理引擎中我做过非常相似的事情。我解决该问题的方法是设置刚体的线速度,而不是直接平移它。然后,物理引擎更新阶段会自动处理运动和碰撞。

文档中看来btRigidBody::setLinearVelocity,您可以使用一种方法。因此,例如,如果您不希望发生任何加速,只需在角色移动时将线速度设置为适当的值,并在角色应该停止时将其重新设置为(0,0,0)(即,当玩家释放钥匙时)。

至于要使用的值,通常的方法是从所需的字符速度(以浮点数/标量)开始,然后将其乘以指向要移动方向的归一化向量。从我可以看到,btVector3该类已经具有用于所有这些方法的方法。

或者,您可以考虑将角色视为完整的物理对象,并使用applyForceapplyImpulse方法处理运动。这些将导致身体加速,因此您的角色将具有动量,并且结果看起来可能会更好。但是您需要采取一些额外的措施,例如,通过夹紧或通过阻尼/摩擦来确保线速度永远不会超过某个极限。因此,实施和调整会有些困难。

尝试两种方法,然后选择行为最接近您的需求的方法。


好吧,感谢您的快速回答,我将立即尝试尝试。
Molmasepic'3

LinearVelocity技巧就像一个魅力一样发挥了预期!我必须解决一些问题,但它可以正常工作100%非常感谢您的回答!
Molmasepic'3

9

记录下来,我的物理经验是在2D游戏引擎中使用Chimpunk,但我很确定这个概念可以很好地转化为3D。

我假设您的角色是一个具有重量之类的物理物体。最好的方法是对步行进行非常简化的模拟。可以这样想:如果您站着,脚会有很大的摩擦,所以您不能只是左右滑动。移动时,这大致相当于消除该摩擦(因为您不会用脚抵抗运动)并施加方向力。我并不是说您应该单独模拟每只脚在地面上的推动力-刚需要的是刚体。

  • 当您的角色不积极尝试移动时,请使其速度阻尼较高,以使其保持静止。
  • 当您的角色移动时,降低其速度阻尼并在移动方向上施加力。设置阻尼和力,以使角色以合理的速度移动。
  • 如果角色在空中,则将阻尼设置得非常低。如果您想求实,则不要让他们在空中时施加任何力来改变方向。您可以通过允许他们施加小得多的力在这里击中一个快乐的介质,从而使他们在空中出生时调整其弹道的能力有限。

在这里,获取变得有些复杂:

  • 如果角色已经在移动并且他们改变了方向,则需要通过调整施加力的方向来补偿动量。例如,如果角色正在向北移动并向东转向,则需要在角色当前行进方向与其预期行进方向相反的方向上施加力。随着行进方向的改变,调整力,使其始终位于两者之间的一半,您的角色将迅速而顺畅地改变方向。

如果正确调整力和阻尼,施加力将始终为您提供最真实的结果,尤其是在角色要向周围推物体的情况下。翻译将是最糟糕的方法,因为物理引擎并不真正将其视为运动。直接设置速度会更好一些,但以我的经验,通过使用力和阻尼可以获得最佳效果。

希望我对此做了足够的解释。随时询问您是否需要澄清。:)


0

对于项目符号2.87,看来正确的方法是有一个滴答回调,该回调以内部模拟更新速率(可能是100 Hz的许多频率)进行更新,并且运动主体上的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()将返回滴答回调中设置的速度(如果这些速度从内部滴答变化到滴答,它可能会返回平均值)。

https://github.com/bulletphysics/bullet3/issues/1204-问题发布者有正确的主意,但回应无济于事。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.