Unity••10 min•7 views••
Physics Tunneling
Minh Khoa
Author
1️⃣ Khái niệm Tunneling là gì?
Tunneling (xuyên vật thể) xảy ra khi một object di chuyển quá nhanh giữa hai khung hình (frame), khiến hệ thống Physics không kịp phát hiện va chạm.
Nói đơn giản: ở frame 1 vật A nằm trước bức tường,
ở frame 2 A đã nằm sau bức tường → Unity không bao giờ “thấy” chúng va nhau.
🧩 Hậu quả:
-
OnCollisionEnter,OnTriggerEnterkhông được gọi. -
Vật thể “chui xuyên” qua collider khác mà không có phản ứng vật lý.
-
Gây lỗi nghiêm trọng trong các game tốc độ cao (đạn, xe, slash attack…)

2️⃣ Nguyên nhân kỹ thuật
🔹 2.1. Unity Physics chạy rời với Rendering
- Mỗi frame Unity update physics 1 lần theo fixed timestep (
Time.fixedDeltaTime– mặc định 0.02s = 50 FPS vật lý). - Nếu vật di chuyển nhanh, giữa 2 lần update physics, nó đã nhảy quá xa collider → va chạm không được tính.
🔹 2.2. Cơ chế Collision Detection mặc định là “Discrete”
- Unity chỉ kiểm tra vị trí tại mỗi step vật lý, không nội suy đường đi.
- Tốc độ cao = bước nhảy lớn → có thể “bỏ lỡ” collider.
🔹 2.3. Timestep hoặc Rigidbody kém chính xác
Fixed Timestepquá lớn → khoảng cách giữa các frame vật lý xa.- Rigidbody interpolation không đủ → khung hình hiển thị “đúng” nhưng vật lý thì “bỏ qua”.
3️⃣ Minh họa cơ chế “miss collision”
Frame 1: O---| (O trước tường)
Frame 2: |---O (O sau tường)
Kết quả: Không có frame nào thấy O chạm | → Không có collision!
Nếu tốc độ đủ cao, object có thể “dịch chuyển vượt qua” chiều dày của collider chỉ trong 1 tick vật lý.
4️⃣ Giải pháp khắc phục
✅ 4.1. Dùng Continuous Collision Detection
- Trong
Rigidbody→Collision Detection:Discrete: mặc định (nhanh, rẻ, dễ miss).Continuous: tính toán đường chuyển động → phát hiện va chạm chính xác hơn.Continuous Dynamic: cho vật di chuyển nhanh.Continuous Speculative: Unity mới (mạnh nhất, nhưng tốn CPU).
🧠 Khuyến nghị:
- Dùng
Continuous Dynamiccho vật thể nhanh có Rigidbody (đạn, projectile, xe). - Đặt collider tĩnh (tường, sàn) là Continuous Static hoặc để mặc định.
✅ 4.2. Giảm Fixed Timestep
- Trong
Edit → Project Settings → Time → Fixed Timestep. - Mặc định 0.02s → có thể giảm xuống
0.01hoặc0.005. - Physics update nhiều hơn → ít bỏ lỡ va chạm.
⚠️ Đổi lại: CPU tốn hơn (vì tăng số lần update vật lý mỗi frame).
✅ 4.3. Giới hạn tốc độ vật thể
- Đặt
Rigidbody.maxLinearVelocityhoặc tự clamp tốc độ. - Không cho phép di chuyển “teleport” giữa frame.
- Với đạn → nên raycast thay vì dùng rigidbody velocity.
✅ 4.4. Sử dụng Raycast kiểm tra thủ công
- Thay vì phụ thuộc hoàn toàn vào physics engine, bạn tự raycast theo hướng di chuyển.
Vector3 dir = rb.velocity.normalized;
float dist = rb.velocity.magnitude * Time.fixedDeltaTime;
if (Physics.Raycast(transform.position, dir, out RaycastHit hit, dist))
{
// Xử lý va chạm thủ công
}
- Đặc biệt hữu ích cho đạn hoặc slash attack – nơi chỉ cần biết va chạm tức thời.
✅ 4.5. Dùng Rigidbody Interpolation
- Giúp hiển thị mượt mà khi FixedUpdate thấp hơn framerate.
- Không trực tiếp giải quyết tunneling, nhưng cải thiện độ chính xác hiển thị.
✅ 4.6. Collider dày hơn / Bounding box rộng hơn
- Nếu collider quá mỏng (vd: plane 0.001), va chạm dễ miss.
- Dày hơn = vùng check lớn hơn → ít bỏ sót hơn.
✅ 4.7. Không mix Transform.Translate / MovePosition không chuẩn
- Đừng “teleport” object bằng
transform.positionkhi nó có Rigidbody. - Hãy dùng
Rigidbody.MovePosition()hoặc thêm lực (AddForce,velocity), để physics kiểm soát chuyển động.