Files
Cielonos/Assets/Scripts/MainGame/Characters/Base/Submodules/FunctionalAnimationSubmodule.cs

278 lines
12 KiB
C#
Raw Normal View History

2025-11-25 08:19:33 -05:00
using System;
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
2025-12-17 04:19:38 -05:00
using Sirenix.OdinInspector;
2025-11-25 08:19:33 -05:00
using SLSUtilities.FunctionalAnimation;
using UnityEngine;
namespace Cielonos.MainGame
{
public partial class FunctionalAnimationSubmodule : SubmoduleBase<AnimationSubcontrollerBase>
{
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<string, FuncAnimData> collection;
public RuntimeFuncAnim currentRuntimeFuncAnim;
public FuncAnimData currentData => currentRuntimeFuncAnim.funcAnimData;
public AnimationClip currentClip => currentData.animationClip;
public float currentPlaySpeedMultiplier = 1f;
2025-12-17 04:19:38 -05:00
[ShowInInspector]
public float currentPlayTime => currentRuntimeFuncAnim?.currentPlayTime ?? 0f;
2025-11-25 08:19:33 -05:00
public float currentNormalizedPlayTime => Mathf.Min(1, currentPlayTime / currentClip.length);
2025-12-17 04:19:38 -05:00
[ShowInInspector]
public float currentFrame => currentRuntimeFuncAnim?.currentPlayTime * currentRuntimeFuncAnim?.funcAnimData.animationClip.frameRate ?? 0f;
2025-11-25 08:19:33 -05:00
public float currentScaledClipLength => currentClip.length / currentPlaySpeedMultiplier;
public FunctionalAnimationSubmodule(AnimationSubcontrollerBase owner, string animatorLayerName) : base(owner)
{
this.animatorLayerName = animatorLayerName;
collection = new Dictionary<string, FuncAnimData>();
}
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(DisruptionType disruptionType = DisruptionType.NormalAction)
{
2026-01-03 18:19:39 -05:00
if (character.statusSm.isDead)
2025-11-25 08:19:33 -05:00
{
2026-01-03 18:19:39 -05:00
return false;
2025-11-25 08:19:33 -05:00
}
2026-01-03 18:19:39 -05:00
if (currentRuntimeFuncAnim == null || disruptionType == DisruptionType.Death || disruptionType == DisruptionType.Must)
2025-12-08 05:27:53 -05:00
{
return true;
}
2025-11-25 08:19:33 -05:00
2026-01-03 18:19:39 -05:00
if (disruptionType == DisruptionType.ForcedAction)
{
return animationSc.disruptionStatus[DisruptionType.ForcedAction] ||
animationSc.disruptionStatus[DisruptionType.NormalAction] ||
animationSc.disruptionStatus[DisruptionType.Movement];
}
2025-11-25 08:19:33 -05:00
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,
2026-01-03 18:19:39 -05:00
DisruptionType.Must or DisruptionType.Death => true,
2025-11-25 08:19:33 -05:00
_ => animationSc.disruptionStatus[disruptionType]
};
}
/// <summary>
/// 通过动画名称播放动画
/// </summary>
/// <param name="animationName">动画名称详见FuncAnimData</param>
/// <param name="animationSpeedMultiplier">播放速度倍率</param>
/// <param name="transitionDuration">过渡时间</param>
2025-12-08 05:27:53 -05:00
/// <param name="isNormalizedTransition">过渡时间是否归一化</param>
2025-11-25 08:19:33 -05:00
/// <param name="runtimeStartEvents">运行时开始事件列表</param>
/// <returns></returns>
public bool Play(string animationName, float animationSpeedMultiplier = 1, float transitionDuration = 0.1f,
2025-12-08 05:27:53 -05:00
bool isNormalizedTransition = false, List<FuncAnimPayloadBase> runtimeStartEvents = null)
2025-11-25 08:19:33 -05:00
{
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(newRtFuncAnim.funcAnimData.animInfo.disruptionType))
{
return false;
}
if (currentRuntimeFuncAnim != null && !currentRuntimeFuncAnim.isDisrupted)
{
currentRuntimeFuncAnim.isDisrupted = true;
currentRuntimeFuncAnim.InvokeDisruptionEvents();
currentRuntimeFuncAnim.InvokeEndEvents();
ResetPlayerPreinput();
}
2026-01-03 18:19:39 -05:00
float oldClipLength = currentRuntimeFuncAnim != null ? currentClip.length : 1f;
2025-11-25 08:19:33 -05:00
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;
2026-01-03 18:19:39 -05:00
float normalizedTransitionDuration = isNormalizedTransition ? transitionDuration : transitionDuration / oldClipLength;
2025-11-25 08:19:33 -05:00
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;
}
2026-01-03 18:19:39 -05:00
/// <summary>
/// 停止指定名称的动画,默认为强制停止
/// </summary>
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);
}
2025-11-25 08:19:33 -05:00
/// <summary>
/// 停止当前动画
/// </summary>
/// <param name="disruptionType">打断类型</param>
/// <param name="transitionDuration">过渡时间</param>
/// <returns>是否停止成功</returns>
public bool Stop(DisruptionType disruptionType, float transitionDuration = 0.1f)
{
2025-12-08 05:27:53 -05:00
//Debug.Log($"[FunctionalAnimationSubmodule] Attempting to stop animation due to disruption type: {disruptionType}");
2025-11-25 08:19:33 -05:00
if(disruptionType == DisruptionType.None) return false;
if(currentRuntimeFuncAnim == null) return true;
2026-01-03 18:19:39 -05:00
if (disruptionType != DisruptionType.Death && disruptionType != DisruptionType.Must)
2025-11-25 08:19:33 -05:00
{
if (!CheckDisruption(disruptionType))
{
return false;
}
}
if (!currentRuntimeFuncAnim.isDisrupted)
{
currentRuntimeFuncAnim.isDisrupted = true;
currentRuntimeFuncAnim.InvokeDisruptionEvents();
currentRuntimeFuncAnim.InvokeEndEvents();
ResetPlayerPreinput();
}
2026-01-03 18:19:39 -05:00
float oldClipLength = currentRuntimeFuncAnim != null ? currentClip.length : 1f;
float normalizedTransitionDuration = transitionDuration / oldClipLength;
2025-11-25 08:19:33 -05:00
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;
}
2025-12-17 04:19:38 -05:00
currentRuntimeFuncAnim.currentPlayTime += owner.owner.selfTimeSm.DeltaTime * currentData.animInfo.overridePlaySpeed * currentPlaySpeedMultiplier;
2025-11-25 08:19:33 -05:00
if (currentPlayTime >= currentClip.length)
{
2026-01-03 18:19:39 -05:00
UpdateEvents();
2025-11-25 08:19:33 -05:00
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();
}
}