Raycast: hỏi thế giới xem trước mặt có gì
Làm sao biết người chơi đang nhắm vào đâu, hoặc đứng trên cái gì?
Physics.Raycast bắn một đường thẳng vô hình rồi báo lại collider đầu tiên nó gặp, kèm điểm trúng, khoảng cách và pháp tuyến bề mặt. Luôn truyền LayerMask và khoảng cách tối đa — thiếu hai thứ đó, tia sẽ kiểm mọi layer tới vô cực, và tia bắn từ camera góc nhìn thứ ba sẽ trúng nhân vật đứng trước nó đầu tiên.
Raycast là một câu hỏi: nếu bắn một đường thẳng vô hình từ đây, theo hướng này, thì nó trúng cái gì đầu tiên? Bắn súng, kiểm tra chạm đất, xem dưới ngón tay người chơi có gì, camera đang nhìn vào đâu, kẻ địch có thấy bạn không — tất cả đều là một hàm với bốn tham số.
Một đường thẳng vô hình, và collider đầu tiên nó gặp trả lại điểm trúng, pháp tuyến bề mặt và khoảng cách.
Hình dạng của nó
using UnityEngine;
public class Shooter : MonoBehaviour
{
public float range = 50f;
public LayerMask hittable; // đặt trong Inspector
void Fire()
{
// điểm bắt đầu, hướng, kết quả trả ra, xa bao nhiêu, tính những layer nào
if (Physics.Raycast(transform.position, transform.forward,
out RaycastHit hit, range, hittable))
{
Debug.Log("hit " + hit.collider.name + " at " + hit.distance + "m");
}
}
}Cú trúng cho bạn biết gì
hit.point — điểm chính xác trong không gian thế giới. Đây là chỗ đặt vết đạn, tia lửa hay hình dán.
hit.normal — hướng mà bề mặt quay về. Xoay hiệu ứng theo nó thì tia lửa nằm phẳng trên tường thay vì chọc ra ngoài.
hit.distance — tia đã đi được bao xa. Hữu ích cho giảm sát thương theo khoảng cách, và để vẽ vệt đạn đúng độ dài.
hit.collider — thứ bị trúng. Gọi GetComponent trên nó để tìm script máu, hoặc CompareTag để phân biệt đồng đội với bức tường.
// Quaternion.LookRotation(hit.normal) làm trục forward của hiệu ứng chĩa thẳng
// ra khỏi bức tường.
Instantiate(impactPrefab, hit.point, Quaternion.LookRotation(hit.normal));LayerMask, làm cho đúng
LayerMask không phải số thứ tự của layer. Nó là 32 bit, mỗi layer một bit, và bit được bật khi layer đó được tính. Khai báo trường kiểu LayerMask cho bạn cái danh sách tick trong Inspector và khỏi phải tự tính toán bao giờ.
// SAI: layer 8 viết dạng số nghĩa là bit thứ 3, tức là layer 3.
Physics.Raycast(origin, dir, out hit, range, 8);
// Đúng, khi viết trong code:
int mask = 1 << LayerMask.NameToLayer("Enemy");
// Đúng, và tốt hơn: để Inspector lo.
public LayerMask hittable;
// Mọi thứ TRỪ layer của chính người chơi:
int allButPlayer = ~(1 << LayerMask.NameToLayer("Player"));Từ camera, hoặc từ ngón tay
void Update()
{
// Chuột. Trên điện thoại, Input.mousePosition cũng đi theo lần chạm đầu
// tiên, nên cùng đoạn này chạy được cả hai mà không cần sửa gì.
if (!Input.GetMouseButtonDown(0)) return;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f, selectable))
{
hit.collider.GetComponent<Selectable>()?.Select();
}
}Nhìn thấy cái tia
Raycast vốn vô hình, nên gỡ lỗi nó là đoán mò, trừ khi bạn vẽ nó ra. Hai dòng biến một điều bí ẩn thành thứ bạn nhìn được trong Scene view ngay lúc game đang chạy.
// Xanh lá tới chỗ trúng, đỏ hết chiều dài khi trượt.
if (Physics.Raycast(origin, dir, out RaycastHit hit, range, mask))
Debug.DrawLine(origin, hit.point, Color.green, 1f);
else
Debug.DrawRay(origin, dir * range, Color.red, 1f);Khi một đường thẳng quá mảnh
SphereCast quét một quả cầu dọc theo tia. Đây là thứ mà phép kiểm tra chạm đất cần, và viên đạn to cũng vậy, vì một đường thẳng lọt qua những khe hở mà một vật thể thì không.
RaycastAll trả về mọi thứ dọc đường, không sắp xếp. Dùng nó để bắn xuyên qua nhiều kẻ địch — nhưng phải tự sắp theo khoảng cách, vì thứ tự không được đảm bảo.
RaycastNonAlloc đổ kết quả vào mảng của bạn thay vì cấp phát mảng mới. Trên điện thoại, một Update gọi RaycastAll mỗi khung hình sinh ra rác mà bộ dọn rác cuối cùng phải dừng game lại để dọn.
Trigger bị bỏ qua hay được tính là tuỳ thiết lập Physics. Hãy truyền QueryTriggerInteraction một cách tường minh thay vì trông vào một giá trị mặc định toàn dự án mà ai đó có thể đổ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.