旋转:欧拉角、四元数,以及哪个你能碰
怎么旋转一个物体,Quaternion 是什么?
当你已经知道想要的角度时,用 Quaternion.Euler(x, y, z);要转向某个目标,就用 Quaternion.LookRotation 配合 RotateTowards 或 Slerp。绝不要直接往 transform.rotation 上做加法:它存的是四个并非角度的数。
位置和缩放都是可以往上加的三串数。旋转在 Inspector 里看着也是三个数,但它不是——每个新手都是这样发现这件事的:把 transform.rotation 抄进变量,给它的 y 加 1,再写回去,然后看着物体做出没法形容的动作。(C# 甚至不允许在一行里写 transform.rotation.y += 1——那个 property 交给你的只是一份拷贝。)
Inspector 显示给你的,不是实际存着的东西
Unity 把旋转存成 Quaternion:四个数——x、y、z 和 w——合起来描述一根轴和绕这根轴转了多少。这四个数里没有一个是按度算的角度。Inspector 为了显示把它们换算成三个好读的欧拉角,你敲进去的数再反向换算回去。
设置一个你已经知道的旋转
// Face 90° to the right, level, no roll.
transform.rotation = Quaternion.Euler(0f, 90f, 0f);
// Local rotation instead: relative to the parent, not to the world.
transform.localRotation = Quaternion.Euler(0f, 90f, 0f);
// Add 90° to whatever it is now. Quaternions multiply, they do not add.
transform.rotation *= Quaternion.Euler(0f, 90f, 0f);转向某个目标
实战中真正常见的是这种情况:敌人要面向玩家,炮塔要咬住目标,角色要转向自己正在走的方向。它只有两步——算出你想要的那个旋转,然后每帧朝它挪一点。
using UnityEngine;
public class FaceTarget : MonoBehaviour
{
public Transform target;
public float turnSpeed = 360f; // degrees per second
void Update()
{
if (target == null) return;
Vector3 to = target.position - transform.position;
// Flatten it, or the enemy tips forward to look down at a short player.
to.y = 0f;
// LookRotation complains about a zero vector: standing exactly on the target.
if (to.sqrMagnitude < 0.0001f) return;
Quaternion wanted = Quaternion.LookRotation(to);
transform.rotation = Quaternion.RotateTowards(
transform.rotation, wanted, turnSpeed * Time.deltaTime);
}
}用 RotateTowards 还是 Slerp?
RotateTowards 按每秒固定的度数转动,而且会真的转到位。当转速本身就是设计的一部分时用它——比如一座不许瞬间甩过去的炮塔。
Slerp 越接近越慢、永远到不了终点,速度还取决于还剩多少角度。适合相机,或任何要柔和、不想像机械的东西。
把 Slerp 写成 Slerp(a, b, speed * Time.deltaTime) 会随帧率变化。修法和位置那套完全一样:1f - Mathf.Exp(-speed * Time.deltaTime)。
让一个东西一直转
// Around its own up axis: a coin spinning on the spot.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.Self);
// Around the world's up axis: orbiting behaviour, unaffected by tilt.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.World);Gimbal lock,以及为什么要自己存一份角度
欧拉角把旋转描述成依次施加的三个转动。当中间那一转到达 90° 时,第一转和第三转就变成了绕同一根轴转,自由度少掉一个。这就是 gimbal lock——第一人称相机在你抬头看正上方时发疯,多半就是它干的。
using UnityEngine;
public class MouseLook : MonoBehaviour
{
public float sensitivity = 2f;
// Your own numbers, in degrees, never read back from the transform.
float yaw, pitch;
void Update()
{
yaw += Input.GetAxis("Mouse X") * sensitivity;
pitch -= Input.GetAxis("Mouse Y") * sensitivity;
// Clamping works because pitch is a plain float you control.
pitch = Mathf.Clamp(pitch, -80f, 80f);
transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
}
}做出这个的那一课
第三人称环绕镜头
这篇指南单独成篇,是一份可以直接照着做的配方。在课程里,同样的东西会作为贯穿全部五个章的那个项目的一部分来搭建 —— 镜头与操作,第 02 课。