Va chạm và trigger: vì sao sự kiện không chạy
Vì sao OnCollisionEnter và OnTriggerEnter không chạy?
Cả hai vật đều cần collider, và một trong hai cần Rigidbody: loại không kinematic cho OnCollisionEnter, loại nào cũng được — kể cả kinematic — cho OnTriggerEnter. Rồi kiểm tên hàm và tham số của nó, script có nằm đúng object chứa collider không, và hai layer còn được tick trong Layer Collision Matrix không.
Hai vật chạm nhau ngay trên màn hình mà hàm của bạn không chạy. Console không báo gì, không lỗi, không cảnh báo — đơn giản là Unity chưa từng gọi nó. Chỉ có sáu lý do, và bạn dò hết chúng trong khoảng một phút.
Trước hết: bạn cần cái nào trong hai?
✓ OnCollisionEnter
solid hits solid
Collision, trong đó có các điểm chạm và vận tốc lúc đâm vào.✓ OnTriggerEnter
something enters an area
Collider: thứ vừa đi vào, không kèm thông tin va đập.Sáu thứ cần kiểm, theo thứ tự
- 1
Phải có Rigidbody ở đâu đó. Unity chỉ báo có chạm khi vật lý đang theo dõi một trong hai vật. Sự kiện va chạm cần một Rigidbody không kinematic ở ít nhất một bên; sự kiện trigger cần một Rigidbody ở ít nhất một bên, và kinematic cũng được. Hai vật cùng nằm im thì chẳng báo gì cả.
- 2
Tên hàm và tham số.
OnTriggerEnter(Collider other)vàOnCollisionEnter(Collision collision)— viết đúng y như vậy. Unity tìm hàm theo tên, nênonTriggerEnter, hay mộtCollider2Dtrong cảnh 3D, vẫn biên dịch ngon lành và không bao giờ được gọi. - 3
Script nằm đúng object. Thông điệp được gửi tới GameObject đang giữ collider, và tới GameObject đang giữ Rigidbody mà collider đó thuộc về. Script nằm cao hơn cả hai chỗ đó thì không nghe thấy gì.
- 4
Cả hai collider đều tồn tại và đang bật. Nhìn Inspector là nhanh nhất: bấm Play, đi vào vật đó, rồi xem hai khung collider có thật sự chạm nhau trong cửa sổ Scene không. Collider để nguyên kích thước mặc định thường nằm lọt thỏm trong model.
- 5
Hai layer được phép gặp nhau. có bảng Layer Collision Matrix. Chỉ cần một ô bị bỏ tick là hai vật phớt lờ nhau hoàn toàn — không va chạm, không trigger, không thông điệp nào.
- 6
2D và 3D không bao giờ gặp nhau.
Collider2DvàColliderlà hai bộ máy vật lý riêng biệt sống chung một cảnh. Collider 2D không bao giờ chạm được collider 3D, và sự kiện của 2D là những hàm có đuôi2D.
Một trigger chạy được, và một va chạm chạy được
using UnityEngine;
// Đồng xu nằm im, nên Rigidbody nằm ở nhân vật chứ không ở đây.
[RequireComponent(typeof(Collider))]
public class Coin : MonoBehaviour
{
public int value = 1;
void Reset()
{
// Chạy lúc vừa gắn component: tự tick Is Trigger hộ người hay quên.
GetComponent<Collider>().isTrigger = true;
}
void OnTriggerEnter(Collider other)
{
// Ai cũng có thể đi vào đây — xem là ai rồi hẵng cộng điểm.
if (!other.CompareTag("Player")) return;
// Nối chỗ này vào thứ đang giữ điểm của bạn.
Debug.Log($"+{value}");
Destroy(gameObject);
}
}using UnityEngine;
[RequireComponent(typeof(Rigidbody), typeof(Collider))]
public class Crate : MonoBehaviour
{
public AudioSource thud;
void OnCollisionEnter(Collision collision)
{
// Collision mang theo lực va: chạm nhẹ thì đừng kêu như tông xe.
if (collision.relativeVelocity.magnitude < 2f) return;
thud.Play();
}
}Hai thứ nữa hay làm người ta mắc
CharacterController không phải Rigidbody. Nó không bao giờ gọi OnCollisionEnter — nó gọi OnControllerColliderHit — nhưng nó vẫn kích hoạt trigger khi di chuyển, nên mới có chuyện nhân vật không đẩy nổi cái thùng mà vẫn nhặt được đồng xu.
Vật đủ nhanh sẽ nhảy thẳng qua một bức tường mỏng giữa hai khung hình. Trên Rigidbody đó, đặt Collision Detection thành Continuous, và tiện tay cho bức tường dày lên một chút.
Di chuyển Rigidbody bằng cách ghi thẳng transform.position là dịch chuyển tức thời, mà dịch chuyển tức thời thì không có đường đi nào cho vật lý kiểm tra. Hãy dùng Rigidbody.MovePosition hoặc dùng vận tốc, các cú chạm sẽ trở lại.
bài học làm ra thứ này
Đạn, sát thương và hiệu ứng
Bài này là một công thức đứng riêng. Trong khoá học, cùng thứ đó được dựng như một phần của dự án xuyên suốt năm tab — Nhân vật & Chiến đấu, bài 05.