158 lines
3.7 KiB
C#
Raw Normal View History

2025-11-05 17:34:40 +08:00
using Cinemachine;
using System;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace TweenAnimation
{
public enum ETweenType
{
Once,
Looped,
PingPong
}
[RequireComponent(typeof(CinemachineSmoothPath)), ExecuteAlways]
public class TweenPath : MonoBehaviour
{
[Serializable]
public class TweenTarget
{
public Transform transform;
public float startPos;
}
[SerializeReference]
public TweenTarget[] targets;
[SerializeField]
public CinemachineSmoothPath path;
[SerializeField, HideInInspector]
private Transform minStarPosTransform;
[SerializeField]
public ETweenType TweenType;
[Min(0.1f)] public float Duration = 1;
[Min(0)] public float Delay = 0;
[SerializeField]
public AnimationCurve speedCurve = AnimationCurve.Linear(0, 0, 1, 1);
private float playTime = 0;
private bool isPlaying = false;
#if UNITY_EDITOR
public bool isEditing = false;
#endif
private void Awake()
{
#if UNITY_EDITOR
path ??= GetComponent<CinemachineSmoothPath>();
#endif
}
private void Start()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
return;
}
#endif
Play();
}
#if UNITY_EDITOR
[ContextMenu("Play")]
#endif
public void Play()
{
isPlaying = true;
playTime = 0;
}
#if UNITY_EDITOR
[ContextMenu("Stop")]
#endif
public void Stop()
{
isPlaying = false;
playTime = 0;
}
private void Update()
{
#if UNITY_EDITOR
if (targets == null)
{
return;
}
if (!isEditing && !isPlaying && !Application.isPlaying)
{
float minStartPos = 10;
for (int i = 0; i < targets.Length; i++)
{
var target = targets[i];
EvaluatePosition(target.transform, target.startPos);
if (target.startPos < minStartPos)
{
minStartPos = target.startPos;
minStarPosTransform = target.transform;
}
}
}
#endif
if (!isPlaying)
{
return;
}
playTime += Time.smoothDeltaTime;
if (playTime < Delay)
{
return;
}
for (int i = 0; i < targets.Length; i++)
{
var target = targets[i];
var t = (playTime - Delay) / Duration + target.startPos;
EvaluatePosition(target.transform, t);
if (target.transform == minStarPosTransform && TweenType == ETweenType.Once && t >= 1)
{
Stop();
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EvaluatePosition(Transform transform, float t)
{
if (TweenType == ETweenType.Looped)
{
t = t % 1.0f;
}
else if (TweenType == ETweenType.PingPong)
{
if (((int)t & 1) == 0)
{
t = t % 1.0f;
}
else
{
t = 1f - (t % 1.0f);
}
}
var p = speedCurve.Evaluate(t);
p = p * (path.MaxPos - path.MinPos);
transform.localPosition = path.EvaluateLocalPosition(p);
}
}
}