133 lines
3.7 KiB
C#
133 lines
3.7 KiB
C#
using UnityEngine;
|
||
using System; // 必须引入 System 命名空间以使用 Action
|
||
using System.Collections;
|
||
|
||
public class YAxisRotator : MonoBehaviour
|
||
{
|
||
[Header("旋转设置")]
|
||
[Tooltip("旋转速度,度数/秒")]
|
||
public float rotationSpeed = 90f;
|
||
|
||
[Tooltip("判断是否到达目标角度的误差范围 (度)")]
|
||
public float angleThreshold = 0.5f;
|
||
|
||
private Coroutine _currentRotationCoroutine = null;
|
||
private float _targetAngle = 0f;
|
||
|
||
void Start()
|
||
{
|
||
_targetAngle = transform.localEulerAngles.y;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 方法1:旋转到180度
|
||
/// </summary>
|
||
/// <param name="onComplete">旋转完成后(或无需旋转时)执行的回调函数</param>
|
||
public void RotateTo180(Action onComplete = null)
|
||
{
|
||
// 检查是否已经接近180度
|
||
if (IsAngleClose(180f))
|
||
{
|
||
Debug.Log($"[{gameObject.name}] 已经在180度附近,跳过旋转,直接触发回调。");
|
||
_targetAngle = 180f;
|
||
|
||
// 【修改点】即使无需旋转,也立即触发回调
|
||
onComplete?.Invoke();
|
||
return;
|
||
}
|
||
|
||
// 如果正在旋转,先打断之前的旋转
|
||
if (_currentRotationCoroutine != null)
|
||
{
|
||
StopCoroutine(_currentRotationCoroutine);
|
||
// 注意:被打断的旧旋转不会触发回调,只有最终完成的那个会触发
|
||
}
|
||
|
||
_targetAngle = 180f;
|
||
_currentRotationCoroutine = StartCoroutine(RotateRoutine(180f, onComplete));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 方法2:旋转到0度
|
||
/// </summary>
|
||
/// <param name="onComplete">旋转完成后(或无需旋转时)执行的回调函数</param>
|
||
public void RotateTo0(Action onComplete = null)
|
||
{
|
||
// 检查是否已经接近0度
|
||
if (IsAngleClose(0f))
|
||
{
|
||
Debug.Log($"[{gameObject.name}] 已经在0度附近,跳过旋转,直接触发回调。");
|
||
_targetAngle = 0f;
|
||
|
||
// 【修改点】即使无需旋转,也立即触发回调
|
||
onComplete?.Invoke();
|
||
return;
|
||
}
|
||
|
||
if (_currentRotationCoroutine != null)
|
||
{
|
||
StopCoroutine(_currentRotationCoroutine);
|
||
}
|
||
|
||
_targetAngle = 0f;
|
||
_currentRotationCoroutine = StartCoroutine(RotateRoutine(0f, onComplete));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 核心协程:执行平滑旋转
|
||
/// </summary>
|
||
private IEnumerator RotateRoutine(float targetY, Action onComplete)
|
||
{
|
||
while (true)
|
||
{
|
||
Vector3 currentEuler = transform.localEulerAngles;
|
||
float currentY = currentEuler.y;
|
||
|
||
// 计算最短路径角度差
|
||
float delta = Mathf.DeltaAngle(currentY, targetY);
|
||
|
||
// 到达目标判断
|
||
if (Mathf.Abs(delta) <= angleThreshold)
|
||
{
|
||
transform.localRotation = Quaternion.Euler(0, targetY, 0);
|
||
|
||
// 旋转结束,触发回调
|
||
onComplete?.Invoke();
|
||
|
||
_currentRotationCoroutine = null;
|
||
yield break;
|
||
}
|
||
|
||
float step = rotationSpeed * Time.deltaTime;
|
||
|
||
// 最后一步修正
|
||
if (Mathf.Abs(delta) < step)
|
||
{
|
||
transform.localRotation = Quaternion.Euler(0, targetY, 0);
|
||
|
||
// 旋转结束,触发回调
|
||
onComplete?.Invoke();
|
||
|
||
_currentRotationCoroutine = null;
|
||
yield break;
|
||
}
|
||
|
||
// 执行旋转
|
||
float newY = currentY + Mathf.Sign(delta) * step;
|
||
transform.localRotation = Quaternion.Euler(0, newY, 0);
|
||
|
||
yield return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 辅助判断角度是否接近
|
||
/// </summary>
|
||
private bool IsAngleClose(float target)
|
||
{
|
||
float currentY = transform.localEulerAngles.y;
|
||
float delta = Mathf.DeltaAngle(currentY, target);
|
||
Debug.Log(delta);
|
||
return Mathf.Abs(delta) <= angleThreshold;
|
||
}
|
||
} |