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 中对应回调是 OnTriggerEnter2D、
OnTriggerStay2D、OnTriggerExit2D——结构相同,但参数是
Collider2D 而不是 Collider。
Trigger 与 Collision 生命周期
Trigger (isTrigger = true)
OnTriggerEnter
接触的第一帧
OnTriggerStay
仍在内部时的每一帧
OnTriggerExit
离开时的最后一帧
✅ 可穿过 — 没有反作用力
Collision (isTrigger = false)
OnCollisionEnter
碰撞的第一帧
OnCollisionStay
仍在接触时的每一帧
OnCollisionExit
分离时
🔒 被挡住 — 有物理反作用力
⚠️ 硬性要求:
两个对象中至少有一个必须带 Rigidbody(或 Rigidbody2D),trigger/collision 才会生效。
动手步骤
创建触发体积
创建空 GameObject,Add Component → BoxCollider,勾选 "Is Trigger"。按需要的区域调整大小。
给移动体挂 Rigidbody
角色或子弹需要 Rigidbody。若不需要重力,设 isKinematic = true。
编写触发处理脚本
在 Trigger 物体或移动体上挂脚本,实现 OnTriggerEnter(Collider other)。
用 Layer 过滤
检查 other.gameObject.layer 或 CompareTag,只响应你关心的对象。
用 Gizmo 颜色调试
Trigger 画成青色(普通碰撞为绿色)。需要更多调试时再加 OnDrawGizmos。
交互模拟器
用 ← → 方向键(或下方按钮)让角色走过 Trigger 区域。
把角色移进触发区域...
代码示例
基础简单拾取:玩家进入 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 里销毁,并先做空检查