loudixvmuniu/Assets/_Scripts/Framework/Utilities/TimelineDirectorCtrl.cs
2025-01-02 19:54:22 +08:00

230 lines
6.5 KiB
C#

using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
/*******************************************************************************
*Create By CG
*Function Timeline正播倒播辅助类
*******************************************************************************/
namespace CG.UTility
{
[RequireComponent(typeof(PlayableDirector))]
public class TimelineDirectorCtrl : MonoBehaviour
{
#region ENUM
public enum Status
{
NULL,
PLAYING,
PAUSED,
STOPPED,
}
public enum Direction
{
NULL,
FORWARD,
BACKWARD
}
#endregion
[SerializeField]
private PlayableDirector m_playableDirector;
[Range(0f, 1f)]
public float PlaySpeed = 1f;
/// <summary>
/// 播放模式
/// </summary>
public WrapMode WrapMode = WrapMode.Once;
/// <summary>
/// 开始播放事件, 返回时 时间点,和触发时方向
/// </summary>
public Action<double, Direction> OnPlay;
/// <summary>
/// 暂停播放事件, 返回时 时间点,和触发时方向
/// </summary>
public Action<double, Direction> OnPause;
/// <summary>
/// 停止播放事件, 返回时 时间点,和触发时方向
/// </summary>
public Action<double, Direction> OnStop;
/// <summary>
/// 继续播放事件, 返回时 时间点,和触发时方向
/// </summary>
public Action<double, Direction> OnContinue;
/// <summary>
/// Timeline长度
/// </summary>
public double Duration { get; private set; } = -1f;
/// <summary>
/// 当前播放状态(如果用不到可是删除,现在这个字段只是一个状态的记录)
/// </summary>
public Status CurrentPlayStatus { get; private set; } = Status.NULL;
/// <summary>
/// 当前播放方向(如果用不到可是删除,现在这个字段只是一个状态的记录)
/// </summary>
public Direction CurrentPlayDirection { get; private set; } = Direction.NULL;
/// <summary>
/// 当前播放进度
/// </summary>
public double CurrentTime { get; private set; } = 0d;
private Tweener m_timeTween;
private void Awake()
{
m_playableDirector = GetComponent<PlayableDirector>();
m_playableDirector.playOnAwake = false;
Duration = m_playableDirector.duration;
CurrentPlayStatus = Status.STOPPED;
}
public void SetDuration()
{
Duration = m_playableDirector.duration;
}
/// <summary>
/// 继续播放
/// </summary>
public void Continue()
{
OnContinue?.Invoke(CurrentTime, CurrentPlayDirection);
CurrentPlayStatus = Status.PLAYING;
CurrentPlayDirection = Direction.FORWARD;
m_timeTween.Kill();
RatioExecute(Duration);
}
/// <summary>
/// 从暂停时间点正向播放到指定时间点, 应用在倒播中途暂停后切换为正播
/// </summary>
public void ContinuePlayForwardByPausePoint(double time,Action finishCall)
{
OnContinue?.Invoke(CurrentTime, CurrentPlayDirection);
CurrentPlayStatus = Status.PLAYING;
CurrentPlayDirection = Direction.FORWARD;
m_timeTween.Kill();
RatioExecute(time);
m_timeTween.OnComplete(()=> { finishCall?.Invoke(); });
}
/// <summary>
/// 从暂停时间点反向播放到指定时间点, 应用在正播中途暂停后切换为倒播
/// </summary>
public void ContinuePlayBackwardByPausePoint(double time, Action finishCall)
{
OnContinue?.Invoke(CurrentTime, CurrentPlayDirection);
CurrentPlayStatus = Status.PLAYING;
CurrentPlayDirection = Direction.BACKWARD;
m_timeTween.Kill();
RatioExecute(time);
m_timeTween.OnComplete(() => { finishCall?.Invoke(); });
}
/// <summary>
/// 从开始播放
/// </summary>
public void PlayForward()
{
OnPlay?.Invoke(CurrentTime, CurrentPlayDirection);
m_timeTween.Kill();
CurrentTime = 0d;
RatioExecute(Duration);
}
/// <summary>
/// 从结尾倒放
/// </summary>
public void PlayBackward()
{
OnPlay?.Invoke(CurrentTime, CurrentPlayDirection);
m_timeTween.Kill();
CurrentTime = Duration;
RatioExecute(0);
}
/// <summary>
/// 暂停播放
/// </summary>
public void Pause()
{
OnPause?.Invoke(CurrentTime, CurrentPlayDirection);
m_timeTween.Pause();
}
/// <summary>
/// 暂停在某个时间点
/// </summary>
public void StopInTime(double time)
{
m_timeTween.Kill();
CurrentTime = time;
m_playableDirector.time = CurrentTime;
m_playableDirector.Evaluate();
}
/// <summary>
/// 停止播放
/// </summary>
public void Stop()
{
OnStop?.Invoke(CurrentTime, CurrentPlayDirection);
m_timeTween.Kill();
CurrentTime = 0d;
if (m_playableDirector)
{
m_playableDirector.time = CurrentTime;
m_playableDirector.Evaluate();
}
DOTween.KillAll();
}
private void RatioExecute(double target)
{
// 使用DoTween最当前时间进行线性过渡
m_timeTween = DOTween.To(() => CurrentTime, x => CurrentTime = x, target, PlaySpeed).SetSpeedBased().SetEase(Ease.Linear);
// 做出限制避免bug
CurrentTime = Clamp(CurrentTime, 0d, Duration);
m_timeTween.OnUpdate(() =>
{
// 直接取样
if (m_playableDirector != null)
{
m_playableDirector.time = CurrentTime;
m_playableDirector.Evaluate();
}
});
m_timeTween.Play();
}
/// <summary>
/// 针对Double的Clamp
/// </summary>
public static double Clamp(double value, double min, double max)
{
if (value < min)
value = min;
else if (value > max)
value = max;
return value;
}
}
}