前言
对于unity的旋转贼麻烦,用Dotween又要考虑打断,所以还是用最原始的方法在Update生命周期里用插值旋转方便。为了更方便模仿Dotween写了个基类希望大家喜欢
调用案例
using UnityEngine;
public class EnemyController : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotateSpeed = 180f;
private void Update()
{
// 1. 移动到目标位置
bool reached = transform.MoveToTransform(target, moveSpeed, Time.deltaTime);
if (reached)
{
Debug.Log("已到达目标位置");
}
// 2. 旋转到目标
bool rotated = transform.RotateTowardsTarget(target, rotateSpeed, Time.deltaTime);
// 3. 旋转到指定欧拉角
transform.RotateToEuler(new Vector3(0, 90, 0), rotateSpeed, Time.deltaTime);
// 4. 移动到指定位置
Vector3 targetPosition = new Vector3(10, 0, 5);
transform.MoveToPosition(targetPosition, moveSpeed, Time.deltaTime);
// 5. 移动到局部坐标系原点XZ平面
transform.MoveToOriginXZ(moveSpeed, Time.deltaTime);
}
}
代码
using UnityEngine; public static class TransformTool { /// <summary> /// 将Transform平滑移动到目标Transform的位置 /// </summary> /// <param name="transform">要移动的Transform</param> /// <param name="target">目标Transform</param> /// <param name="speed">移动速度(单位/秒)</param> /// <param name="deltaTime">时间增量</param> /// <param name="lockYAxis">是否锁定Y轴</param> /// <returns>是否已到达目标位置</returns> public static bool MoveToTransform(this Transform transform, Transform target, float speed, float deltaTime, bool lockYAxis = true) { // 检查目标是否有效 if (target == null) { Debug.LogWarning("MoveToTransform: 目标Transform为空"); return false; } // 获取当前位置和目标位置 Vector3 currentPos = transform.position; Vector3 targetPos = target.position; // 计算当前位置到目标位置的距离 float distance = Vector3.Distance(currentPos, targetPos); // 如果已经在目标位置附近,直接完成 if (distance < 0.01f) { transform.position = targetPos; // 精确移动到目标位置 return true; } // 使用插值移动到目标位置 Vector3 newPos = Vector3.MoveTowards(currentPos, targetPos, speed * deltaTime); // 锁定Y轴 if (lockYAxis) { newPos.y = transform.position.y; } transform.position = newPos; // 计算新位置到目标的距离 float newDistance = Vector3.Distance(newPos, targetPos); // 判断是否到达(距离小于0.1个单位认为到达) return newDistance < 0.1f; } /// <summary> /// 将物体插值移动到父物体坐标系的X=0, Z=0位置 /// 保持Y轴不变 /// </summary> /// <param name="transform">要移动的物体Transform</param> /// <param name="speed">移动速度</param> /// <param name="deltaTime">时间增量</param> /// <returns>是否已到达目标位置</returns> public static bool MoveToOriginXZ(this Transform transform, float speed, float deltaTime) { // 获取当前位置(局部坐标) Vector3 localPos = transform.localPosition; // 如果已经在目标位置,直接返回true if (Mathf.Abs(localPos.x) < 0.01f && Mathf.Abs(localPos.z) < 0.01f) { // 确保精确归零 transform.localPosition = new Vector3(0, localPos.y, 0); return true; } // 计算新位置:X和Z向0移动,Y保持不变 Vector3 targetPos = new Vector3(0, localPos.y, 0); Vector3 newPos = Vector3.MoveTowards(localPos, targetPos, speed * deltaTime); // 应用新位置 transform.localPosition = newPos; // 检查是否到达(使用较小阈值) float distance = Vector2.Distance( new Vector2(newPos.x, newPos.z), Vector2.zero ); return distance < 0.01f; } /// <summary> /// 旋转到指定的欧拉角 /// </summary> /// <param name="transform">物体</param> /// <param name="targetEuler">目标欧拉角</param> /// <param name="rotateSpeed">旋转速度(度/秒)</param> /// <param name="deltaTime">时间增量</param> /// <returns>是否已旋转到位</returns> public static bool RotateToEuler(this Transform transform, Vector3 targetEuler, float rotateSpeed, float deltaTime) { // 获取当前旋转 Quaternion currentRotation = transform.rotation; Quaternion targetRotation = Quaternion.Euler(targetEuler); // 如果已经非常接近目标旋转 if (Quaternion.Angle(currentRotation, targetRotation) < 0.1f) { transform.rotation = targetRotation; // 直接设置为目标旋转 return true; } // 使用插值旋转到目标四元数 Quaternion newRotation = Quaternion.RotateTowards( currentRotation, targetRotation, rotateSpeed * deltaTime ); // 应用旋转 transform.rotation = newRotation; // 返回是否已旋转到位(角度差小于1度认为完成) return Quaternion.Angle(newRotation, targetRotation) < 1f; } /// <summary> /// 旋转到指定的四元数 /// </summary> /// <param name="transform">物体</param> /// <param name="targetRotation">目标四元数</param> /// <param name="rotateSpeed">旋转速度(度/秒)</param> /// <param name="deltaTime">时间增量</param> /// <returns>是否已旋转到位</returns> public static bool RotateToQuaternion(this Transform transform, Quaternion targetRotation, float rotateSpeed, float deltaTime) { // 获取当前旋转 Quaternion currentRotation = transform.rotation; // 如果已经非常接近目标旋转 if (Quaternion.Angle(currentRotation, targetRotation) < 0.1f) { transform.rotation = targetRotation; // 直接设置为目标旋转 return true; } // 使用插值旋转到目标四元数 Quaternion newRotation = Quaternion.RotateTowards( currentRotation, targetRotation, rotateSpeed * deltaTime ); // 应用旋转 transform.rotation = newRotation; // 返回是否已旋转到位(角度差小于1度认为完成) return Quaternion.Angle(newRotation, targetRotation) < 1f; } /// <summary> /// 插值转向指定目标 /// </summary> /// <param name="transform">需要旋转的Transform</param> /// <param name="target">目标Transform</param> /// <param name="rotationSpeed">旋转速度(度/秒)</param> /// <param name="deltaTime">时间增量</param> /// <param name="offsetEuler">旋转偏移量(欧拉角)</param> /// <param name="ignoreYAxis">是否忽略Y轴(水平旋转)</param> /// <returns>是否已旋转到目标方向</returns> public static bool RotateTowardsTarget(this Transform transform, Transform target, float rotationSpeed, float deltaTime, Vector3 offsetEuler = default, bool ignoreYAxis = true) { if (transform == null || target == null) { Debug.LogWarning("RotateTowardsTarget: 自身或目标Transform为空"); return false; } // 计算目标方向 Vector3 direction = target.position - transform.position; // 是否忽略Y轴 if (ignoreYAxis) { direction.y = 0; // 锁定Y轴,确保在水平面旋转 // 如果水平方向几乎为零,则不旋转 if (direction.sqrMagnitude < 0.0001f) { return true; // 可以认为已经面向目标 } } // 计算目标旋转 Quaternion targetRotation = Quaternion.LookRotation(direction.normalized, Vector3.up); // 应用偏移 if (offsetEuler != Vector3.zero) { targetRotation *= Quaternion.Euler(offsetEuler); } // 获取当前旋转 Quaternion currentRotation = transform.rotation; // 计算当前角度差 float currentAngle = Quaternion.Angle(currentRotation, targetRotation); // 如果已经接近目标旋转 if (currentAngle <= 0.1f) { transform.rotation = targetRotation; // 精确设置为目标旋转 return true; } // 使用插值平滑旋转 transform.rotation = Quaternion.RotateTowards( currentRotation, targetRotation, rotationSpeed * deltaTime ); // 计算新的角度差 float newAngle = Quaternion.Angle(transform.rotation, targetRotation); // 返回是否已旋转到位(角度差小于1度认为完成) return newAngle < 1f; } /// <summary> /// 平滑移动到指定位置 /// </summary> /// <param name="transform">要移动的Transform</param> /// <param name="targetPosition">目标位置</param> /// <param name="speed">移动速度(单位/秒)</param> /// <param name="deltaTime">时间增量</param> /// <param name="lockYAxis">是否锁定Y轴</param> /// <returns>是否已到达目标位置</returns> public static bool MoveToPosition(this Transform transform, Vector3 targetPosition, float speed, float deltaTime, bool lockYAxis = true) { // 获取当前位置 Vector3 currentPos = transform.position; // 计算当前位置到目标位置的距离 float distance = Vector3.Distance(currentPos, targetPosition); // 如果已经在目标位置附近,直接完成 if (distance < 0.01f) { transform.position = targetPosition; // 精确移动到目标位置 return true; } // 使用插值移动到目标位置 Vector3 newPos = Vector3.MoveTowards(currentPos, targetPosition, speed * deltaTime); // 锁定Y轴 if (lockYAxis) { newPos.y = transform.position.y; } transform.position = newPos; // 计算新位置到目标的距离 float newDistance = Vector3.Distance(newPos, targetPosition); // 判断是否到达(距离小于0.1个单位认为到达) return newDistance < 0.1f; } }

4262

被折叠的 条评论
为什么被折叠?



