using System; using System.Collections.Generic; using System.Linq; using Cielonos.MainGame.Characters; using Sirenix.OdinInspector; using SLSUtilities.FunctionalAnimation; using UnityEngine; namespace Cielonos.MainGame { public partial class FunctionalAnimationSubmodule : SubmoduleBase { private AnimationSubcontrollerBase animationSc => owner; private CharacterBase character => owner.owner; private Animator animator => owner.animator; private Player player => character as Player; public string animatorLayerName; public Dictionary collection; public RuntimeFuncAnim currentRuntimeFuncAnim; public FuncAnimData currentData => currentRuntimeFuncAnim.funcAnimData; public AnimationClip currentClip => currentData.animationClip; public float currentPlaySpeedMultiplier = 1f; [ShowInInspector] public float currentPlayTime => currentRuntimeFuncAnim?.currentPlayTime ?? 0f; public float currentNormalizedPlayTime => Mathf.Min(1, currentPlayTime / currentClip.length); [ShowInInspector] public float currentFrame => currentRuntimeFuncAnim?.currentPlayTime * currentRuntimeFuncAnim?.funcAnimData.animationClip.frameRate ?? 0f; public float currentScaledClipLength => currentClip.length / currentPlaySpeedMultiplier; public FunctionalAnimationSubmodule(AnimationSubcontrollerBase owner, string animatorLayerName) : base(owner) { this.animatorLayerName = animatorLayerName; collection = new Dictionary(); } public void ReSet(FuncAnimData animation) { if (animation == null) return; Remove(animation.animInfo.animationName); Add(animation); } public void Add(FuncAnimData animation) { collection[animation.animInfo.animationName] = animation; if (character is Player player) { player.animationSc.animatorOverride[animation.animInfo.stateName] = animation.animationClip; } } public void Remove(string animationName) { if (collection.ContainsKey(animationName)) { collection.Remove(animationName); } } } public partial class FunctionalAnimationSubmodule { private static readonly int ActionSpeed = Animator.StringToHash("ActionSpeed"); public bool CheckPlayability(RuntimeFuncAnim oldFuncAnim, RuntimeFuncAnim newFuncAnim) { if (oldFuncAnim != null) { var oldData = oldFuncAnim.funcAnimData; var newData = newFuncAnim.funcAnimData; FuncAnimInterval specifiedInterval = oldData.intervals.FirstOrDefault(interval => interval.intervalType == IntervalType.Custom && interval.intervalName == "SpecifiedActionDisruption"); if (specifiedInterval != null) { if (oldData.interactions.TryGetValue("SpecifiedActionDisruption", out List interactions)) { if (interactions.Contains(newData.animInfo.animationName)) { return animationSc.currentIntervals.Any(interval => interval == specifiedInterval); } } } } return CheckPlayability(newFuncAnim.funcAnimData.animInfo.disruptionType); } public bool CheckPlayability(DisruptionType disruptionType = DisruptionType.NormalAction) { if (character.statusSm.isDead) { return false; } if (currentRuntimeFuncAnim == null || disruptionType == DisruptionType.Death || disruptionType == DisruptionType.Must) { return true; } if (disruptionType == DisruptionType.ForcedAction) { return animationSc.disruptionStatus[DisruptionType.ForcedAction] || animationSc.disruptionStatus[DisruptionType.NormalAction] || animationSc.disruptionStatus[DisruptionType.Movement]; } if (disruptionType == DisruptionType.NormalAction) { return animationSc.disruptionStatus[DisruptionType.NormalAction] || animationSc.disruptionStatus[DisruptionType.Movement]; } if (disruptionType == DisruptionType.Movement) { return animationSc.disruptionStatus[DisruptionType.Movement]; } throw new Exception("Invalid DisruptionType for checking playability."); } public bool CheckDisruption(DisruptionType disruptionType) { return disruptionType switch { DisruptionType.None => false, DisruptionType.Must or DisruptionType.Death => true, _ => animationSc.disruptionStatus[disruptionType] }; } /// /// 通过动画名称播放动画 /// /// 动画名称,详见FuncAnimData /// 播放速度倍率 /// 过渡时间 /// 过渡时间是否归一化 /// 运行时开始事件列表 /// public bool Play(string animationName, float animationSpeedMultiplier = 1, float transitionDuration = 0.1f, bool isNormalizedTransition = false, List runtimeStartEvents = null) { if (!collection.TryGetValue(animationName, out FuncAnimData funcAnimData)) { Debug.LogWarning($"[FunctionalAnimationSubmodule] Animation '{animationName}' not found in collection."); return false; } var newRtFuncAnim = new RuntimeFuncAnim(funcAnimData, character); if (!CheckPlayability(currentRuntimeFuncAnim, newRtFuncAnim)) { return false; } if (currentRuntimeFuncAnim != null && !currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); ResetPlayerPreinput(); } float oldClipLength = currentRuntimeFuncAnim != null ? currentClip.length : 1f; currentRuntimeFuncAnim = newRtFuncAnim; currentRuntimeFuncAnim.ClearRuntimeEvents(); runtimeStartEvents?.ForEach(payload => currentRuntimeFuncAnim.AddStartEvent(payload)); FuncAnimInfo animInfo = currentData.animInfo; currentPlaySpeedMultiplier = animInfo.isAffectedBySpeedMultiplier ? animationSpeedMultiplier : 1; animationSc.isDisablingMoveXZ = false; animationSc.isDisablingMoveY = false; currentRuntimeFuncAnim.currentPlayTime = animInfo.overrideStartFrame / currentClip.frameRate; float normalizedTimeOffset = currentPlayTime / currentClip.length; float normalizedTransitionDuration = isNormalizedTransition ? transitionDuration : transitionDuration / oldClipLength; animator.CrossFade(animInfo.stateName, normalizedTransitionDuration, animator.GetLayerIndex(animatorLayerName), normalizedTimeOffset); float actionSpeed = animInfo.overridePlaySpeed * currentPlaySpeedMultiplier; animator.SetFloat(ActionSpeed, actionSpeed); currentRuntimeFuncAnim.InvokeStartEvents(); currentRuntimeFuncAnim.isDisrupted = false; currentRuntimeFuncAnim.dataAnimEventIndex = 0; currentRuntimeFuncAnim.runtimeAnimEventIndex = 0; currentRuntimeFuncAnim.SetUpdateUntilEventsStatus(); return true; } /// /// 停止指定名称的动画,默认为强制停止 /// public bool Stop(string animationName, DisruptionType disruptionType = DisruptionType.Must, float transitionDuration = 0.1f) { if (currentRuntimeFuncAnim == null) return true; if (currentRuntimeFuncAnim.funcAnimData.animInfo.animationName != animationName) return false; return Stop(disruptionType, transitionDuration); } /// /// 停止当前动画 /// /// 打断类型 /// 过渡时间 /// 是否停止成功 public bool Stop(DisruptionType disruptionType, float transitionDuration = 0.1f) { //Debug.Log($"[FunctionalAnimationSubmodule] Attempting to stop animation due to disruption type: {disruptionType}"); if(disruptionType == DisruptionType.None) return false; if(currentRuntimeFuncAnim == null) return true; if (disruptionType != DisruptionType.Death && disruptionType != DisruptionType.Must) { if (!CheckDisruption(disruptionType)) { return false; } } if (!currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); ResetPlayerPreinput(); } float oldClipLength = currentRuntimeFuncAnim != null ? currentClip.length : 1f; float normalizedTransitionDuration = transitionDuration / oldClipLength; animator.CrossFade("Empty", normalizedTransitionDuration, animator.GetLayerIndex(animatorLayerName)); animationSc.disruptionStatus[DisruptionType.NormalExternal] = false; animationSc.disruptionStatus[DisruptionType.NormalAction] = false; animationSc.disruptionStatus[DisruptionType.Movement] = false; currentRuntimeFuncAnim = null; return true; } public void UpdateTime() { if (currentRuntimeFuncAnim == null) { return; } currentRuntimeFuncAnim.currentPlayTime += owner.owner.selfTimeSm.DeltaTime * currentData.animInfo.overridePlaySpeed * currentPlaySpeedMultiplier; if (currentPlayTime >= currentClip.length) { UpdateEvents(); if (currentClip.isLooping) { currentRuntimeFuncAnim.currentPlayTime %= currentClip.length; currentRuntimeFuncAnim.dataAnimEventIndex = 0; currentRuntimeFuncAnim.runtimeAnimEventIndex = 0; currentRuntimeFuncAnim.ResetUpdateUntilEventsStatus(); currentRuntimeFuncAnim.InvokeStartEvents(); } else { if (!currentRuntimeFuncAnim.isDisrupted) { currentRuntimeFuncAnim.isDisrupted = true; currentRuntimeFuncAnim.InvokeDisruptionEvents(); currentRuntimeFuncAnim.InvokeEndEvents(); ResetPlayerPreinput(); } animationSc.disruptionStatus[DisruptionType.NormalExternal] = false; animationSc.disruptionStatus[DisruptionType.NormalAction] = false; animationSc.disruptionStatus[DisruptionType.Movement] = false; currentRuntimeFuncAnim = null; } } } public void UpdateEvents() { if (currentRuntimeFuncAnim == null) { return; } currentRuntimeFuncAnim.UpdateAnimEvent(); currentRuntimeFuncAnim.InvokeUpdateEvents(); currentRuntimeFuncAnim.InvokeUpdateUntilEvents(); } private void ResetPlayerPreinput() => player?.inputSc.preinputSubmodule.Reset(); } }