本日のテーマ
『当たり判定』や『トリガー』きの要となる
「Collider」をマスターしよう!
当記事は、出来るだけわかりやすく書いておりますが、
「Colliderを迷わず使いこなす!」そんな内容になっているため、
正直言って長いです。
もし、単純に設定だけを知りたいという場合には、以下をご覧ください。
「当たり判定」の設定方法
⇒ 「『当たり判定』の設定方法を詳しく解説!」
「Trigger」の設定方法
⇒ 「『Trigger』の設定方法を詳しく解説!」
「壁すり抜け」に困っている方
⇒ 「オブジェクトが壁をすり抜けるときの対処法」
『Collider(コライダー)』について
それでは、ゲーム制作には欠かせない「Collider」について説明していきます。
Colliderとは
「Collider」とは「当たり判定」や「トリガー」を利用するときに、
ゲームオブジェクトにつける図形(形状)のことです。
「Collider」をキャラクターのGameObjectにアタッチすると、
Scene画面において以下のような緑色の図形が表示されます。
余談ですが、オブジェクトにColliderなどを付けることを『アタッチする』といいます。
この緑色の「Collider」同士が接触することにより、
「当たり判定」や「トリガー」が発生するわけです。
ですので、接触するすべてのオブジェクトに「Collider」をつける必要があります。
「Collider」のついていないGameObjectには、「当たり」は発生しないので、
背景なんかのGameObjectには付ける必要がないですね。
では、「Collider」にはどのような種類があるのでしょうか。
Colliderの種類
・Circle Collider 2D :円形
・Box Collider 2D :正方形・長方形
・Polygon Collider 2D :多角形
・Edge Collider 2D :線で自由に描く
・Capsule Collider 2D :円形・ひし形
・Composite Collider 2D :BoxCollider2DとPolygonCollider2Dの融合型
・Box Collider :立方体
・Sphere Collider :球体
・Capsule Collider :円柱
・Mesh Collider :メッシュに基づくコライダー
・Wheel Collider :陸上車用の特殊コライダー
・Terrain Collider :Terrain Dataに基づくコライダー
特殊なものも含めてこんな感じになります。用途に合わせて使い分けましょう。
1つのGameObjectに複数の「Collider」をアタッチするのは問題ありません。
「Collider」を組み合わせて、理想の「当たり」を作り上げましょう。
とはいえ、処理の問題もあるので付けすぎには注意してください。
上記の「Collider」一覧を見ていると、
2Dのついたものとついていないものの2種類あるが・・・
Colliderの2Dと3Dの違い
「Collider」には2D用のColliderと3D用のColliderがあります。
2Dオブジェクトには、2DのついたColliderを、
3Dオブジェクトには、2DのついていないColliderを使うことになります。
上記の「Collider」一覧で太字で表記されたものがあるが・・・
Colliderの正しい使い方
太字になっている「Collider」はプリミティブなコライダーと呼ばれ、
単純な構造ゆえ負荷が小さい(ゲームが重くなりにくい)Colliderとなっています。
それ以外のCollliderは複雑な構造で非常に負荷が大きいため、
極力使用を控えたほうが良いみたいです。
うまくプリミティブなコライダーを組み合わせて使うのが正しい使い方のようです。
オブジェクトに『Collider』をつけることで「当たり判定」や「トリガー」が発生する
ということは分かったけど、
「当たり判定」では物理的な接触が起こるが、「トリガー」では物理的な接触は起きない。
2つにはこのような決定的な違いがあるのに、『Collider』だけで大丈夫なの?
どうやって使い分けるの?
というわけで、続いては『Collider』の設定を見ていくことにしましょう。
『Collider』の設定方法
何はともあれ、「当たり判定」や「トリガー」を行いたいGameObjectに
「Collider」をアタッチします。
GameObjectに「Collider」をアタッチして、初めて「当たり」が発生します。
Colliderの設定
今回は、TestObjectを作って、そこに「Box Collider 2D」をアタッチしてみました。
EditColliderというボタンをクリックすることで(画像3)、
Scene画面でコライダー(緑の枠)のサイズや位置を変更することができます。
下部にあるSizeやOffsetから直接数値を入力することでも変更可能です。(画像4)
基本の設定は以上となります。
では、「当たり判定」と「トリガー」の区別をつける設定はどこになるか。
それは「Is Trigger」という項目になります。
『両方の「Is Trigger」のチェックが外れていると「当たり判定」が発生し、
いずれか一方の「Is Trigger」にチェックが入っていると「トリガー」が発生します』
両方の「Is Trigger」のチェックが外れているときのみ「当たり判定」が発生する
ということをしっかり覚えておいてください。
「Is Trigger」に関する詳しいことはこちらの記事をお読みください。
「『Is Trigger』が2つを分かつ!」
これで『Collider』に関する話が一通りが終わりましたので、
具体例をみながら、さらに理解を深めましょう。
『Collider』の理解を深める
具体的な例を見ていき、より「Collider」の理解を深めていきましょう。
Colliderの具体例
以下のようなものを用意してみました。
登場するのは、「Unityちゃん」と「床」と「Trigger」です。
「Trigger」には画像を設定していないので、ゲーム画面には表示されません。
単なる「トリガー」なので、ゲームをプレイする人には見える必要がないですよね。
実際のトリガーはもっと小さなもので良いのですが、
今回は見やすいようにこの大きさにしています。
「Unityちゃん」が「床」を歩いていて、接触する大きさであればよいので、
本当に小さいもので大丈夫です。
この3つのGameObjectすべてに『Collider』をアタッチして、
「Unityちゃん」と「床」には「Is Trigger」のチェックを入れず、
「Trigger」にのみ「Is Trigger」のチェックをいれています。
ここでやりたいことは、「Unityちゃん」が「床」の上を歩いていき、
「Trigger」に接触すると、「床」が開いて「Unityちゃん」が穴に落ちる
といったことです。
では、説明していきます。
まず「Is Trigger」のチェックが外されている「Unityちゃん」と「床」との間には
物理的な接触が起こり「当たり判定」が発生します。
なので「Unityちゃん」が「床」より下に落ちてしまうことはありません。
『両方の「Is Trigger」のチェックが外れている』がポイントですね。
※「Unity」ちゃんには重力がかかっている想定でお願いします。
では、「床」と「Trigger」はどうでしょうか。
「Is Trigger」にチェックが入った「Trigger」と、
「Is Trigger」にチェックが入っていない「床」なので、
物理的接触は起こらず「トリガー」が発生する・・・のかと思いきや、
画像にも書いてある通り、実は何も発生しないのです。
そうなんですね。
「Collider」がついているだけでは、
「当たり判定」や「トリガー」といった『接触』は発生しないのです。
これらの『接触』を発生させるには、「Collider」以外にもう一つ
『Rigidbody(あるいはRigidbody2D)』というものが必要になります。
『Rigidbody』とは、オブジェクトの物理挙動を可能にするためのコンポーネントで、
「当たり判定」「トリガー」を行うための必須コンポーネントとなっています。
『Rigidbody』に関してはこちらの記事をご覧ください。
⇒『オブジェクトが壁をすり抜ける!そんなときの対処法』
「Rigidbody」の「当たり判定」が関わる部分を詳しく解説しております。
そういうわけで、「当たり判定」や「トリガー」を発生させるには、
「Collider」に加え、『Rigidbody』がアタッチされている必要があるのです。
どちらか一方のオブジェクトにアタッチされていれば大丈夫です。
では、改めて「当たり判定」「トリガー」が発生する条件をまとめますと、
・両方のオブジェクトに『Collider』がアタッチされている
・少なくとも一方のオブジェクトに『Rigidbody/Rigidbody2D』がアタッチされている
となります。
『Collider』に加え、『Rigidbody』のアタッチも忘れないようにしてください。
「Unityちゃん」へと話を戻します。
今回の場合は「Unityちゃん」にRigidbody2Dがアタッチされています。
そのため「Unityちゃん」と「床」との間には物理的接触である「当たり判定」が発生し、
「床」と「Trigger」の間には何も発生しなかったのです。
では、
「Unityちゃん」が右方向に進んでいき、「Trigger」と接触したらどうなりますか?
考えてみてくださいね。
Unityちゃん:Rigidbody + Collider(Is Trigger はチェックなし)
Trigger:Collider(Is Triggerにチェックあり)
答えは、
「Unityちゃん」と「Trigger」の間には物理的接触が発生しないため、
「Unityちゃん」は何事もなく右方向へと進んでいくことになります。
「Unityちゃん」が「Trigger」と接触している間は、「トリガー」が発生しています。
大丈夫ですね?
ところで、
「Unityちゃん」と「Trigger」の接触により、
「トリガー」が発生するのは理解できたけど、
落とし穴に落とすという話はどうなったの?
これが次のテーマになります。
『衝突』を検知する関数
ここからはスクリプトを触ることになります。
「当たり」の発生を検知する関数
物理的接触(当たり判定)が発生したときには、下記6つの関数が呼び出されます。
・OnCollisionEnter2D
・OnCollisionStay2D
・OnCollisionExit2D
・OnCollisionEnter
・OnCollisionStay
・OnCollisionExit
言うまでもないですが、2Dがついている関数は2D同士の「当たり判定」に、
2Dがついていない関数は3D同士の「当たり判定」に使用します。
ですので、「BoxCollider2D」をアタッチしているオブジェクトで使用する関数は、
「OnCollisionEnter」ではなく「OnCollisionEnter2D」となりますので、
書き間違えには十分注意してください。
では、「Enter」「Exit」「Stay」の3つの違いは何かというと、
「OnCollisionEnter」は、物体同士が接触した瞬間の1回のみ呼び出され、
「OnCollisionExit」は、物体同士が離れた瞬間の1回のみ呼び出されます。
「OnCollisionStay」に関しては、物体同士が接触している間、常に呼び出されます。
実際のスクリプトの書き方は、このようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CollisionScript: MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } private void OnCollisionEnter(Collision collision) { // 3D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnCollisionStay(Collision collision) { // 3D同士が接触している間、常に呼び出される処理 } private void OnCollisionExit(Collision collision) { // 3D同士が離れた瞬間の1回のみ呼び出される処理 } private void OnCollisionEnter2D(Collision2D collision) { // 2D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnCollisionStay2D(Collision2D collision) { // 2D同士が接触している間、常に呼び出される処理 } private void OnCollisionExit2D(Collision2D collision) { // 2D同士が離れた瞬間の1回のみ呼び出される処理 } } |
C#でのコードですが、新しく「CollisionScript」という名前でスクリプトを作成し、
6つの「当たり判定」用の関数を書き足してみました。
「当たり判定」だけを行いたいなら 最初のStartやUpdateの関数は不要ですし、
「当たり判定」用の関数も自分で必要なものだけを書けば良いです。
2Dの「当たり判定」なら3D用の関数は不要で、3Dなら2D用の関数は不要ですね。
このスクリプトを「当たり判定」を検知したいオブジェクトにアタッチします。
そうすることで、衝突が発生したときに、
スクリプトに記述した該当関数の中に処理が入ってきます。
関数を見ていると『Collision』や『Collision2D』という文字(変数)がありますが、
「Collision」には、衝突したオブジェクトの情報が格納されています。
「Collision」に関しては、こちらの記事で解説しております。
⇒「『Collision』を理解する」
以上で「当たり」の発生を検知する関数の説明を終わります。
続いては、「トリガー」の発生を検知する関数です。
「トリガー」の発生を検知する関数
「当たり判定」とは使用する関数が違っています。
・OnTriggerEnter2D
・OnTriggerStay2D
・OnTriggerExit2D
・OnTriggerEnter
・OnTriggerStay
・OnTriggerExit
「当たり判定」では「Collision」だった箇所が「Trigger」に変わっていますね。
使い方に関しては、「当たり判定」と全く同じです。
では、実際の書き方ですが、新しく「TriggerScript」という名前でクラスを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TriggerScript : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } private void OnTriggerEnter(Collider collider) { // 3D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnTriggerStay(Collider collider) { // 3D同士が接触している間、常に呼び出される処理 } private void OnTriggerExit(Collider collider) { // 3D同士が離れた瞬間の1回のみ呼び出される処理 } private void OnTriggerEnter2D(Collider2D collider) { // 2D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnTriggerStay2D(Collider2D collider) { // 2D同士が接触している間、常に呼び出される処理 } private void OnTriggerExit2D(Collider2D collider) { // 2D同士が離れた瞬間の1回のみ呼び出される処理 } } |
「当たり判定」では、取得できる情報が「Collision」になっていたのに対し、
「トリガー」では「Collider」になっています。
「Collider」はもうわかりますよね。
「トリガー」では、接触した相手の「Collider」情報のみを取得することができます。
ここまで読んでこられた方なら、もうわかりますよね。
「Unityちゃん」を「穴」へ落とす方法のことです。
詳しい処理は省略しますが、
|
private void OnTriggerEnter2D(Collider2D collider) { // 床を消すなどの処理を入れる } |
このように「OnTriggerEnter2D」の関数内に、床を消すなどの処理を書いておけば、
「Unityちゃん」が「Trigger」に接触した瞬間に、床を消すことが実現できそうです。
かなり長くなってしまいましたが、ようやくすべての説明が終わりました。
お疲れさまでした。
「当たり判定」や「トリガー」というのは、ゲームを作るうえで必須の項目なので、
繰り返し読んで、ぜひ使いこなせるようになってください。
使いこなせるようになっても、どうしてもミスはしてしまいます。
そんなときは、もう一度一から設定を見直してみてください。
項目別の設定方法まとめ
それでは最後に、項目別の設定方法をまとめておきます。
「当たり判定」を行う設定_2D編
・少なくとも一方のオブジェクトに『Rigidbody2D』をアッタッチします
・両方のオブジェクトに任意の『Collider2D』をアタッチする
・両方の『Collider2D』の『Is Trigger』のチェックを外す
・利用できるスクリプトはこちらです。
|
private void OnCollisionEnter2D(Collision2D collision) { // 2D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnCollisionStay2D(Collision2D collision) { // 2D同士が接触している間、常に呼び出される処理 } private void OnCollisionExit2D(Collision2D collision) { // 2D同士が離れた瞬間の1回のみ呼び出される処理 } |
「トリガー」を行う設定_2D編
・少なくとも一方のオブジェクトに『Rigidbody2D』をアッタッチします
・両方のオブジェクトに任意の『Collider2D』をアタッチする
・少なくとも一方の『Collider2D』の『Is Trigger』にチェックをつける
・利用できるスクリプトはこちらです。
|
private void OnTriggerEnter2D(Collider2D collider) { /// 2D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnTriggerStay2D(Collider2D collider) { // 2D同士が接触している間、常に呼び出される処理 } private void OnTriggerExit2D(Collider2D collider) { // 2D同士が離れた瞬間の1回のみ呼び出される処理 } |
「当たり判定」を行う設定_3D編
・少なくとも一方のオブジェクトに『Rigidbody』をアッタッチします
・両方のオブジェクトに任意の『Collider』をアタッチする
・両方の『Collider』の『Is Trigger』のチェックを外す
・利用できるスクリプトはこちらです。
|
private void OnCollisionEnter(Collision collision) { // 3D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnCollisionStay(Collision collision) { // 3D同士が接触している間、常に呼び出される処理 } private void OnCollisionExit(Collision collision) { // 3D同士が離れた瞬間の1回のみ呼び出される処理 } |
「トリガー」を行う設定_3D編
・少なくとも一方のオブジェクトに『Rigidbody』をアッタッチします
・両方のオブジェクトに任意の『Collider』をアタッチする
・少なくとも一方の『Collider』の『Is Trigger』にチェックをつける
・利用できるスクリプトはこちらです。
|
private void OnTriggerEnter(Collider collider) { // 3D同士が接触した瞬間の1回のみ呼び出される処理 } private void OnTriggerStay(Collider collider) { // 3D同士が接触している間、常に呼び出される処理 } private void OnTriggerExit(Collider collider) { // 3D同士が離れた瞬間の1回のみ呼び出される処理 } |
最後になりましたが、
「当たり判定」の発生を検知したいのに「OnTriggerEnter」を使ってしまったり、
逆に「トリガー」の発生を検知したいのに「OnCollisionEnter」を使ってしまったり、
また、関数や変数名の2Dの有無にも十分気を付けてください。
これで、『Collider』をマスターする!の解説を終わります。