Answers:
尽管我没有专门使用子弹物理引擎,但在另一个物理引擎中我做过非常相似的事情。我解决该问题的方法是设置刚体的线速度,而不是直接平移它。然后,物理引擎更新阶段会自动处理运动和碰撞。
从文档中看来btRigidBody::setLinearVelocity
,您可以使用一种方法。因此,例如,如果您不希望发生任何加速,只需在角色移动时将线速度设置为适当的值,并在角色应该停止时将其重新设置为(0,0,0)(即,当玩家释放钥匙时)。
至于要使用的值,通常的方法是从所需的字符速度(以浮点数/标量)开始,然后将其乘以指向要移动方向的归一化向量。从我可以看到,btVector3
该类已经具有用于所有这些方法的方法。
或者,您可以考虑将角色视为完整的物理对象,并使用applyForce
或applyImpulse
方法处理运动。这些将导致身体加速,因此您的角色将具有动量,并且结果看起来可能会更好。但是您需要采取一些额外的措施,例如,通过夹紧或通过阻尼/摩擦来确保线速度永远不会超过某个极限。因此,实施和调整会有些困难。
尝试两种方法,然后选择行为最接近您的需求的方法。
记录下来,我的物理经验是在2D游戏引擎中使用Chimpunk,但我很确定这个概念可以很好地转化为3D。
我假设您的角色是一个具有重量之类的物理物体。最好的方法是对步行进行非常简化的模拟。可以这样想:如果您站着,脚会有很大的摩擦,所以您不能只是左右滑动。移动时,这大致相当于消除该摩擦(因为您不会用脚抵抗运动)并施加方向力。我并不是说您应该单独模拟每只脚在地面上的推动力-刚需要的是刚体。
在这里,获取变得有些复杂:
如果正确调整力和阻尼,施加力将始终为您提供最真实的结果,尤其是在角色要向周围推物体的情况下。翻译将是最糟糕的方法,因为物理引擎并不真正将其视为运动。直接设置速度会更好一些,但以我的经验,通过使用力和阻尼可以获得最佳效果。
希望我对此做了足够的解释。随时询问您是否需要澄清。:)
对于项目符号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-问题发布者有正确的主意,但回应无济于事。