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();
}
}
}