fix(scene-mgmt): 修复 Timeline 播放结束后可选回到起点
Made-with: Cursor
This commit is contained in:
@@ -20,9 +20,17 @@ namespace AibisDream
|
||||
[Tooltip("加载新 Timeline 时自动绑定 CinemachineBrain")]
|
||||
[SerializeField] private bool autoBindCinemachineBrain;
|
||||
|
||||
[Header("播放结束")]
|
||||
[Tooltip("勾选:自然播放到结尾(PlayableDirector.stopped)后将时间设回 0;不勾选:停留在最后一帧(默认)")]
|
||||
[SerializeField] private bool resetToStartWhenFinished;
|
||||
[Tooltip("当 resetToStartWhenFinished 为真时,回到时间 0 前的等待秒数;0 表示立刻回到起点")]
|
||||
[Min(0f)]
|
||||
[SerializeField] private float resetToStartDelay;
|
||||
|
||||
private Action _onCompleteCallback;
|
||||
private AsyncOperationHandle<PlayableAsset> _addressableHandle;
|
||||
private PlayableAsset _savedPlayableAsset;
|
||||
private Coroutine _pendingResetToStartCoroutine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
@@ -54,6 +62,8 @@ namespace AibisDream
|
||||
{
|
||||
TimelineCenter.Instance.UnregisterDirector(this);
|
||||
|
||||
CancelPendingResetToStartCoroutine();
|
||||
|
||||
if (director != null)
|
||||
{
|
||||
director.stopped -= OnDirectorStopped;
|
||||
@@ -62,6 +72,58 @@ namespace AibisDream
|
||||
ReleaseAddressableHandle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要订阅 PlayableDirector.stopped(完成回调或需要播放结束行为时)。
|
||||
/// </summary>
|
||||
private bool ShouldSubscribeStopped(Action onComplete)
|
||||
{
|
||||
return onComplete != null || resetToStartWhenFinished;
|
||||
}
|
||||
|
||||
private void CancelPendingResetToStartCoroutine()
|
||||
{
|
||||
if (_pendingResetToStartCoroutine == null) return;
|
||||
StopCoroutine(_pendingResetToStartCoroutine);
|
||||
_pendingResetToStartCoroutine = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 Director 时间设到 0 并刷新一帧(不 Stop、不释放资源)。
|
||||
/// </summary>
|
||||
private void ApplyPlaybackTimeZero()
|
||||
{
|
||||
if (director == null) return;
|
||||
director.time = 0;
|
||||
director.Evaluate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在 Release + 完成回调之后执行:按配置回到起点或延时回到起点。
|
||||
/// </summary>
|
||||
private void ApplyEndBehaviorAfterStopped()
|
||||
{
|
||||
if (!resetToStartWhenFinished) return;
|
||||
|
||||
CancelPendingResetToStartCoroutine();
|
||||
|
||||
var delay = Mathf.Max(0f, resetToStartDelay);
|
||||
if (delay <= 0f)
|
||||
{
|
||||
ApplyPlaybackTimeZero();
|
||||
}
|
||||
else
|
||||
{
|
||||
_pendingResetToStartCoroutine = StartCoroutine(ResetToStartAfterDelayCoroutine(delay));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ResetToStartAfterDelayCoroutine(float delaySeconds)
|
||||
{
|
||||
yield return new WaitForSeconds(delaySeconds);
|
||||
_pendingResetToStartCoroutine = null;
|
||||
ApplyPlaybackTimeZero();
|
||||
}
|
||||
|
||||
private void ReleaseAddressableHandle()
|
||||
{
|
||||
if (!_addressableHandle.IsValid()) return;
|
||||
@@ -156,6 +218,7 @@ namespace AibisDream
|
||||
}
|
||||
|
||||
// 先停止再播放
|
||||
CancelPendingResetToStartCoroutine();
|
||||
director.stopped -= OnDirectorStopped;
|
||||
if (director.state == PlayState.Playing)
|
||||
{
|
||||
@@ -164,8 +227,7 @@ namespace AibisDream
|
||||
|
||||
_onCompleteCallback = onComplete;
|
||||
|
||||
// 如果有完成回调,订阅 stopped 事件
|
||||
if (onComplete != null)
|
||||
if (ShouldSubscribeStopped(onComplete))
|
||||
{
|
||||
director.stopped += OnDirectorStopped;
|
||||
}
|
||||
@@ -187,12 +249,18 @@ namespace AibisDream
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 先停止再播放
|
||||
CancelPendingResetToStartCoroutine();
|
||||
director.stopped -= OnDirectorStopped;
|
||||
if (director.state == PlayState.Playing)
|
||||
{
|
||||
director.Stop();
|
||||
}
|
||||
|
||||
if (ShouldSubscribeStopped(null))
|
||||
{
|
||||
director.stopped += OnDirectorStopped;
|
||||
}
|
||||
|
||||
// 自动绑定 CinemachineBrain
|
||||
AutoBindCinemachineBrain();
|
||||
|
||||
@@ -259,6 +327,7 @@ namespace AibisDream
|
||||
yield break;
|
||||
}
|
||||
|
||||
CancelPendingResetToStartCoroutine();
|
||||
director.stopped -= OnDirectorStopped;
|
||||
if (director.state == PlayState.Playing)
|
||||
{
|
||||
@@ -276,7 +345,7 @@ namespace AibisDream
|
||||
_addressableHandle = loadedHandle;
|
||||
|
||||
_onCompleteCallback = onComplete;
|
||||
if (onComplete != null)
|
||||
if (ShouldSubscribeStopped(onComplete))
|
||||
{
|
||||
director.stopped += OnDirectorStopped;
|
||||
}
|
||||
@@ -297,6 +366,8 @@ namespace AibisDream
|
||||
{
|
||||
if (director == null) return;
|
||||
|
||||
CancelPendingResetToStartCoroutine();
|
||||
|
||||
// 先取消事件订阅,避免 Stop() 触发回调
|
||||
director.stopped -= OnDirectorStopped;
|
||||
|
||||
@@ -338,12 +409,13 @@ namespace AibisDream
|
||||
{
|
||||
if (director == null) return;
|
||||
|
||||
CancelPendingResetToStartCoroutine();
|
||||
|
||||
// 先取消事件订阅,避免 Stop() 触发回调
|
||||
director.stopped -= OnDirectorStopped;
|
||||
|
||||
director.Stop();
|
||||
director.time = 0;
|
||||
director.Evaluate();
|
||||
ApplyPlaybackTimeZero();
|
||||
|
||||
_onCompleteCallback = null;
|
||||
ReleaseAddressableHandle();
|
||||
@@ -398,16 +470,18 @@ namespace AibisDream
|
||||
/// <summary>
|
||||
/// Director 停止事件处理
|
||||
/// </summary>
|
||||
private void OnDirectorStopped(PlayableDirector director)
|
||||
private void OnDirectorStopped(PlayableDirector stoppedDirector)
|
||||
{
|
||||
// 立即取消订阅,避免重复触发
|
||||
director.stopped -= OnDirectorStopped;
|
||||
stoppedDirector.stopped -= OnDirectorStopped;
|
||||
|
||||
var callback = _onCompleteCallback;
|
||||
_onCompleteCallback = null;
|
||||
|
||||
ReleaseAddressableHandle();
|
||||
callback?.Invoke();
|
||||
|
||||
ApplyEndBehaviorAfterStopped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user