【Unity入門】1からわかる当たり判定!衝突や判定方法を学ぼう

今回はゲーム制作の要となる「当たり判定」について見ていきましょう。

当たり判定があるからこそ、主人公が敵にぶつかったらダメージを受けますし、ボタンを押したら反応するのです。

判定なんて聞くと難しそうな印象を受けますが大丈夫です。

なんとUnityでは数クリックで簡単に設定できるんです!

今回はそんな当たり判定について見ていきましょう。

それでは今回のアジェンダです。

[基本] 当たり判定とは?
[基本] 当たり判定を行おう!
[基本] 当たった時にプログラムを呼ぶには?
[応用] 当たり判定の種類
[応用] その他細かい部分

それでは順に見ていきましょう!

目次

当たり判定とは?

まず当たり判定とは、一言でいうと「物と物がぶつかったことを知る判定」のことを言います。

通常はこれをif文を用いて行わなければなりません。

オブジェクトAの座標とオブジェクトBの座標が、重なっているか判定するようなイメージです。

しかしUnityでは、コンポーネントという形で当たり判定を実行してくれる道具が用意されているんです!

とても便利ですね!

早速詳細を見ていきましょう。

またコンポーネントについて理解が浅い人はこちらの記事を読んでおきましょう。

ゲームオブジェクトコンポーネントの関係性は、Unityを使う上でとても重要なポイントです!

しっかりと把握しておきましょう。

当たり判定を行おう!

では実際に当たり判定を行ってみましょう!

そのためにまずはオブジェクトを作りRigidbodyColliderをつける必要があります。

(とはいえだいたいのオブジェクトにはColliderが最初からついています)

この辺りは実は、別の記事で説明を行っています。

次の記事を参考にRigidbody・Colliderを付けたオブジェクトを作成しましょう。

実行2

当たったらプログラムを呼ぶには?

先ほどのRigidbodyだけで、物理演算的な当たり判定は実装できます。

ちゃんと衝突し跳ねていましたね!

しかし今回はここから一歩踏み込んで、衝突時にスクリプトを呼び出してみましょうか。

プログラムを用意しよう!

今回はボールに「MyScript」と言う名前のスクリプトをもたせて、地面に衝突した時に「Hit!」とログを表示するようにしましょうか。

まずは次の画面のように、Sphereオブジェクトを選択中に、「InspectorウィンドウのAddComponentボタン」→「NewScript」→名前をMyScriptにして「Create and Add」しましょう。

unity-hit-1

MyScriptを開いたら、以下のプログラムを記述しましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyScript : MonoBehaviour {
  // 当たった時に呼ばれる関数
    void OnCollisionEnter(Collision collision)
    {
        Debug.Log("Hit"); // ログを表示する
    }
}

実行してみよう!

さてそれでは実行してみましょう!

unity-hit-m1

地面に衝突した時に「Hit」とログが出ていますね!

ちゃんとスクリプトが呼び出されているようです。

OnCollisionEnter関数を詳しく見てみよう!

実行できたところで先ほど使用した「OnCollisionEnter関数」を改めて見てみましょう。

どんな関数なの?

// 当たり判定
void OnCollisionEnter(Collision collision)
{
      Debug.Log("Hit"); // ログを表示する
}

この関数はRigidbodyとCollider関係(BoxCollider・SphereColliderなど)のコンポーネントを、持っているオブジェクトが衝突した場合、自動的に呼び出されます。

毎フレーム呼び出されるUpdate関数や、生成時に呼び出されるStart関数と同じですね!

衝突した時に、勝手に呼び出してもらえるんです。

引数が便利!

よくよくみるとOnCollisionEnter関数には引数があるではありませんか。

void OnCollisionEnter(Collision collision){}

この引数「Collision collision」ですが、実は非常に便利です。

衝突した相手の情報が、Collision型で送られてきているんです!

Collision型には「gameObject」「Transform」などの値が入っています。

つまり…

void OnCollisionEnter(Collision collision)
{
      Debug.Log(collision.gameObject.name); // ぶつかった相手の名前を取得
}

例えば、こうすればぶつかった相手の名前を取得できるわけですね!

名前で当たった時の「名前」で判定して処理を分岐できますし、タグなどを使用しても便利に分岐できそうですね!

例えば「Enemyという名前のオブジェクトがぶつかった相手だったらダメージを受ける」などしょうか。

非常に有用な関数なのでぜひ覚えておきましょう。

当たり判定の種類

