Bullet Physics / Ogre3Dを使用したRPGでキャラクターをどのように移動しますか?


9

最近、Ogre3Dゲームでのキャラクターの移動に問題があります。基本的には弾丸のRigidBody->translate()機能でキャラクターを動かしていますが、そうすると壁にぶつかると少し通り抜けて跳ね返ります。壁のある単純な平面タイプの世界で、自分のキャラクター(球の衝突形状を持つ)を移動する別の良い方法があるかどうか疑問に思っていますか?

これに関連する私が使用しているライブラリは、「Ogre3D」と「Bullet Physics」です。

回答:


9

特に弾丸の物理エンジンを使用したことはありませんが、別の物理エンジンで非常によく似たことを行いました。私がそれを解決した方法は、剛体の線速度を直接変換する代わりに設定することでした。その後、動きと衝突は、物理エンジンの更新フェーズによって自動的に処理されました。

ドキュメントがあるようbtRigidBody::setLinearVelocityに使用できる方法。たとえば、加速度を発生させたくない場合は、キャラクターが動いているときは常に線形速度を適切な値に設定し、キャラクターが停止するはずのときに(0,0,0)に戻します(つまり、プレーヤーがキーを離したとき)。

どの値を使用するかについては、通常のアプローチは、キャ​​ラクターの望ましい速度(フロート/スカラーとして)で開始し、次に、移動したい方向を指している正規化されたベクトルを掛けます。私が見ることができるものから、btVector3クラスにはすでにこれらすべてのメソッドがあります。

または、キャラクターを完全な物理オブジェクトとして扱い、applyForceまたはapplyImpulseメソッドを使用して動きを処理することもできます。これらはボディアクセラレーションをもたらすので、キャラクターに勢いがあり、結果はおそらくこの方法で見栄えが良くなります。ただし、たとえば、クランプするか、減衰/摩擦で遊んで、線形速度が特定の制限を超えないようにするなど、追加の対策を講じる必要があります。したがって、実装と微調整が少し難しくなります。

両方の方法を試し、ニーズに最も近い方法を選択してください。


わかりました、すばやい回答をありがとう、私はすぐにこれを試してみるつもりです。
モルマセピック

LinearVelocityトリックは、チャームのように期待どおりに機能しました。私が修正しなければならないいくつかのねじれがありましたが、それは機能しています100%答えに感謝します!
Molmasepic

9

ちなみに、私の物理学の経験は2DゲームエンジンでのChimpunkの使用ですが、この概念が3Dにうまく変換できると確信しています。

あなたのキャラクターは体重などの物理的な体であると想定しています。これを行う最良の方法は、非常に単純化された歩行のシミュレーションを実行することです。次のように考えてください。立っている場合、足には大きな摩擦があるため、ただ滑るだけではありません。動くとき、それはその摩擦を取り除き(足で動きに抵抗していないので)、方向付け力を加えることとほぼ同じです。私はしていない、あなたが個別に地面に押してそれぞれの足をシミュレートする必要があることを言って-剛体は、あなたが望むものです。

  • キャラクターが積極的に動かそうとしないときは、速度減衰を高くして静止したままにします。
  • キャラクターが動いているときは、速度ダンピングを下げて、動きの方向に力を加えます。ダンピングとフォースを設定して、キャラクターが適度な速度で動くようにします。
  • キャラクターが空中にいる場合は、ダンピングを非常に低く設定します。リアルになりたい場合は、空中にいるときに方向を変えるために力を加えないでください。ここでハッピーメディアを攻撃するには、はるかに小さな力を加えて、空中にいるときに軌道を調整するための制限された能力を与えます。

ここでgetが少し複雑になります。

  • キャラクターがすでに動いていて方向を変えている場合は、力を加える方向を調整することで、勢いを補う必要があります。たとえば、キャラクターが真北に移動し、真東に曲がる場合は、キャラクターの現在の移動方向の反対方向と意図した移動方向の中間の方向に力を加える必要があります。移動の方向が変わったら、力が常に2つの中間になるように力を調整します。これにより、キャラクターはすばやくスムーズに方向を変えます。

フォースとダンピングを正しく調整した場合、特にキャラクターがオブジェクトを押しのける場合は、フォースを適用すると常に最もリアルな結果が得られます。物理エンジンは実際にはそれを動きであると見なしていないので、翻訳はそれを行うための最悪の方法になるでしょう。速度を直接設定する方が多少良いですが、私の経験では、フォースとダンピングを使用することで最良の結果を得ることができます。

うまくいけば、私はこれを十分に説明しました。説明が必要な場合は、遠慮なくお尋ねください。:)


0

箇条書き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-問題の投稿者は正しい考えを持っていますが、回答は役に立ちません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.