Unity Term Book
物理

Trigger

Trigger はゴースト化した Collider です——進入・滞在・退出を検知しても押し返しません。チェックポイント、ピックアップ、自動ドア、ダメージゾーンに使い、Rigidbody 条件と OnTriggerEnter の基礎を学べます。図解とシミュレーターでゾーン反応を体感し、自学にも使えます。

想像してみてください...

Trigger はスーパーの自動ドアのセンサーのようなものです。入っても押し返さず、 気づいてドアを開けるだけ。物理的な力はなく、「誰かが入った」という信号だけ。 Unity では `OnTriggerEnter` がその信号——ゾーンに触れた瞬間に発火し、ドアを開ける、回復する、カットシーンを始める…などに使えます。

概念の詳細

Trigger は通常の Collider で Is Trigger にチェックを入れたものです。有効にすると すり抜け可能になり——押し返しはありません。代わりに Unity は三つのコールバックを発火します: OnTriggerEnter(進入時)、OnTriggerStay (内側にいる毎フレーム)、OnTriggerExit(退出時)。

Trigger が発火するには、二者のうち少なくとも一方Rigidbody が必要です。これが典型的な取りこぼし——両方静的(Rigidbody なし)だと 互いにトリガーしません。重力が不要なら isKinematic = true にします。

Trigger の用途は広い:checkpoint(通過で位置保存)、 pickup zone(アイテム取得)、 enemy detection(AI の感知半径)、 damage zone(火・酸)、 cutscene trigger(ストーリー開始)。本物の物理は不要—— 「誰がこの体積に入ったか」だけです。

Unity 2D では対応コールバックが OnTriggerEnter2DOnTriggerStay2DOnTriggerExit2D — 形は同じですが引数は Collider ではなく Collider2D です。

Trigger と Collision のライフサイクル

Trigger (isTrigger = true)

OnTriggerEnter

接触した最初のフレーム

OnTriggerStay

内部にいる間の毎フレーム

OnTriggerExit

離脱する最後のフレーム

✅ 通り抜け可能 — 反力なし

Collision (isTrigger = false)

OnCollisionEnter

衝突した最初のフレーム

OnCollisionStay

接触中の毎フレーム

OnCollisionExit

離れたとき

🔒 ブロックされる — 物理的な反力あり

⚠️ 必須条件:

2 つのオブジェクトのうち少なくとも一方に Rigidbody(または Rigidbody2D)がないと、trigger/collision は発火しません。

ハンズオン手順

1

トリガー体積を作成

空の GameObject を作り、Add Component → BoxCollider、"Is Trigger" にチェック。ゾーンの大きさに合わせます。

2

動く側に Rigidbody を付ける

キャラや弾には Rigidbody が必要。重力をかけたくなければ isKinematic = true。

3

トリガーハンドラを書く

トリガー側または動く側に OnTriggerEnter(Collider other) を持つスクリプトを追加します。

4

Layer でフィルタ

other.gameObject.layer や CompareTag で、関心のある物体だけに反応します。

5

Gizmo の色でデバッグ

Trigger はシアン(通常の衝突は緑)。追加のデバッグ描画には OnDrawGizmos を使います。

インタラクティブシミュレーター

← → キー(または下のボタン)でキャラを動かし、トリガーゾーンを通過してみましょう。

Trigger Zone

キャラクターをトリガー領域へ移動...

コード例

基本

シンプルなピックアップ:プレイヤーがトリガーに入るとコインを取得。

using UnityEngine;

// Attach this to a Coin with a Collider that has isTrigger = true
public class CoinPickup : MonoBehaviour
{
  public int value = 10;
  public AudioClip pickupSound;

  void OnTriggerEnter(Collider other)
  {
      // Only react to the Player
      if (!other.CompareTag("Player")) return;

      // Award points via GameManager
      GameManager.instance.AddScore(value);

      // Play a pickup sound
      AudioSource.PlayClipAtPoint(pickupSound, transform.position);

      // Remove the coin from the scene
      Destroy(gameObject);
  }
}

コード例

上級

時限ハザード:内側にいる間は毎フレームダメージ、退出で停止。

using UnityEngine;
using System.Collections;

// A fire zone that damages while you stand in the trigger
public class DamageZone : MonoBehaviour
{
  public float damagePerSecond = 10f;
  public LayerMask damageable;

  Coroutine damageRoutine;
  PlayerHealth currentTarget;

  void OnTriggerEnter(Collider other)
  {
      if ((damageable.value & (1 << other.gameObject.layer)) == 0) return;

      currentTarget = other.GetComponent<PlayerHealth>();
      if (currentTarget != null)
          damageRoutine = StartCoroutine(DamageLoop());
  }

  void OnTriggerExit(Collider other)
  {
      if (damageRoutine != null)
      {
          StopCoroutine(damageRoutine);
          damageRoutine = null;
          currentTarget = null;
      }
  }

  IEnumerator DamageLoop()
  {
      while (true)
      {
          currentTarget.TakeDamage(damagePerSecond * Time.deltaTime);
          yield return null; // Wait one frame
      }
  }
}

📌 要点

  • isTrigger=true → すり抜け、イベント受信
  • 少なくとも一方に Rigidbody が必要
  • CompareTag() は文字列直接比較より速い
  • OnTriggerStay は毎フレーム——コストに注意
  • LayerMask で安くフィルタ

⚠️ よくあるミス

  • ❌ isTrigger がオンなのに Trigger が発火しない

    どちらにも Rigidbody がない

    ✅ 動く側に Rigidbody を追加(必要なら isKinematic=true)

  • ❌ OnTriggerStay 内で Destroy(other.gameObject)

    物理ループの途中で破棄されエラー

    ✅ OnTriggerEnter で Destroyし、先に null チェック