実は当たり判定に使う、Colliderはいろいろな種類があります。

その辺りの詳細は以下のリンクで種類ごとの特徴・使い方の説明しています。

ぜひ読んでみてください。

その他細かい部分

その他、当たり判定に関する細かい点を見てみましょう!

衝突はさせずにプログラムを呼び出したい!

衝突させたくない場合はColliderの「IsTrigger」のチェックボックスにチェックを入れておきましょう。

unity-hit-2

今回でしたらボールである、Sphereオブジェクトの「SphereCollider」の「IsTrigger」チェックボックスですね。

これは物理演算の衝突のようなことはさせずに、スクリプトの呼び出しのみ行ってくれるという仕組みです。

チェックボックスにチェックを入れ実行してみましょう。

no-hit

無事衝突し跳ね返ることがなくなりました!

しかしスクリプトが呼ばれませんね…

それもそのはず、IsTrrigerにチェックを入れている場合は「OnCollisionEnter関数」ではなく「OnTriggerEnter関数」が呼ばれることになるからです。

void OnTriggerEnter(Collider t)
{
  Debug.Log(collision.gameObject.name);
}

OnTriggerEnter関数を使用するように変更すれば…

hit3

問題なくログが表示されるようになりました!

当たった瞬間や離れた瞬間を知りたい!

先ほど使用した「OnCollisionEnter関数」「OnTriggerEnter関数」は、触れた時に呼ばれていましたね。

実は「触れた時」意外にも呼び出してもらえる関数が用意されています!

・通常時に使えるもの

OnCollisionEnter ・・・触れた時、呼ばれる
OnCollisionStay ・・・触れている時、呼ばれる
OnCollisionExit ・・・離れた時、呼ばれる

・isTriggerチェック時に呼ばれるもの

OnTriggerEnter ・・・触れた時、呼ばれる
OnTriggerStay ・・・触れている間、呼ばれる
OnTriggerExit ・・・離れた時、呼ばれる

これらを利用すれば「地面に立っている時」「地面から離れた瞬間」なんて判定も簡単にとれますね!

有効活用してみましょう!

※引数などの詳細は、以下のリファレンスから確認してみてください。

参照元:https://docs.unity3d.com/ja/540/ScriptReference/Collider.html

すり抜けを予防しよう!

ここから先は、当たり判定を貫通してしまう「すり抜け」予防を説明していきます。

※すり抜けがわからない初心者の型はスルーしていただいても問題ありません。

早すぎる移動は避けよう

そもそも、衝突時の速度が早すぎる場合に「すり抜け」が発生するケースが多いです。

あまり高速で衝突させないように気をつけましょう。

Collision Detectionパラメータ

あとは、もう一つ行える対策として、当たり判定の設定変更が挙げられます。

unity-hit-3

「Collision Detection」パラメーターは、非常に簡単に一言で言うと「当たり判定の精度」の設定です。

この設定を変えることで、高速で動くオブジェクトの動きを予測させて、すり抜けを防止することができます。

高速で動くオブジェクトについては「Continues Dynamic」の設定に変更をしてみてください。

FixedUpdateの回数を上げる

あとは負荷が上がってしまうのがネックですがFixedUpdateの頻度を上げることで対処も可能です。

unity-hit-4
「Edit→ProjectSettings→Time」でInspectorウィンドウ上に変更画面を開けます。

unity-hit-5
ここの「Fixed Timestep」です。

ここの数字を下げることで、衝突判定のチェック頻度を向上させ、より高精度の判定が行えるわけです。

ただし先ほども説明した通り、チェック頻度が増えればその分負荷も上がるわけなので…

頻度を上げすぎるのも考えものです。

またFixedUpdate関数の詳細は以下の記事で説明していますので、目を通してみてください。

まとめ

今回は、当たり判定について見てきました。

isTriggerのチェックの入れ間違いや、OnCollisionEnter関数とOnTriggerEnter関数の使い間違えによって「当たり判定が正しく取れない!」と困っている人もよくいます。

この辺りはちゃんと覚えておきましょう!

また当たり判定は上手に行えれば、負荷を下げられますが、下手に判定すると一気に負荷が向上してしまいます。

ぜひ深く学び、理解して失敗を防ぎましょう!

この記事を書いた人

学生時代を含めると、かれこれ10年以上プログラマーとして過ごしています。
様々な言語や環境、プロジェクトに関わってきましたので、より実践的な記事をみなさんにお届きるよう情報発信していきます!

目次