using System; using System.Collections; using AibisDream.Framework; using UnityEngine; using UnityEngine.ResourceManagement.AsyncOperations; namespace AibisDream { public class AnimatorHandler : MonoBehaviour { private const string AnimationPrefix = "Animation/"; public string animatorName; [SerializeField] private Animator animator; [Tooltip("若当前状态为 Loop:勾选则播完一整轮后触发完成回调;不勾选则循环状态不会结束(异步会一直等待)")] [SerializeField] private bool completeAfterOneCycleWhenStateLoops = true; private float _speedBeforePause = 1f; private AsyncOperationHandle _addressableHandle; private RuntimeAnimatorController _savedRuntimeAnimatorController; private Coroutine _playCompletionCoroutine; private Action _onCompleteCallback; #if UNITY_EDITOR private void OnValidate() { ValidateSerializedAnimator(); } #endif private void Start() { AnimatorCenter.Instance.RegisterHandler(this); } private void OnDestroy() { AnimatorCenter.Instance.UnregisterHandler(this); CancelCompletionCoroutine(); if (animator != null) animator.speed = _speedBeforePause > 0f ? _speedBeforePause : 1f; ReleaseAddressableHandle(); } private void ValidateSerializedAnimator() { if (animator != null && animator.transform == transform) animator = null; } private bool EnsureAnimator() { if (animator != null) return true; Debug.LogError($"AnimatorHandler {animatorName}: 未在子物体上找到 Animator。", this); return false; } private void CancelCompletionCoroutine() { if (_playCompletionCoroutine == null) return; StopCoroutine(_playCompletionCoroutine); _playCompletionCoroutine = null; } private void ReleaseAddressableHandle() { if (!_addressableHandle.IsValid()) return; if (animator != null && animator.runtimeAnimatorController == _addressableHandle.Result) animator.runtimeAnimatorController = _savedRuntimeAnimatorController; ResourceKit.Release(_addressableHandle); _addressableHandle = default; _savedRuntimeAnimatorController = null; } private void EnsurePlayingSpeedForNewClip() { if (animator != null && animator.speed < 0.001f) animator.speed = _speedBeforePause > 0f ? _speedBeforePause : 1f; } /// /// 对挂载 调用 , /// 不是修改 。Handler 根物体可保持激活以便协程与注册。 /// public void SetAnimatorObjectActive(bool active) { if (animator == null) return; animator.gameObject.SetActive(active); } private void ActivateAnimatorGameObject() { SetAnimatorObjectActive(true); } /// /// 使用当前 Animator 上已绑定的控制器播放指定状态。 /// public void Play(string stateName, int layer = 0, Action onComplete = null) { if (!EnsureAnimator()) return; ActivateAnimatorGameObject(); CancelCompletionCoroutine(); ReleaseAddressableHandle(); _onCompleteCallback = onComplete; EnsurePlayingSpeedForNewClip(); animator.Play(stateName, layer, 0f); animator.Update(0f); if (onComplete != null) _playCompletionCoroutine = StartCoroutine(WaitForStatePlaybackEnd(layer, stateName, true)); } public IEnumerator PlayAsync(string stateName, int layer = 0) { if (!EnsureAnimator()) yield break; ActivateAnimatorGameObject(); CancelCompletionCoroutine(); ReleaseAddressableHandle(); EnsurePlayingSpeedForNewClip(); animator.Play(stateName, layer, 0f); animator.Update(0f); yield return WaitForStatePlaybackEnd(layer, stateName, false); } private void OnPlaybackComplete() { _playCompletionCoroutine = null; var completionCallback = _onCompleteCallback; _onCompleteCallback = null; ReleaseAddressableHandle(); completionCallback?.Invoke(); } /// 为 true 时在结束时调用 (含 Addressable 释放与 Action);为 false 时仅做 Addressable 释放(用于无回调异步) private IEnumerator WaitForStatePlaybackEnd(int layer, string stateName, bool invokeCompletionCallback) { var timeout = 10f; while (timeout > 0f) { var currentStateInfo = animator.GetCurrentAnimatorStateInfo(layer); if (currentStateInfo.IsName(stateName) && !animator.IsInTransition(layer)) break; timeout -= Time.deltaTime; yield return null; } while (true) { var currentStateInfo = animator.GetCurrentAnimatorStateInfo(layer); if (!currentStateInfo.IsName(stateName)) { if (invokeCompletionCallback) OnPlaybackComplete(); else ReleaseAddressableHandle(); yield break; } if (animator.IsInTransition(layer)) { yield return null; continue; } if (currentStateInfo.loop) { if (completeAfterOneCycleWhenStateLoops && currentStateInfo.normalizedTime >= 1f) { if (invokeCompletionCallback) OnPlaybackComplete(); else ReleaseAddressableHandle(); yield break; } } else if (currentStateInfo.normalizedTime >= 1f) { if (invokeCompletionCallback) OnPlaybackComplete(); else ReleaseAddressableHandle(); yield break; } yield return null; } } /// /// 从 Addressables 加载 RuntimeAnimatorController(键为 Animation/ + addressableKey)并播放状态。 /// public void PlayFromAddressable(string addressableKey, string stateName, int layer = 0, Action onComplete = null) { StartCoroutine(PlayFromAddressableCoroutine(addressableKey, stateName, layer, onComplete)); } public IEnumerator PlayFromAddressableAsync(string addressableKey, string stateName, int layer = 0) { yield return PlayFromAddressableCoroutine(addressableKey, stateName, layer, null); } private IEnumerator PlayFromAddressableCoroutine(string addressableKey, string stateName, int layer, Action onComplete) { if (!EnsureAnimator()) yield break; ActivateAnimatorGameObject(); if (string.IsNullOrEmpty(addressableKey)) { Debug.LogError($"AnimatorHandler {animatorName}: addressableKey 为空。", this); yield break; } ReleaseAddressableHandle(); var loadKey = AnimationPrefix + addressableKey; RuntimeAnimatorController loaded = null; AsyncOperationHandle loadedHandle = default; var loadDone = false; ResourceKit.LoadAssetAsyncWithHandle(loadKey, loadHandle => { loadedHandle = loadHandle; if (loadHandle.Status == AsyncOperationStatus.Succeeded) loaded = loadHandle.Result; loadDone = true; }); yield return new WaitUntil(() => loadDone); if (loaded == null) { Debug.LogError($"AnimatorHandler {animatorName}: 加载失败 '{loadKey}'", this); yield break; } CancelCompletionCoroutine(); _savedRuntimeAnimatorController = animator.runtimeAnimatorController; animator.runtimeAnimatorController = loaded; animator.Rebind(); animator.Update(0f); _addressableHandle = loadedHandle; EnsurePlayingSpeedForNewClip(); _onCompleteCallback = onComplete; animator.Play(stateName, layer, 0f); animator.Update(0f); if (onComplete != null) { _playCompletionCoroutine = StartCoroutine(WaitForStatePlaybackEnd(layer, stateName, true)); while (_playCompletionCoroutine != null) yield return null; } else { yield return WaitForStatePlaybackEnd(layer, stateName, false); } } public void Stop() { if (!EnsureAnimator()) return; CancelCompletionCoroutine(); _onCompleteCallback = null; animator.speed = 0f; ReleaseAddressableHandle(); } public void Pause() { if (!EnsureAnimator()) return; if (animator.speed > 0f) { _speedBeforePause = animator.speed; animator.speed = 0f; } } public void Resume() { if (!EnsureAnimator()) return; if (animator.speed == 0f) animator.speed = _speedBeforePause > 0f ? _speedBeforePause : 1f; } public void Reset() { if (!EnsureAnimator()) return; CancelCompletionCoroutine(); _onCompleteCallback = null; animator.speed = 1f; animator.Rebind(); animator.Update(0f); ReleaseAddressableHandle(); } /// /// 将 Animator 状态机恢复到当前 的默认入口状态(参数与层会按控制器重置), /// 不释放 Addressable、不还原已替换的运行时控制器。用于在保留当前加载的控制器前提下清掉过渡与参数。 /// public void ReturnToDefaultState() { if (!EnsureAnimator()) return; CancelCompletionCoroutine(); _onCompleteCallback = null; EnsurePlayingSpeedForNewClip(); animator.Rebind(); animator.Update(0f); } /// /// 当前层当前状态下,已播放时长(秒)。过渡或非目标状态时语义以当前 StateInfo 为准。 /// public float GetPlaybackTime(int layer = 0) { if (animator == null) return 0f; var currentStateInfo = animator.GetCurrentAnimatorStateInfo(layer); return currentStateInfo.normalizedTime * currentStateInfo.length; } /// /// 当前层当前状态片段长度(秒)。 /// public float GetDuration(int layer = 0) { if (animator == null) return 0f; return animator.GetCurrentAnimatorStateInfo(layer).length; } public void SetPlaybackSpeed(float speed) { if (!EnsureAnimator()) return; animator.speed = speed; if (speed > 0f) _speedBeforePause = speed; } /// /// 在当前层下,将播放位置 seek 到指定时间(秒),相对当前状态片段长度归一化后播放。 /// public void SeekToTime(double timeSeconds, int layer = 0) { if (!EnsureAnimator()) return; var currentStateInfo = animator.GetCurrentAnimatorStateInfo(layer); var stateLengthSeconds = currentStateInfo.length; if (stateLengthSeconds <= 0.0001f) return; var normalizedPlaybackTime = Mathf.Clamp01((float)(timeSeconds / stateLengthSeconds)); animator.Play(currentStateInfo.shortNameHash, layer, normalizedPlaybackTime); animator.Update(0f); } } }