Unityを使う以上、エンジンにある機能を使っていきたい。
バージョンは2021.3。
エンジン機能をあまり使わない方向についても最後に書く。
物理演算の世界に参加する
Rigidbody2D
と Collider2D
が参加券である。
対象のゲームオブジェクトに Rigidbody2D
と いずれかのCollider2D
の二つを付けるとUnityに物理演算してもらえるようになる。
Rigidbody2D
が挙動を Collider2D
衝突を担当する。
物理演算ステップがいつ実行されるかは、Unityエディタの
- Edit -> Project Setting -> physics 2D ->
Simulation Mode
にて設定されており、デフォルトでは FixedUpdate()
実行後となっている。
例えばこれを Script
とすると Physics2D.Simulate()
をスクリプトで呼び出したときに物理演算ステップが実行される。
Rigidbody2D について
Rigidbody2D
が付けられたゲームオブジェクトにおいては Transform
を直接触らない。Rigidbody2D
が移動すると、それが Transform
へ伝搬する。
Rigidbody2D
は AddForce()
によって動かす。速度を直接変更とかしない。物体に力を加えて加速させ、速度を上げて、移動する。そういうふうに動かす。
Rigidbody2D
への操作は FixedUpdate()
内で行う(Simulation Mode
が FixedUpdata
の場合)、そうすると次の物理演算ステップに反映される。
単純な AddForce()
の場合、物理演算ステップ中ずっと力が加えられる、ような動作になると思う。そのため、固定周期でない Updata()
などで行うと意図しない動作となりやすい。
瞬間的な力を表す ForceMode2D.Impulse
であれば、おそらくその限りではない。
Rigidbody2D
が物理演算によって動くのは Body Type
が Dynamic
の場合のみである。
Static
の場合は固定され動かないし、Kinematic
であればスクリプトが挙動を決める。
一時的に物理演算からはずれたい時は Simulated
を Off にする。
Simulated
が Off な Rigidbody2D
は物理演算から無視される。動かなくなるし、他の Rigidbody2D
とも干渉しない(衝突しなくなる)。
Collider2D について
Collider2D
は Rigidbody2D
に紐付けられる。Rigidbody2D
がない場合は、Body Type
が Static
な Rigidbody2D
として扱われる。
Collider2D
にはいくつか種類があって、自由形状のものは処理が重くなる。
一つの Rigidbody2D
には 複数の Collider2D
を紐づけできるので、基本図形の組み合わせで複雑な形に対応させることも可能。
衝突すると OnCollisionXXX2D()
が呼び出される。
Is Trigger
を On にすると、他の Collider2D
と衝突/反発 しなくなり、重なる/すり抜けるようになる。
この時、OnTriggerXXX2D()
が呼び出される(OnCollisionXXX2D()
は呼ばれない)。
特定の地点を通過したらイベント発生とか、そういう使い方をするのだろうか。
ある領域においては速度が1/2になる、みたいなのも作れそうだが、そういう用途向けには Effector2D
があって、よくある動作が用意されている。
衝突対象は、Layer
(レイヤ) 単位で指定する。
例えば、自キャラ(操作キャラ)と敵キャラは衝突するが敵キャラ同士は衝突しない、とする場合、
自キャラレイヤと敵キャラレイヤをそれぞれ用意し、敵キャラレイヤ-敵キャラレイヤ間は衝突をOffにすればよい。
Unityエディタの
- Edit -> Project Setting -> physics 2D ->
Collision Layer Matrix
でそういう設定を行う。
スクリプトから動的に変更するような他の手段などは見つからなかったので不明。
敵キャラと接触しダメージを受けたら一定時間無敵になる、などしたい場合は、無敵時間レイヤを用意してレイヤを移動すれば良い。
(Is Trigger
を On にする等だと、壁抜けしてしまうので期待する動作にならない)
OnCollisionXXX2D()
、OnTriggerXXX2D()
などのイベント通知系のメソッド内部で重い処理をするのはやめた方が良い気がするので、
これらの中では一時リストへの情報登録などに留め、実際の処理は、次の物理演算ステップ前に行うようにする。
もしくは、OnCollision
、OnTrigger
系は使わず、GetContacts()
と OverlapCollider()
を用いれば、スクリプトの好きな個所で同じ情報を取得できる。
当たり前だが、次の物理演算ステップが実行されたら更新されるので、それより前に呼び出す。
エンジン側からのスクリプト呼び出し回数は少ない方がパフォーマンス的に有利らしいので、こちらの方が良いかもしれない
古い記事なので、いまでもそうかは分からない。
エンジン機能をあまり使わない方向
Simulation Mode
を Script にし Physics2D.Simulate()
を呼び出さなければ、物理演算自体が停止する。
この場合は Collider2D
、Rigidbody2D
共に働かないので、全てを自前で実装しなければならない。
衝突判定は欲しいなら、Rigidbody2D
の Body Type
を Kinematic
に変更し、Use Full Kinematic Contacts
を On にする。
衝突/反発等 しなくなるが OverlapCollider()
で重なっている Collider2D
を取得できるので、それを使って該当処理を実装すればよい。
Use Full Kinematic Contacts
が Off だと、Kinematic
-Kinematic
および Kinematic
-Static
間が干渉しなくなり、お互いの Collider2D
に反応しなくなる。
以上。