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
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.
Đả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.
Viết script xử lý trigger
Thêm script với OnTriggerEnter(Collider other) vào object trigger hoặc object di chuyển.
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.
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.
Di chuyển nhân vật vào vùng trigger...
Ví dụ Code
Cơ bảnPickup 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 caoVù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