Unity Term Book
物理

Trigger

Trigger 是幽灵模式的 Collider:检测进入、停留与离开,却不产生物理推回力,常用于 Unity 检查点、拾取物、伤害区域与自动门。需勾选 Is Trigger 并配合 Rigidbody 才能收到 OnTrigger 回调。它让区域交互与实体碰撞响应分离,是关卡设计与玩法脚本的常用工具。

想象一下...

Trigger 就像超市感应门。你走进去时门不会把你推回去——它只是察觉到你并打开。没有物理力,只有信号:“有人进来了。”在 Unity 里,`OnTriggerEnter` 就是那个信号——角色碰到区域的瞬间触发,用来开门、回血、播过场……

概念详解

Trigger 就是勾选了 Is Trigger 的普通 Collider。启用后,Collider 变为可穿透—— 物体穿过去不会被推回。Unity 改为触发三个回调:OnTriggerEnter(进入时)、 OnTriggerStay (在内每一帧)、以及 OnTriggerExit(离开时)。

要让 Trigger 生效,双方至少一方必须有 Rigidbody。这是最常见的疏漏——两个静态物体(都没有 Rigidbody)永远不会互相触发。 若不需要重力,设 isKinematic = true

Trigger 用途很广:检查点(走过时存位置)、 拾取区(收集道具)、 敌人感知(AI 察觉半径)、 伤害区(火焰、酸液)、 过场触发(剧情节点)。这些都不需要真实物理—— 只要回答“谁进入了这个体积?”

在 Unity 2D 中对应回调是 OnTriggerEnter2DOnTriggerStay2DOnTriggerExit2D——结构相同,但参数是 Collider2D 而不是 Collider

Trigger 与 Collision 生命周期

Trigger (isTrigger = true)

OnTriggerEnter

接触的第一帧

OnTriggerStay

仍在内部时的每一帧

OnTriggerExit

离开时的最后一帧

✅ 可穿过 — 没有反作用力

Collision (isTrigger = false)

OnCollisionEnter

碰撞的第一帧

OnCollisionStay

仍在接触时的每一帧

OnCollisionExit

分离时

🔒 被挡住 — 有物理反作用力

⚠️ 硬性要求:

两个对象中至少有一个必须带 Rigidbody(或 Rigidbody2D),trigger/collision 才会生效。

动手步骤

1

创建触发体积

创建空 GameObject,Add Component → BoxCollider,勾选 "Is Trigger"。按需要的区域调整大小。

2

给移动体挂 Rigidbody

角色或子弹需要 Rigidbody。若不需要重力,设 isKinematic = true。

3

编写触发处理脚本

在 Trigger 物体或移动体上挂脚本,实现 OnTriggerEnter(Collider other)。

4

用 Layer 过滤

检查 other.gameObject.layer 或 CompareTag,只响应你关心的对象。

5

用 Gizmo 颜色调试

Trigger 画成青色(普通碰撞为绿色)。需要更多调试时再加 OnDrawGizmos。

交互模拟器

用 ← → 方向键(或下方按钮)让角色走过 Trigger 区域。

Trigger Zone

把角色移进触发区域...

代码示例

基础

简单拾取:玩家进入 Trigger 时收集金币。

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 却从不触发

    双方都没有 Rigidbody

    ✅ 给移动体加 Rigidbody(需要时设 isKinematic=true)

  • ❌ 在 OnTriggerStay 里 Destroy(other.gameObject)

    对象在物理循环中途被销毁 → 报错

    ✅ 在 OnTriggerEnter 里销毁,并先做空检查