using System; using System.Collections.Generic; using System.Linq; using Continentis.MainGame.Character; using SLSFramework.General; using UniRx; using UnityEngine; using UnityEngine.Events; namespace Continentis.MainGame.Commands { public class Cmd_PlayAnimation : CommandBase { private readonly CombatCharacterViewBase characterView; private readonly Animator animator; private bool waitForFinish; private float overrideDuration; private string stateName; private int layer; //在动画的normalizedTime执行函数 private AnimationClip clip; private float clipScaledLength => clip.length / animator.speed; private Dictionary animationActions; public Cmd_PlayAnimation(CombatCharacterViewBase characterView, string stateName, bool waitForFinish = false, float overrideDuration = -1, int layer = 0) : base(null) { this.characterView = characterView; this.animator = characterView.animator; this.stateName = stateName; this.clip = characterView.animationClips[stateName]; this.waitForFinish = waitForFinish; this.overrideDuration = overrideDuration; this.layer = layer; this.animationActions = new Dictionary(); } public Cmd_PlayAnimation AddAction(float normalizedDuration, Action action) { animationActions[normalizedDuration] = action; return this; } public Cmd_PlayAnimation AddAction(int frame, Action action) { float normalizedDuration = frame / (clip.frameRate * clip.length); return AddAction(normalizedDuration, action); } public Cmd_PlayAnimation AddAction(float normalizedDuration, string selfContextKey, Action action) { T param = selfContext.GetInfo(selfContextKey); animationActions[normalizedDuration] = () => action(param); return this; } public Cmd_PlayAnimation AddAction(int frame, string selfContextKey, Action action) { float normalizedDuration = frame / (clip.frameRate * clip.length); return AddAction(normalizedDuration, selfContextKey, action); } protected override IObservable OnExecute(CommandContext outerContext) { if (animator == null) { Debug.LogWarning("Animator or stateName is null or empty."); return Observable.Return(Unit.Default); } if (!animator.HasState(layer, Animator.StringToHash(stateName))) { if (!animator.HasState(layer, Animator.StringToHash("Default"))) { Debug.LogWarning($"Animator does not have state: {stateName}, and Default state is also missing."); return Observable.Return(Unit.Default); } stateName = "Default"; // Fallback to Default state Debug.Log($"Animator does not have state: {stateName}. Falling back to Default state."); } animator.CrossFade(stateName, 0f, layer, 0f); //监听动画进度以执行函数,独立Observable if (animationActions.Count > 0) { Observable.EveryUpdate().TakeUntil(Observable.Timer(TimeSpan.FromSeconds(clipScaledLength))).Subscribe(_ => { float normalizedTime = animator.GetCurrentAnimatorStateInfo(layer).normalizedTime % 1f; foreach (var kvp in animationActions.ToList()) { if (normalizedTime >= kvp.Key) { kvp.Value?.Invoke(); animationActions.Remove(kvp.Key); //确保只执行一次 } } }); } if (waitForFinish) { float animationDuration = overrideDuration >= 0 ? overrideDuration : characterView.animationClips[stateName].length; return Observable.Timer(TimeSpan.FromSeconds(animationDuration)).AsUnitObservable(); } else { return Observable.Return(Unit.Default); } } } }