Unity Term Book
Physics

Trigger

Trigger là Collider ở chế độ ma — phát hiện enter, stay và exit mà không tạo phản lực vật lý, dùng cho checkpoint, pickup, vùng sát thương và cửa tự động.

Hãy tưởng tượng...

Trigger giống như cảm biến cửa siêu thị. Cánh cửa không đẩy bạn lại khi bước vào — nó chỉ phát hiện bạn bước qua và tự động mở. Không có phản lực vật lý, chỉ có tín hiệu: "có người vào". Trong Unity, `OnTriggerEnter` là tín hiệu đó — được gọi đúng lúc nhân vật chạm vào vùng trigger, cho phép bạn làm bất cứ điều gì: mở cửa, hồi máu, kích hoạt cutscene...

Khái niệm chi tiết

Trigger là một Collider bình thường với checkbox Is Trigger được bật. Khi bật, Collider trở nên xuyên thấu — vật thể đi qua được mà không bị đẩy ngược lại. Thay vào đó, Unity gọi 3 callback đặc biệt: OnTriggerEnter (khi đi vào), OnTriggerStay (mỗi frame khi còn bên trong), và OnTriggerExit (khi đi ra).

Để trigger hoạt động, ít nhất một trong hai đối tượng va chạm phải có Rigidbody. Đây là lỗi phổ biến — hai static object (không Rigidbody) không bao giờ kích hoạt trigger lẫn nhau. Nếu không muốn object bị ảnh hưởng bởi gravity, dùng isKinematic = true.

Trigger có ứng dụng rất rộng: checkpoint (lưu vị trí khi chạy qua), pickup zone (nhặt item), enemy detection (vùng cảnh giác AI), damage zone (vùng nguy hiểm như lửa, acid), cutscene trigger (kích hoạt sự kiện story). Các use case này đều không cần vật lý thực — chỉ cần biết “ai vào vùng này”.

Với Unity 2D, callback tương ứng là OnTriggerEnter2D, OnTriggerStay2D, OnTriggerExit2D — cú pháp giống hệt nhưng nhận Collider2D thay vì Collider.

Vòng đời Trigger vs Collision

Trigger (isTrigger = true)

OnTriggerEnter

Frame đầu tiên tiếp xúc

OnTriggerStay

Mỗi frame khi còn bên trong

OnTriggerExit

Frame cuối cùng khi thoát ra

✅ Đi xuyên qua — không có phản lực

Collision (isTrigger = false)

OnCollisionEnter

Frame đầu tiên va chạm

OnCollisionStay

Mỗi frame khi đang chạm

OnCollisionExit

Khi tách ra

🔒 Bị chặn lại — có phản lực vật lý

⚠️ Yêu cầu bắt buộc:

Ít nhất một trong hai đối tượng phải có Rigidbody (hoặc Rigidbody2D) thì trigger/collision mới hoạt động.

Hướng dẫn thực hành

1

Tạo vùng trigger

Tạo empty GameObject, Add Component → BoxCollider, bật checkbox "Is Trigger". Điều chỉnh kích thước phù hợp.

2

Đảm bảo vật thể di chuyển có Rigidbody

Nhân vật hoặc đạn cần Rigidbody. Nếu không muốn bị ảnh hưởng trọng lực, đặt isKinematic = true.

3

Viết script xử lý trigger

Thêm script với OnTriggerEnter(Collider other) vào object trigger hoặc object di chuyển.

4

Dùng Layer để lọc đối tượng

Kiểm tra other.gameObject.layer hoặc dùng CompareTag để chỉ phản ứng với đối tượng mong muốn.

5

Debug bằng màu Gizmo

Trigger hiển thị màu xanh lam (khác collision màu xanh lá). Thêm OnDrawGizmos để vẽ thêm thông tin debug.

Trình mô phỏng tương tác

Dùng phím mũi tên ← → (hoặc nút bên dưới) để di chuyển nhân vật qua các vùng trigger.

Trigger Zone

Di chuyển nhân vật vào vùng trigger...

Ví dụ Code

Cơ bản

Pickup item đơn giản: nhặt coin khi nhân vật bước vào vùng trigger.

using UnityEngine;

// Gắn script này vào đối tượng Coin có Collider với isTrigger = true
public class CoinPickup : MonoBehaviour
{
  public int value = 10;
  public AudioClip pickupSound;

  void OnTriggerEnter(Collider other)
  {
      // Chỉ phản ứng với nhân vật Player
      if (!other.CompareTag("Player")) return;

      // Cộng điểm cho GameManager
      GameManager.instance.AddScore(value);

      // Phát âm thanh nhặt coin
      AudioSource.PlayClipAtPoint(pickupSound, transform.position);

      // Xoá coin khỏi scene
      Destroy(gameObject);
  }
}

Ví dụ Code

Nâng cao

Vùng nguy hiểm theo thời gian: gây damage liên tục khi ở trong trigger, dừng khi ra ngoài.

using UnityEngine;
using System.Collections;

// Vùng lửa gây sát thương liên tục khi đứng trong 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; // Chờ 1 frame
      }
  }
}

📌 Ghi nhớ nhanh

  • isTrigger=true → đi xuyên qua, nhận sự kiện
  • Ít nhất 1 bên phải có Rigidbody
  • CompareTag() nhanh hơn so sánh string trực tiếp
  • OnTriggerStay gọi mỗi frame — cẩn thận cost cao
  • Dùng LayerMask để lọc object hiệu quả

⚠️ Lỗi thường gặp

  • ❌ Trigger không hoạt động dù đã bật isTrigger

    Không có Rigidbody trên bất kỳ đối tượng nào

    ✅ Thêm Rigidbody (isKinematic=true nếu cần) vào vật thể di chuyển

  • ❌ Gọi Destroy(other.gameObject) trong OnTriggerStay

    Gây lỗi vì object bị xoá giữa vòng lặp physics

    ✅ Dùng OnTriggerEnter và kiểm tra null trước khi Destroy