[Unity] positionとMovePositionの違いを比べた

正直前回の記事のおまけ程度にかこうと思ったんだけど、調べ方が悪いのか予想外の挙動をするので理解するのに手間取った。

あらかじめRigidbodyは取得しておいて..

Rigidbody rigid; public float speed; void Start () { rigid = GetComponent<Rigidbody>(); }
speedは任意で設定します。

positionの操作

void FixedUpdate(){
  rigid.position = transform.position + transform.forward * speed * Time.deltaTime;

これはスムーズに移動しているように見えるけど、実際はフレームごとにテレポートを繰り返してるような状態です。

MovePositionの操作

 void FixedUpdate(){
  rigid.MovePosition(transform.position + transform.forward * speed * Time.deltaTime);

前提として、MovePositionを使う場合はRididbodyのis Kinematicにチェックを入れていないと意味がないです。positionの操作と変わらない挙動になります。(ドキュメントに書いてます)
そして、is Kinematicにチェックが入っていると物理的な干渉を受けなくなります。
例えばUse Gravityにチェックが入っていても無視されるし、別のオブジェクトがぶつかっても動きません。
その代わり周りのオブジェクトに対しては干渉するようになります。

positionを操作してもある程度干渉は起こるけど、正確な物理特性は考慮されません。

MovePositoinを使うとRigidbodyを介して,現在の物理特性が周りのオブジェクトに影響します。positionの操作と違って動作が連続しているように見えると思います。




動作が連続している『ように見える』という言い方をしたのはすり抜け現象が起きることがあるからです。

結局のところ、どちらもワープしてます。その上でMovePositionはis Kinematicをチェックすると更新時に物理特性を伝播できます。


MovePosition時のすり抜け

ここからはおまけ的要素です。こっちを先に検証したばっかりに混乱した..

ドキュメントには
Rigidbody.MovePositionを呼び出すと、レンダリングされた中間フレームの2つの位置の間でスムーズに移行します。これは、各FixedUpdateで剛体を連続的に移動する場合に使用します。

とある。スムーズに移行ってことはフレーム間で衝突判定を補完するってこと? じゃあそのフレーム間で動く距離を大きくして、その間にオブジェクトを配置したらすごい勢いで吹っ飛ぶんじゃないか?と思い試したてみた。
分かりやすくするために意図的にスロー再生のようにしてます。


いたって平和なもんです。いわゆるすり抜けとか壁抜けとか言うやつ。

すり抜け現象で検索すればたくさんヒットするので詳しい解説は省くけど、要は移動速度が早すぎて(更新間隔が空きすぎて)アップデートごとの衝突判定をすり抜けてしまう現象。これを防ぐにはいくつか方法があるようで
  • 壁を分厚くする
  • スピードを落とす
  • FixedTimeStepを小さくする(FixedUpdateが呼ばれる頻度を増やす)
  • Collision Detectionの設定を変える
などなど。今回は手っ取り早いので一番下のCollision Detectionを試してみる。
inspectorからRigidbodyのCollisionDetectionをContinuousDynamicに。これはフレーム間の衝突判定を補間してくれるようです。


無事に楽しげな動きになりました。
ちなみにContinuousでは衝突しませんでした。MovePositionで連続衝突を検知させたい場合はContinuous Dynamicにしないとダメなようです。



コメント