Xoay vật: góc Euler, Quaternion, và cái nào bạn được đụng vào
Làm sao xoay một vật, và Quaternion là gì?
Dùng Quaternion.Euler(x, y, z) khi bạn biết góc mình muốn, và Quaternion.LookRotation kèm RotateTowards hoặc Slerp để quay dần về phía một vật nào đó. Đừng bao giờ cộng thẳng vào transform.rotation: nó chứa bốn con số không phải là góc, ghi góc vào đó chỉ ra kết quả vô nghĩa.
Vị trí và tỉ lệ là ba con số bạn cộng vào được. Góc xoay trông cũng như ba con số trong Inspector nhưng không phải, và người mới nào cũng phát hiện ra điều đó theo cùng một cách: chép transform.rotation ra một biến, cộng 1 vào y, ghi ngược lại, rồi nhìn vật thể làm một chuyện không tả nổi. (C# thậm chí không cho viết transform.rotation.y += 1 trên một dòng — property đó chỉ trả về một bản sao.)
Thứ Inspector hiện ra không phải thứ được lưu
Unity lưu góc xoay dưới dạng Quaternion: bốn con số x, y, z và w, gộp lại mô tả một trục và một lượng quay quanh trục đó. Không con số nào trong bốn cái là góc tính bằng độ. Inspector đổi chúng thành ba góc Euler dễ nhìn để hiện ra, và đổi ngược lại khi bạn gõ vào.
Đặt một góc xoay bạn đã biết
// Quay 90° sang phải, không ngẩng, không nghiêng.
transform.rotation = Quaternion.Euler(0f, 90f, 0f);
// Xoay cục bộ: tính theo vật cha, không theo thế giới.
transform.localRotation = Quaternion.Euler(0f, 90f, 0f);
// Cộng thêm 90° vào góc hiện tại. Quaternion nhân với nhau, không cộng.
transform.rotation *= Quaternion.Euler(0f, 90f, 0f);Quay về phía thứ gì đó
Đây mới là tình huống thật sự hay gặp: kẻ địch phải nhìn về phía người chơi, tháp súng phải bám mục tiêu, nhân vật phải quay theo hướng đang đi. Nó gồm hai bước — tính ra góc muốn đạt tới, rồi mỗi khung hình tiến về phía đó một chút.
using UnityEngine;
public class FaceTarget : MonoBehaviour
{
public Transform target;
public float turnSpeed = 360f; // độ mỗi giây
void Update()
{
if (target == null) return;
Vector3 to = target.position - transform.position;
// Ép phẳng lại, không thì kẻ địch chúi đầu xuống nhìn nhân vật thấp hơn.
to.y = 0f;
// LookRotation báo lỗi khi gặp vector bằng 0: tức là khi đang đứng đúng ngay mục tiêu.
if (to.sqrMagnitude < 0.0001f) return;
Quaternion wanted = Quaternion.LookRotation(to);
transform.rotation = Quaternion.RotateTowards(
transform.rotation, wanted, turnSpeed * Time.deltaTime);
}
}Dùng RotateTowards hay Slerp?
RotateTowards quay với số độ mỗi giây cố định và có lúc tới nơi. Dùng khi tốc độ quay là một phần của thiết kế — tháp súng không được phép xoay tức thì.
Slerp quay chậm dần, không bao giờ tới hẳn nơi, và tốc độ phụ thuộc quãng còn lại. Dùng cho camera hoặc thứ cần cảm giác mềm chứ không máy móc.
Slerp viết kiểu Slerp(a, b, speed * Time.deltaTime) phụ thuộc khung hình. Cách sửa giống hệt với vị trí: 1f - Mathf.Exp(-speed * Time.deltaTime).
Cho vật quay liên tục
// Quanh trục lên của chính nó: đồng xu xoay tại chỗ.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.Self);
// Quanh trục lên của thế giới: kiểu quay quỹ đạo, không bị ảnh hưởng bởi độ nghiêng.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.World);Gimbal lock, và vì sao bạn nên tự giữ góc
Góc Euler mô tả phép xoay thành ba lần quay nối tiếp nhau. Khi lần quay ở giữa đạt 90°, lần thứ nhất và lần thứ ba rơi vào cùng một trục, và mất đi một bậc tự do. Đó là gimbal lock, và trên thực tế nó chính là thứ làm camera góc nhìn thứ nhất loạn lên khi bạn nhìn thẳng lên trời.
using UnityEngine;
public class MouseLook : MonoBehaviour
{
public float sensitivity = 2f;
// Con số của riêng bạn, tính bằng độ, không bao giờ đọc ngược từ transform.
float yaw, pitch;
void Update()
{
yaw += Input.GetAxis("Mouse X") * sensitivity;
pitch -= Input.GetAxis("Mouse Y") * sensitivity;
// Giới hạn góc chạy đúng vì pitch là một float thường do bạn quản lý.
pitch = Mathf.Clamp(pitch, -80f, 80f);
transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
}
}bài học làm ra thứ này
Camera xoay góc nhìn thứ ba
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 — Camera & Điều khiển, bài 02.