テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Rigidbody2Dの新しい設定「Dynamic」「Kinematic」「Static」と「Simulated」の使い分け

Unity 5.5からRigidbody2Dの表示が新しくなり、新しいパラメータも追加されました。その内容が凄く分かりにくいので、確認がてらメモします。

「Dynamic」「Kinematic」「Static」

f:id:tsubaki_t1:20160911212643j:plain

Body Typeに新しくDynamicやKinemac、Staticが追加されました。

用途は大体こんな感じみたいです。

  • Dynamic
    物理演算で移動するオブジェクト
  • Kinematic
    スクリプトで動かすオブジェクト
  • Static
    原則移動しない、稀に再配置もしくはOn・OFFするオブジェクト
  • Rigidbody2d無し
    動かさない。

Dynamicは今までどおりのRigidbody2dです。

問題はKinematicとStaticで、この辺りで意味がわかりにくくなります。

KinematicとUse Full Kinematic Contacts

Kinematicの設定にUseFullKinematicContactsという設定が追加されました。この設定の有無は、DynamicもしくはUseFullKinematicContactsを設定したコライダーに接触するかどうかの判定みたいです。

f:id:tsubaki_t1:20160911215655j:plain

UseFullKinematicContactsにチェックの付いていないRigidbodyは、Staticもしくは同様にUseFullKinematicContactsにチェックの付いていないRigidbodyとは接触しないみたいです。

これは少し分かりにくいです。

f:id:tsubaki_t1:20160911214852j:plain

 

例えば下のようなステージがあったとします。赤い地面が上下に動き、プレイヤーのロボが入ったら死ぬ…という奴です。当然、左右のブロックにも当たり判定があります。

f:id:tsubaki_t1:20160911214546j:plain

これ、赤い地面が「接触した対象を消す」みたいなコードを書いていると、周囲の床を判定して消してしまいます。

f:id:tsubaki_t1:20160911224318j:plain

この例では、赤い地面にはUseFullKinematicContactsの無いKinematicを設定します。

これで、地面を動かしても周囲の地面と接触する事を避ける事我できます。また、コールバックイベントの発生を抑えられるので、パフォーマンス的に劇的に有利です。

さらにStaticでは無いので、Rigidbody無しでコライダーを動かした時のペナルティも無いです。

f:id:tsubaki_t1:20160911224534j:plain

Staticは動かさない、動けない

Staticは「動かさない事」を前提にしているので、FixedUpdate等によるコストが0になります。ステージ上に大量に配置しても殆どコストが発生しません。(動かさないならば)
この「動かす」はコライダーのON/OFFやActiveの切替も含まれます。

Rigidbody2D無しコライダーとRigidbody2D Staticは「動かしてはいけない」点で同様ですが、Rigidbody2D StaticはSimulatedでコライダーを効率的に無効化出来るみたいです。

Simulatedは物理演算と当たり判定をOFFにする

多分今回の変更で最も大きな要素が、SimulatedのON/OFFです。

f:id:tsubaki_t1:20160911215707j:plain

このSimulated機能は、物理演算の挙動だけでなく、コライダーの判定も有効・無効にする機能です。例えばSimulatedをOFFにすると、下のような挙動を行うみたいです。

  • 物理演算の機能が停止
  • コライダーの判定を行わなくなる
    Physics.OverlapCircleNonAlloc等にも反応しなくなる
  • Join系の接続も外れる(ONにすると戻ってくる)

つまり、念願のRigidbodyのenableみたいなもんです。
なんでsimulatedなんて分かりにくい名前なのか…

オブジェクトプール時に良いカモ

Simulatedは、主にShootingでObjectPoolingするようなケースで有効かなと思います。というのも、

  • Rigidbody2DはOFFにする方法は提供されていなかった
  • GameObjectを非アクティブにするとOFFにできるが、GameObjectを非アクティブにするコストが発生する
    (例えば、物理演算のパラメータやコライダーのシェイプ情報等がGameObjectのアクティブ切替で破棄・再構築される)

なる問題により、オブジェクトのアクティブ切替によるコストがオブジェクトプーリングで使い回す事により得られるコストを圧迫するケースがある為です。*1

これをRendererとRigidbody.simulatedの切替に変更すると、それなりのパフォーマンスが稼げます。
試しにPCでSpriteとColliderとRigidbody2Dのセットを1000個程、アクティブ切替した物とsimulated&Renderer切替したもので比較してみます。

f:id:tsubaki_t1:20160911224001j:plain

 関連

docs.unity3d.com

tsubakit1.hateblo.jp

*1:特にAnimatorとCollider・Rigidbody、CanvasRendererは大きなコストになってたと思います