Files
Cielonos/Assets/Scripts/MainGame/Characters/Base/Submodules/FunctionalAnimationSubmodule.cs
SoulliesOfficial d15957c719 更新
2025-12-17 04:19:38 -05:00

269 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
using Sirenix.OdinInspector;
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;
[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<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)
{
if (currentRuntimeFuncAnim == null || disruptionType == DisruptionType.Death)
{
return true;
}
if (disruptionType == DisruptionType.ForcedAction || disruptionType == DisruptionType.ForcedExternal)
{
if (character.statusSm.isDead || character.statusSm.HasStatus(StatusType.Incapacitation))
{
return false;
}
return true;
}
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 or DisruptionType.ForcedAction or DisruptionType.ForcedExternal => true,
_ => animationSc.disruptionStatus[disruptionType]
};
}
/// <summary>
/// 通过动画名称播放动画
/// </summary>
/// <param name="animationName">动画名称详见FuncAnimData</param>
/// <param name="animationSpeedMultiplier">播放速度倍率</param>
/// <param name="transitionDuration">过渡时间</param>
/// <param name="isNormalizedTransition">过渡时间是否归一化</param>
/// <param name="runtimeStartEvents">运行时开始事件列表</param>
/// <returns></returns>
public bool Play(string animationName, float animationSpeedMultiplier = 1, float transitionDuration = 0.1f,
bool isNormalizedTransition = false, List<FuncAnimPayloadBase> 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(newRtFuncAnim.funcAnimData.animInfo.disruptionType))
{
Debug.LogWarning($"[FunctionalAnimationSubmodule] Cannot play animation '{animationName}' due to playability check failure." +
$"CurrentAnimation={currentRuntimeFuncAnim?.funcAnimData.animInfo.animationName ?? "None"} " +
$"NewRtFuncAnim: disruptionType={newRtFuncAnim.funcAnimData.animInfo.disruptionType}" +
$"IsDuringDisruption={animationSc.disruptionStatus[newRtFuncAnim.funcAnimData.animInfo.disruptionType]}");
return false;
}
if (currentRuntimeFuncAnim != null && !currentRuntimeFuncAnim.isDisrupted)
{
currentRuntimeFuncAnim.isDisrupted = true;
currentRuntimeFuncAnim.InvokeDisruptionEvents();
currentRuntimeFuncAnim.InvokeEndEvents();
ResetPlayerPreinput();
}
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 / currentClip.length;
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;
}
/// <summary>
/// 停止当前动画
/// </summary>
/// <param name="disruptionType">打断类型</param>
/// <param name="transitionDuration">过渡时间</param>
/// <returns>是否停止成功</returns>
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)
{
if (!CheckDisruption(disruptionType))
{
return false;
}
}
if (!currentRuntimeFuncAnim.isDisrupted)
{
currentRuntimeFuncAnim.isDisrupted = true;
currentRuntimeFuncAnim.InvokeDisruptionEvents();
currentRuntimeFuncAnim.InvokeEndEvents();
ResetPlayerPreinput();
}
float normalizedTransitionDuration = transitionDuration / currentClip.length;
animator.CrossFade("Empty", normalizedTransitionDuration, animator.GetLayerIndex(animatorLayerName));
animationSc.disruptionStatus[DisruptionType.NormalExternal] = false;
animationSc.disruptionStatus[DisruptionType.NormalAction] = false;
animationSc.disruptionStatus[DisruptionType.Movement] = false;
currentRuntimeFuncAnim = null;
Debug.Log("[FunctionalAnimationSubmodule] Animation stopped successfully.");
return true;
}
public void UpdateTime()
{
if (currentRuntimeFuncAnim == null)
{
return;
}
currentRuntimeFuncAnim.currentPlayTime += owner.owner.selfTimeSm.DeltaTime * currentData.animInfo.overridePlaySpeed * currentPlaySpeedMultiplier;
if (currentPlayTime >= currentClip.length)
{
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();
}
}