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 animationName; private int layer; //在动画的normalizedTime执行函数 private AnimationClip clip; private float clipScaledLength => clip.length / animator.speed; private Dictionary animationActions; public Cmd_PlayAnimation(CombatCharacterViewBase characterView, string animationName, bool waitForFinish = true, float overrideDuration = -1, int layer = 0) : base(null) { this.characterView = characterView; this.animator = characterView.animator; this.animationName = animationName; this.clip = null; characterView.animations.TryGetValue(animationName, out clip); 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 || clip == null || string.IsNullOrEmpty(animationName)) { Debug.LogWarning("Animator or stateName is null or empty."); return Observable.Return(Unit.Default); } string finalAnimationName = animationName; if (!characterView.animations.ContainsKey(animationName)) { finalAnimationName = "Action"; } if (characterView.animations.TryGetValue(finalAnimationName, out clip)) { characterView.animatorPlus2D.Play(clip); } else { Debug.LogWarning($"Animation clip not found for state: {finalAnimationName}"); return Observable.Return(Unit.Default); } //监听动画进度以执行函数,独立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 / animator.speed : clipScaledLength; return Observable.Timer(TimeSpan.FromSeconds(animationDuration)).AsUnitObservable(); } else { return Observable.Return(Unit.Default); } } } }