using System; using System.Collections.Generic; using UnityEngine; namespace SLSUtilities.FunctionalAnimation { /// /// 纯净的 FunctionalAnimation 物理播放器基类。 /// 负责管理注册数据集、时间推进、动画混合、事件分发以及无战斗业务耦合的通用区间查询。 /// public class FuncAnimPlayer { private static readonly int ActionSpeed = Animator.StringToHash("ActionSpeed"); /// 执行当前动画的实体对象(如 CharacterBase 或 NpcBase) public IFuncAnimExecutor Executor { get; } /// 实体关联的动画状态机组件 public Animator Animator { get; } /// 动作所播放的 Animator Layer 目标层级名称 public string animatorLayerName; /// 当前正在播放的动作运行时状态 public RuntimeFuncAnim currentRuntimeFuncAnim; /// 动作播放速度的临时缩放倍率 public float currentPlaySpeedMultiplier = 1f; /// 实体本地注册的动作数据集查找字典 public Dictionary collection; // ── 快捷只读时间/帧属性 ── public FuncAnimData currentData => currentRuntimeFuncAnim?.funcAnimData; public AnimationClip currentClip => currentData?.animationClip; public float currentPlayTime => currentRuntimeFuncAnim?.currentPlayTime ?? 0f; public float currentTotalPlayTime => currentRuntimeFuncAnim?.currentTotalPlayTime ?? 0f; /// 当前动画播放的归一化进度 (0 到 1) public float currentNormalizedPlayTime => (currentClip != null && currentClip.length > 0f) ? Mathf.Min(1f, currentPlayTime / currentClip.length) : 0f; /// 当前动画播放对应的帧数 public float currentFrame => (currentRuntimeFuncAnim != null && currentClip != null) ? (currentRuntimeFuncAnim.currentPlayTime * currentClip.frameRate) : 0f; /// 经播放速度缩放后的总动画剪辑时长 public float currentScaledClipLength => (currentClip != null) ? (currentClip.length / currentPlaySpeedMultiplier) : 0f; /// 当前是否有动画正在播放 public bool IsPlaying => currentRuntimeFuncAnim != null; public FuncAnimPlayer(IFuncAnimExecutor executor, string layerName = "FullBodyAction") { Executor = executor; Animator = executor.Animator; animatorLayerName = layerName; collection = new Dictionary(); } /// /// 注册动作资源到本地字典中 /// public virtual void Add(FuncAnimData animation) { if (animation == null) return; collection[animation.animInfo.animationName] = animation; } /// /// 从动作库中移除指定动画 /// public virtual void Remove(string animationName) { if (collection.ContainsKey(animationName)) { collection.Remove(animationName); } } /// /// 重新覆盖注册某个动画数据 /// public virtual void Reset(FuncAnimData animation) { if (animation == null) return; Remove(animation.animInfo.animationName); Add(animation); } /// /// 通过动画名称查找并播放动作。 /// public virtual bool Play(string animationName, float speedMultiplier = 1f, float transitionDuration = 0.1f, bool isNormalizedTransition = false, float normalizedStartTime = -1f, List runtimeStartEvents = null) { if (!collection.TryGetValue(animationName, out FuncAnimData funcAnimData)) { // 使用 GetType().Name 动态输出子类名称,避免日志混淆 Debug.LogWarning($"[{GetType().Name}] 动作库中未找到名为 '{animationName}' 的动作数据。"); return false; } return Play(funcAnimData, speedMultiplier, transitionDuration, isNormalizedTransition, normalizedStartTime, runtimeStartEvents); } /// /// 物理执行动作播放的核心实现。 /// public virtual bool Play(FuncAnimData data, float speedMultiplier = 1f, float transitionDuration = 0.1f, bool isNormalizedTransition = false, float normalizedStartTime = -1f, List runtimeStartEvents = null) { if (data == null || Animator == null) return false; // 1. 打断并退场当前正在播放的动作,触发其打断事件与结束事件 if (currentRuntimeFuncAnim != null && !currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); } float oldClipLength = (currentRuntimeFuncAnim != null && currentClip != null) ? currentClip.length : 1f; // 2. 构建全新的运行时动作实例并装载动态事件 currentRuntimeFuncAnim = new RuntimeFuncAnim(data, Executor); currentRuntimeFuncAnim.ClearRuntimeEvents(); runtimeStartEvents?.ForEach(payload => currentRuntimeFuncAnim.AddStartEvent(payload)); FuncAnimInfo animInfo = currentData.animInfo; currentPlaySpeedMultiplier = speedMultiplier; // 3. 计算起始偏移并执行 Animator 融合过渡 float clipLength = currentClip != null ? currentClip.length : 1f; float frameRate = currentClip != null ? currentClip.frameRate : 30f; currentRuntimeFuncAnim.currentPlayTime = normalizedStartTime < 0f ? animInfo.overrideStartFrame / frameRate : normalizedStartTime; float normalizedTimeOffset = clipLength > 0f ? currentPlayTime / clipLength : 0f; float normalizedTransitionDuration = isNormalizedTransition ? transitionDuration : transitionDuration / oldClipLength; Animator.CrossFade(animInfo.stateName, normalizedTransitionDuration, Animator.GetLayerIndex(animatorLayerName), normalizedTimeOffset); // 4. 应用动作播放速度参数 try { float actionSpeed = animInfo.overridePlaySpeed * currentPlaySpeedMultiplier; Animator.SetFloat(ActionSpeed, actionSpeed); } catch { /* 忽略状态机中未配置 ActionSpeed 变量的情况 */ } // 5. 触发启动事件 currentRuntimeFuncAnim.InvokeStartEvents(); currentRuntimeFuncAnim.isDisrupted = false; return true; } /// /// 物理停止当前动画:触发退场事件并将状态机融合至 Empty 空白状态。 /// public virtual bool Stop(float transitionDuration = 0.1f) { if (currentRuntimeFuncAnim == null) return true; if (!currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); } float oldClipLength = currentClip != null ? currentClip.length : 1f; float normalizedTransitionDuration = transitionDuration / oldClipLength; Animator.CrossFade("Empty", normalizedTransitionDuration, Animator.GetLayerIndex(animatorLayerName)); currentRuntimeFuncAnim = null; return true; } /// /// 动作生命周期推进(时钟更新与循环/自然退场监测)。 /// public virtual void Update(float deltaTime) { if (currentRuntimeFuncAnim == null) { currentPlaySpeedMultiplier = 1f; return; } // 推进播放时间 float step = deltaTime * currentData.animInfo.overridePlaySpeed * currentPlaySpeedMultiplier; currentRuntimeFuncAnim.currentPlayTime += step; currentRuntimeFuncAnim.currentTotalPlayTime += step; float clipLength = currentClip != null ? currentClip.length : 0f; // 监测单次播放是否到头 if (currentPlayTime >= clipLength) { UpdateEvents(); if (currentClip != null && currentClip.isLooping) { // 循环动作:取模复位并重新触发 StartEvent currentRuntimeFuncAnim.currentPlayTime = clipLength > 0f ? currentRuntimeFuncAnim.currentPlayTime % clipLength : 0f; currentRuntimeFuncAnim.dataAnimEventIndex = 0; currentRuntimeFuncAnim.runtimeAnimEventIndex = 0; currentRuntimeFuncAnim.ResetUpdateUntilEventsStatus(); currentRuntimeFuncAnim.InvokeStartEvents(); } else { // 非循环动作:执行打断与结束退场事件,并注销运行时 if (!currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); } currentRuntimeFuncAnim = null; } } } /// /// 物理帧更新:驱动时间轴上已注册的时刻事件及持续事件。 /// public virtual void UpdateEvents() { RuntimeFuncAnim rt = currentRuntimeFuncAnim; if (rt == null) return; currentRuntimeFuncAnim.UpdateAnimEvent(); currentRuntimeFuncAnim.InvokeUpdateEvents(); currentRuntimeFuncAnim.InvokeUpdateUntilEvents(); } } }