Transform 变换
Transform 是 Unity 中最重要的组件之一,它定义了 GameObject 在三维空间中的位置、旋转和缩放。本章将深入讲解 Transform 的各种操作和应用。
Transform 基础
每个 GameObject 都有一个 Transform 组件,它是唯一不能移除的组件。
核心属性
public class TransformExample : MonoBehaviour
{
void Start()
{
Transform trans = transform; // 简写方式
// ========== 位置 ==========
Vector3 worldPos = trans.position; // 世界坐标位置
Vector3 localPos = trans.localPosition; // 相对于父对象的本地位置
// ========== 旋转 ==========
Quaternion worldRot = trans.rotation; // 世界坐标旋转(四元数)
Quaternion localRot = trans.localRotation;// 本地旋转(四元数)
Vector3 euler = trans.eulerAngles; // 世界欧拉角(度)
Vector3 localEuler = trans.localEulerAngles; // 本地欧拉角
// ========== 缩放 ==========
Vector3 scale = trans.localScale; // 本地缩放(相对于父对象)
// 注意:没有 worldScale 属性,因为缩放受父对象影响
// ========== 方向向量 ==========
Vector3 forward = trans.forward; // 前方向(Z轴正方向)
Vector3 right = trans.right; // 右方向(X轴正方向)
Vector3 up = trans.up; // 上方向(Y轴正方向)
}
}
坐标系说明
Y (上/up)
│
│ Z (前/forward)
│ ╱
│ ╱
│ ╱
└────────── X (右/right)
╱
╱
╱
Unity 使用左手坐标系:
- X 轴:向右为正
- Y 轴:向上为正
- Z 轴:向前为正
位置操作
设置位置
// 直接设置世界坐标
transform.position = new Vector3(0, 5, 0);
transform.position = Vector3.zero; // (0, 0, 0)
transform.position = Vector3.one; // (1, 1, 1)
transform.position = Vector3.up * 10; // (0, 10, 0)
// 设置本地坐标(相对于父对象)
transform.localPosition = new Vector3(1, 0, 0);
// 只修改某个轴
transform.position = new Vector3(
transform.position.x,
10f,
transform.position.z
);
相对移动
// Translate 方法 - 相对当前位置移动
// 参数:位移向量,相对坐标系(默认 Space.Self)
// 向自己的前方移动 1 单位
transform.Translate(Vector3.forward);
// 向世界坐标上方移动 5 单位
transform.Translate(Vector3.up * 5f, Space.World);
// 向自己的右方移动 2 单位
transform.Translate(Vector3.right * 2f, Space.Self);
// 每帧向前移动(需要放在 Update 中)
void Update()
{
float speed = 5f;
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
平滑移动
public class SmoothMovement : MonoBehaviour
{
public Vector3 targetPosition;
public float smoothTime = 0.3f;
public float maxSpeed = 10f;
private Vector3 velocity = Vector3.zero;
void Update()
{
// 方法1:Lerp(线性插值)
// 速度会越来越慢
transform.position = Vector3.Lerp(
transform.position,
targetPosition,
0.1f
);
// 方法2:SmoothDamp(平滑阻尼)
// 更自然的减速效果
transform.position = Vector3.SmoothDamp(
transform.position,
targetPosition,
ref velocity,
smoothTime,
maxSpeed
);
// 方法3:MoveTowards(匀速移动)
float step = 5f * Time.deltaTime;
transform.position = Vector3.MoveTowards(
transform.position,
targetPosition,
step
);
}
}
旋转操作
欧拉角与四元数
// 欧拉角(Euler Angles)
// 优点:直观,容易理解
// 缺点:存在万向节锁(Gimbal Lock)问题
Vector3 euler = new Vector3(0, 90, 0); // Y轴旋转90度
// 四元数(Quaternion)
// 优点:避免万向节锁,插值更平滑
// 缺点:不直观,难以直接理解
Quaternion rotation = Quaternion.Euler(0, 90, 0);
设置旋转
// 使用欧拉角(简单但不推荐直接设置)
transform.eulerAngles = new Vector3(0, 45, 0);
// 使用四元数(推荐)
transform.rotation = Quaternion.Euler(0, 45, 0);
// 设置本地旋转
transform.localEulerAngles = new Vector3(0, 45, 0);
transform.localRotation = Quaternion.Euler(0, 45, 0);
相对旋转
// Rotate 方法 - 相对当前旋转
// 参数:旋转角度,旋转轴,相对坐标系
// 绕 Y 轴旋转 10 度
transform.Rotate(Vector3.up, 10f);
// 绕世界 Y 轴旋转
transform.Rotate(Vector3.up * 10f, Space.World);
// 绕自己的 X 轴旋转
transform.Rotate(Vector3.right * 5f, Space.Self);
// 每帧持续旋转
void Update()
{
transform.Rotate(0, 30 * Time.deltaTime, 0); // Y轴每秒转30度
}
看向目标
// LookAt - 让对象的 Z 轴指向目标
// 看向另一个对象
transform.LookAt(targetTransform);
// 看向特定位置
transform.LookAt(new Vector3(10, 0, 10));
// 指定自己的上方方向(防止翻转)
transform.LookAt(targetTransform, Vector3.up);
// 只在一个平面上看向目标(如只在 Y 轴旋转)
void LookAtTargetYOnly(Transform target)
{
Vector3 direction = target.position - transform.position;
direction.y = 0; // 忽略高度差
if (direction != Vector3.zero)
{
Quaternion rotation = Quaternion.LookRotation(direction);
transform.rotation = rotation;
}
}
平滑旋转
public class SmoothRotation : MonoBehaviour
{
public Transform target;
public float rotationSpeed = 5f;
void Update()
{
// 方法1:Lerp 插值
Quaternion targetRotation = Quaternion.LookRotation(
target.position - transform.position
);
transform.rotation = Quaternion.Lerp(
transform.rotation,
targetRotation,
Time.deltaTime * rotationSpeed
);
// 方法2:Slerp(球面线性插值,更适合旋转)
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
Time.deltaTime * rotationSpeed
);
// 方法3:RotateTowards(匀速旋转)
float maxRadiansDelta = rotationSpeed * Time.deltaTime;
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
maxRadiansDelta
);
}
}
缩放操作
// 设置本地缩放
transform.localScale = new Vector3(2, 2, 2); // 放大2倍
transform.localScale = Vector3.one * 1.5f; // 等比例放大
// 只修改某个轴
transform.localScale = new Vector3(
transform.localScale.x,
2f,
transform.localScale.z
);
// 均匀缩放
float scale = Mathf.PingPong(Time.time, 1) + 1; // 1-2之间变化
transform.localScale = Vector3.one * scale;
注意事项
- 缩放会影响子对象
- 负缩放可能导致渲染问题
- 物理对象的缩放会影响碰撞体
父子关系与坐标转换
本地坐标与世界坐标转换
// 本地坐标转世界坐标
Vector3 worldPos = transform.TransformPoint(localPos);
Vector3 worldDir = transform.TransformDirection(localDir);
Vector3 worldVector = transform.TransformVector(localVector);
// 世界坐标转本地坐标
Vector3 localPos = transform.InverseTransformPoint(worldPos);
Vector3 localDir = transform.InverseTransformDirection(worldDir);
Vector3 localVector = transform.InverseTransformVector(worldVector);
父子关系操作
// 设置父对象
transform.SetParent(parentTransform);
// 保持世界坐标不变设置父对象
transform.SetParent(parentTransform, true);
// 保持本地坐标不变设置父对象
transform.SetParent(parentTransform, false);
// 解除父子关系
transform.SetParent(null);
// 获取根对象(最顶层的父对象)
Transform root = transform.root;
// 判断是否子对象
bool isChild = transform.IsChildOf(parentTransform);
// 查找子对象
Transform child = transform.Find("ChildName");
Transform deepChild = transform.Find("Parent/Child/GrandChild");
实用工具方法
计算距离和方向
// 计算与目标的距离
float distance = Vector3.Distance(transform.position, target.position);
// 计算方向向量(归一化)
Vector3 direction = (target.position - transform.position).normalized;
// 计算角度差
float angle = Vector3.Angle(transform.forward, direction);
// 判断目标在左侧还是右侧
float dot = Vector3.Dot(transform.right, direction);
if (dot > 0) {
// 目标在右侧
} else {
// 目标在左侧
}
// 判断目标在前方还是后方
float forwardDot = Vector3.Dot(transform.forward, direction);
if (forwardDot > 0) {
// 目标在前方
}
限制和钳制
// 限制位置在某个范围内
Vector3 ClampPosition(Vector3 position, Vector3 min, Vector3 max)
{
return new Vector3(
Mathf.Clamp(position.x, min.x, max.x),
Mathf.Clamp(position.y, min.y, max.y),
Mathf.Clamp(position.z, min.z, max.z)
);
}
// 限制在圆形范围内
Vector3 ClampInCircle(Vector3 position, Vector3 center, float radius)
{
Vector3 offset = position - center;
if (offset.magnitude > radius)
{
offset = offset.normalized * radius;
}
return center + offset;
}
实践示例
示例1:相机跟随
public class CameraFollow : MonoBehaviour
{
public Transform target; // 跟随目标
public Vector3 offset = new Vector3(0, 5, -10); // 偏移量
public float smoothSpeed = 0.125f; // 平滑速度
void LateUpdate()
{
// 计算目标位置
Vector3 desiredPosition = target.position + offset;
// 平滑移动
Vector3 smoothedPosition = Vector3.Lerp(
transform.position,
desiredPosition,
smoothSpeed
);
transform.position = smoothedPosition;
// 看向目标
transform.LookAt(target);
}
}
示例2:第三人称角色控制
public class ThirdPersonController : MonoBehaviour
{
public float moveSpeed = 5f;
public float rotationSpeed = 10f;
void Update()
{
// 获取输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// 计算移动方向(相对于相机)
Vector3 direction = new Vector3(horizontal, 0, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
// 计算目标旋转角度
float targetAngle = Mathf.Atan2(direction.x, direction.z)
* Mathf.Rad2Deg
+ Camera.main.transform.eulerAngles.y;
// 平滑旋转
float angle = Mathf.SmoothDampAngle(
transform.eulerAngles.y,
targetAngle,
ref turnSmoothVelocity,
0.1f
);
transform.rotation = Quaternion.Euler(0, angle, 0);
// 向朝向的方向移动
Vector3 moveDir = Quaternion.Euler(0, targetAngle, 0) * Vector3.forward;
transform.Translate(moveDir * moveSpeed * Time.deltaTime, Space.World);
}
}
private float turnSmoothVelocity;
}
示例3:轨道相机
public class OrbitCamera : MonoBehaviour
{
public Transform target; // 环绕目标
public float distance = 10f; // 距离
public float sensitivity = 3f; // 灵敏度
private float yaw = 0f; // 水平角度
private float pitch = 20f; // 垂直角度
void Update()
{
// 获取鼠标输入
yaw += Input.GetAxis("Mouse X") * sensitivity;
pitch -= Input.GetAxis("Mouse Y") * sensitivity;
// 限制垂直角度
pitch = Mathf.Clamp(pitch, -80f, 80f);
// 计算旋转
Quaternion rotation = Quaternion.Euler(pitch, yaw, 0);
// 计算位置
Vector3 position = target.position - (rotation * Vector3.forward * distance);
transform.rotation = rotation;
transform.position = position;
}
}
示例4:巡逻移动
public class PatrolMovement : MonoBehaviour
{
public Transform[] waypoints; // 巡逻点
public float moveSpeed = 3f;
public float waitTime = 1f;
public float rotationSpeed = 5f;
private int currentIndex = 0;
private float waitTimer = 0f;
private bool isWaiting = false;
void Update()
{
if (isWaiting)
{
waitTimer += Time.deltaTime;
if (waitTimer >= waitTime)
{
isWaiting = false;
waitTimer = 0f;
currentIndex = (currentIndex + 1) % waypoints.Length;
}
return;
}
Transform target = waypoints[currentIndex];
// 计算方向和距离
Vector3 direction = (target.position - transform.position).normalized;
float distance = Vector3.Distance(transform.position, target.position);
// 旋转朝向目标
if (direction != Vector3.zero)
{
Quaternion targetRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime
);
}
// 移动
if (distance > 0.1f)
{
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}
else
{
isWaiting = true;
}
}
}
性能优化建议
-
缓存 Transform:在
Awake或Start中缓存transform引用private Transform myTransform;
void Awake() { myTransform = transform; } -
避免频繁修改:批量修改位置/旋转/缩放,而非逐帧修改
-
使用局部坐标:尽可能使用
localPosition和localRotation,计算更快 -
避免在 Update 中查找:缓存目标引用,不要每帧
Find或GetComponent
下一步
掌握 Transform 后,你可以: