Unity の機能の中でも、基礎中の基礎とも言える Collision。
参考書の通りにやれば、物理演算に基づいたそれらしい挙動は作れるのですが、実際のところ『Rigidbody』や『Collider』の設定によって細かく挙動の種類分けがなされており、これらをいじっていると、オブジェクト同士が衝突したりしなかったりで苦戦することがあります。
今回は、これらの設定によって変化する『当たり判定の性質の種別』をまとめてみます。
試行環境:Unity 2017.2.1p2
『前編』では、『Rigidbody』と『Collider』の紹介と、それぞれが持つ要素について取り扱いました。
【Unity】Rigidbody や Collider の設定により変化する、当たり判定の性質 前編
『後編』となる本稿では各コンポーネントの設定による具体的な挙動の変化について見ていきます。
↓の公式ドキュメントの一部について解説したような内容になりますので、原文が気になる方はこちらへ。
https://docs.unity3d.com/ja/current/Manual/CollidersOverview.html
目次
1. 3種類の設定
Unity によると、当たり判定の相互作用の種類は、以下の3つが存在します。
- Dynamic Rigidbody Collider(公式の表記は『Rigidbody Collider』ですが、区別を明確にするため『Dynamic』を付けて表記します。)
- Kinematic Rigidbody Collider
- Static Collider
ざっくり言うと、上へ行くほど「動的で負荷が重い」、下へ行くほど「静的で負荷が軽い」という性質。
これらについて、以下で具体的に取り扱っていきます。
2. Dynamic Rigidbody Collider
- 『Rigidbody』と『Collider』を共に持つ
- 『Rigidbody』の『Is Kinematic』が OFF
GameObject に『Rigidbody』と『Collider』をひっつけて、何もいじっていない初期設定のままだと、この状態になります。
ちなみに 2D 用コンポーネントの場合は「『Is Kinematic』が OFF =『Body Type』が『Dynamic』」にあたるため、↓こんな感じ。
(本稿で『Dynamic Rigidbody Collider』と表記しているのは、この表示に基づいています)
この『Dynamic Rigidbody Collider』は、 いわゆる「物理演算に支配されたオブジェクト」になります。
つまり『Rigidbody』の『Use Gravity』にチェックが入っていれば、重力に従って Y軸 マイナス方向に加速し、左から他のオブジェクトがぶつかれば、右への力が加わって弾かれます。
2.1. 挙動の例
- 上の Cube:Dynamic Rigidbody Collider、Use Gravity:ON、Is Trigger:OFF
- 下の Cube:Dynamic Rigidbody Collider、Use Gravity:OFF、Is Trigger:OFF
『Dynamic Rigidbody Collider』同士の衝突例です。
上の Cube は重力に従って落下します。
下の Cube には重力は働きませんが、上の Cube に押される力によって、共に落下していきます。
- 上の Cube:Dynamic Rigidbody Collider、Use Gravity:ON、Is Trigger:OFF
- 下の Cube:Dynamic Rigidbody Collider、Use Gravity:OFF、Is Trigger:ON
『前編』で取り上げた『Collider』の『Is Trigger』をいじったパターンです。
下の Cube が『Trigger』となったことで、衝突による物理的な力の働きは無くなりました。
ただし画面下部のログにも出力している通り、侵入判定を取ることは出来ています*1。
また、以下は個人的な推測ですが…。
『Dynamic Rigidbody Collider』は「物理演算による挙動」を前提としているため、おそらくスクリプト内で『transform.position』や『transform.localPosition』などを直接変更して座標を移動させる、という処理を推奨していないと思われます。
これらを動かす処理をスクリプト中に記述したい場合は、物理演算に基づいた処理である『Rigidbody.AddForce』などを使用すべき、と思われます。
『Transform』をいじるタイプの座標移動処理は、下記『Kinematic Rigidbody Collider』に対して適用しましょう。
3. Kinematic Rigidbody Collider
- 『Rigidbody』と『Collider』を共に持つ
- 『Rigidbody』の『Is Kinematic』が ON
2D 版は「『Is Kinematic』が ON =『Body Type』が『Kinematic』」であるため、↓こんな感じ。
『Kinematic Rigidbody Collider』は「物理演算の影響を受けず、スクリプトで物理挙動を制御するオブジェクト」になります。
ノーコードな開発ならともかく、プログラマが当たり判定を伴うゲームを制作する場合、多くはこれを選択することになると思います。
重力の影響も、他のオブジェクトが衝突した際の挙動も、そのままでは一切の処理が行われません。『前編』で紹介した『OnCollision ~』系の関数などの中に、処理を記述しましょう。
3.1. 挙動の例
- 上の Cube:Dynamic Rigidbody Collider、Use Gravity:ON、Is Trigger:OFF
- 下の Cube:Kinematic Rigidbody Collider、Is Trigger:OFF
下の Cube は衝突の影響を一切受けません。
対して上の Cube は、下の Cube への衝突を感知して、上へ乗る形で停止するようです。
- 上の Cube:Dynamic Rigidbody Collider、Use Gravity:ON、Is Trigger:OFF
- 下の Cube:Kinematic Rigidbody Collider、Is Trigger:ON
下の Cube の『Is Trigger』を ON にしたパターン。
ログ出力の通り、衝突判定はしっかり検知されていますが、上の Cube の物理挙動には直接影響を与えていません。
- 上の Cube:Kinematic Rigidbody Collider、Is Trigger:OFF、落下用スクリプト付き
- 下の Cube:Kinematic Rigidbody Collider、Is Trigger:OFF
上の Cube の自由落下処理をコードで記述した『Kinematic Rigidbody collider』同士の衝突。両者ともにトリガーではない状態。
ログ出力にも表示が無いため、衝突は一切検知されないようです。
ちなみにスクリプトは超シンプルに↓こんなので動かしています。
using UnityEngine;
public class FallDownTest : MonoBehaviour
{
Transform mTransform;
// Use this for initialization
void Start()
{
mTransform = this.transform;
}
// Update is called once per frame
void Update()
{
mTransform.localPosition = mTransform.localPosition + Vector3.down * 0.1f;
}
}
- 上の Cube:Kinematic Rigidbody Collider、Is Trigger:OFF、落下用スクリプト付き
- 下の Cube:Kinematic Rigidbody Collider、Is Trigger:ON
片方をトリガー化したパターン。
こちらの場合は衝突が検知され、コールバック関数が呼ばれるようです。ちょっと不思議ですね。
だんだんと組み合わせがややこしくなって来ましたが、先にリンクを紹介した公式ドキュメント
https://docs.unity3d.com/ja/current/Manual/CollidersOverview.html
の一番下に、コールバック関数が呼ばれるかどうかが、表になってまとまっています。
3.2. 2D コンポーネントの場合…
『Rigidbody 2D』の場合のみ、さらにもう1つ『Use Full Kinematic Contacts』という要素が追加されています。
これを ON にすると『Kinematic Regidbody Collider』同士の衝突を検知できるようになります(上の『挙動の例』3つ目で、検知できていなかったケース)。
- 上の Sprite:Kinematic Rigidbody Collider、Is Trigger:OFF、Use Full Kinematic Contacts:ON、落下用スクリプト付き
- 下の Cube:Kinematic Rigidbody Collider、Is Trigger:OFF、Use Full Kinematic Contacts:OFF
トリガー化されていないオブジェクト同士でも、衝突を検知することが可能になっています。
衝突を見る対象が増えるため、おそらく処理についても、一段階重いものになっていると思われます。この辺りいつか検証してみたい。
『Rigidbody 2D』の詳しい特徴については↓こちら
https://docs.unity3d.com/ja/current/Manual/class-Rigidbody2D.html
4. Static Collider
- 『Collider』のみを持ち『Rigidbody』を持たない
最も静的なケースで、つまるところ「当たり判定は持つけれど、動かないオブジェクト」を前提としています。多くの場合、マップ地形などがこれにあたると思われます。
↓ 2D コンポーネントでは「『Body Type』が『Static』」のケースがこれにあたります。2D の場合は『Rigidbody 2D』を持たせておくことが許容されるのですね。
おそらく、動かさない限りは最も処理負荷が少ないケースです。ただし公式ドキュメントによると「これを勝手に動かす(含スケーリング)と、物理演算処理のパフォーマンスが著しく低下する」ようです。
おそらく物理演算において、衝突を検知する対象の中で動くオブジェクトは『Dynamic ~』と『Kinematic ~』に限られ、『Static Rigidbody Collider』は動かない、という前提で処理を行っているものだ、と推測されます。
5. おわりに
当たり判定をエンジンで持たせると、いろいろと処理が重くなるんじゃないかと思いますが、そこでなるべく軽量化するように Unity の機能を使って小手先の調整を行う際に、注意しておきたい情報をまとめてみました。
だいたいは例の公式ドキュメントの表を、実験したという感じです。また必要に応じて追記などできればと思います。
*1:本稿の動画において、ログ出力のスクリプトはすべて『上の Cube 側』に貼り付けています。
共同の図解についてですが、上下の箱が同色なのでぱっと見で分かりづらいと思うので、色を変えてみるといいのでは?と思いました。