0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】衝突"していない"ことを検知する

Last updated at Posted at 2025-04-19

衝突"していない"ことを検知するメソッドはない

Unityにはコライダーの衝突を検知するものとして OnCollision と OnTrigger というメソッドがあり、それぞれ以下の3つの種類があります。

  • OnCollision系
関数 内容
OnCollisionEnter 他のコライダーに触れ始めたとき
OnCollisionStay 他のコライダーに触れている間
OnCollisionExit 他のコライダーに触れるのをやめたとき
  • OnTrigger系
関数 内容
OnTriggerEnter 他のコライダーに触れ始めたとき
OnTriggerStay 他のコライダーに触れている間
OnTriggerExit 他のコライダーに触れるのをやめたとき

しかしながら、「衝突した」「衝突している」ということは検知できても「衝突していない」ことを直接検知することはできません。
そこで本記事では「衝突していない」ことを検知する方法について紹介します。

方法① On〇〇Enter と On〇〇Exit を組み合わせる

単純でわかりやすいし、まずこれで困らないと思います。
Enterメソッドで衝突しているかどうかのフラグを立て、Exitメソッドでそのフラグを下ろすやり方です。

using UnityEngine;

public class DetectNoCollision_A() : MonoBehaviour
{

    private bool isCollisionDetected = false;  // 衝突判定用のフラグ

    private void OnTriggerEnter(Collider other)
    {
        isCollisionDetected = true;
    }

    private void OnTriggerExit(Collider other)
    {
        isCollisionDetected = false;
    }

    private void Update()
    {
        if (isCollisionDetected)
        {
            Debug.Log("衝突してるよ");
        }
        else
        {
            Debug.Log("衝突してないよ");
        }
    }
}

この方法で困る場合

先ほど「まずこれで困らない」と述べましたが、じゃあどんな場面で困るのかというと

  • 衝突を検知する物体が生成されたときにすでに衝突していて
  • かつそれを FixedUpdate で検知する場合

です。そんな場面あるのかよというようなレアケースではありますが、実際にあったためその対策としてこの記事を書いておきます。

ここでちょっとした実験をしてみます。
半透明なキューブがあり、その中に別の緑のキューブが入っています。半透明なキューブは isTrigger を有効にしてあり、緑のキューブには Rigidbody をつけています。(落ちないように isKinematic を有効化)

image.png

この状態で緑のキューブに先ほどの DetectNoCollision_A をアタッチし、シーンを再生します。
ただし Update は FixedUpdate に変えておきます。
すると...

image.png

シーンを再生したあとの最初の1回だけ衝突していない判定になりました。

なんでこんなことになる?

Unity公式のイベント関数の実行順序のページを見るとわかります。
https://docs.unity3d.com/ja/2022.3/Manual/ExecutionOrder.html

一部抜粋した物理関連の処理はこのようになっています。
つまり FixedUpdate は 衝突検知系のメソッドよりも先に実行されるため、FixedUpdate の最初の1回だけはフラグを立てる前に衝突が判定され、衝突していない扱いになってしまうのです。

image.png

方法② yield WaitForFixedUpdate を使う

先ほどの図をもう一度見てもらうと、 Phisics の処理の最後に yield WaitForFixedUpdate というものがあります。
これをコルーチン内で使うと衝突判定の後まで待ってもらえます。
衝突判定が終わるまで待って、その時点で衝突したフラグが立っていなければ衝突したことにする、という方式です。

using System.Collections;
using UnityEngine;

public class DetectNoCollision_B : MonoBehaviour
{
    private bool isCollisionDetected = false;  // 衝突判定用のフラグ

    private void FixedUpdate()
    {
        StartCoroutine(CollisionDetect());
    }

    IEnumerator CollisionDetect()
    {
        isCollisionDetected = false;
        yield return new WaitForFixedUpdate();
        if (!isCollisionDetected)
        {
            Debug.Log("衝突してないよ");
        }
    }

    private void OnTriggerStay(Collider other)
    {
        isCollisionDetected = true;
        Debug.Log("衝突してるよ");
    }
}

これを同じ状況で実験してみると...

image.png

無事最初の1回から衝突している判定になりました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?