回答:
特に弾丸の物理エンジンを使用したことはありませんが、別の物理エンジンで非常によく似たことを行いました。私がそれを解決した方法は、剛体の線速度を直接変換する代わりに設定することでした。その後、動きと衝突は、物理エンジンの更新フェーズによって自動的に処理されました。
ドキュメントがあるようbtRigidBody::setLinearVelocity
に使用できる方法。たとえば、加速度を発生させたくない場合は、キャラクターが動いているときは常に線形速度を適切な値に設定し、キャラクターが停止するはずのときに(0,0,0)に戻します(つまり、プレーヤーがキーを離したとき)。
どの値を使用するかについては、通常のアプローチは、キャラクターの望ましい速度(フロート/スカラーとして)で開始し、次に、移動したい方向を指している正規化されたベクトルを掛けます。私が見ることができるものから、btVector3
クラスにはすでにこれらすべてのメソッドがあります。
または、キャラクターを完全な物理オブジェクトとして扱い、applyForce
またはapplyImpulse
メソッドを使用して動きを処理することもできます。これらはボディアクセラレーションをもたらすので、キャラクターに勢いがあり、結果はおそらくこの方法で見栄えが良くなります。ただし、たとえば、クランプするか、減衰/摩擦で遊んで、線形速度が特定の制限を超えないようにするなど、追加の対策を講じる必要があります。したがって、実装と微調整が少し難しくなります。
両方の方法を試し、ニーズに最も近い方法を選択してください。
ちなみに、私の物理学の経験は2DゲームエンジンでのChimpunkの使用ですが、この概念が3Dにうまく変換できると確信しています。
あなたのキャラクターは体重などの物理的な体であると想定しています。これを行う最良の方法は、非常に単純化された歩行のシミュレーションを実行することです。次のように考えてください。立っている場合、足には大きな摩擦があるため、ただ滑るだけではありません。動くとき、それはその摩擦を取り除き(足で動きに抵抗していないので)、方向付け力を加えることとほぼ同じです。私はしていない、あなたが個別に地面に押してそれぞれの足をシミュレートする必要があることを言って-剛体は、あなたが望むものです。
ここでgetが少し複雑になります。
フォースとダンピングを正しく調整した場合、特にキャラクターがオブジェクトを押しのける場合は、フォースを適用すると常に最もリアルな結果が得られます。物理エンジンは実際にはそれを動きであると見なしていないので、翻訳はそれを行うための最悪の方法になるでしょう。速度を直接設定する方が多少良いですが、私の経験では、フォースとダンピングを使用することで最良の結果を得ることができます。
うまくいけば、私はこれを十分に説明しました。説明が必要な場合は、遠慮なくお尋ねください。:)
箇条書き2.87の場合、適切な方法は、内部シミュレーションの更新レート(おそらく数百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-問題の投稿者は正しい考えを持っていますが、回答は役に立ちません。