骑士插图,UI调整

This commit is contained in:
SoulliesOfficial
2025-12-03 09:22:57 -05:00
parent c65462e73b
commit a4c28b955f
317 changed files with 143921 additions and 4004 deletions

View File

@@ -0,0 +1,358 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace AnimatorPlus
{
[RequireComponent(typeof(Animator))]
public class AnimatorPlus:MonoBehaviour,IAnimatorPlus
{
private List<LayerInfo> Layers = new List<LayerInfo>{ new LayerInfo()
{
mask = null,
isAdditive = false,
maxWeight = 1.0f,
}};
private const bool EnableBlendSameAnim = true;
public bool IsRootMotion = true;
public Vector3 DeltaPosition { get; private set; }
public Quaternion DeltaRotation { get; private set; }
public Vector3 RootMotionVelocity { get; private set; }
public AnimClipPlayInfo animatorPlayableInfo = new AnimClipPlayInfo() { index = 0};
public Animator Animator
{
get
{
if (!animator)
animator = GetComponent<Animator>();
if(!animator)
Debug.LogError("Animator Component not found!");
return animator;
}
}
private Animator animator;
public bool IsPlaying => !isPaused && playableGraph.IsValid() &&playableGraph.IsPlaying();
public float AnimatorPlayWeight => Layers[0].playable.GetInputWeight(0);
public Action<Vector3, Quaternion> OnAnimationIK;
// private void OnValidate()
// {
// if(Layers.Length==0)
// Layers = new LayerInfo[1] ;
// Layers[0].name = "Base Layer";
// Layers[0].mask = null;
// Layers[0].isAdditive = false;
// Layers[0].maxWeight = 1;
//
// // if(Application.isPlaying)
// // InitializeGraph();
// }
// private Dictionary<AnimationClip,AnimClipPlayInfo> baseClipInfoDictionary;
// private Dictionary<AnimationClip,AnimClipPlayInfo> additiveClipInfoDictionary;
// private Dictionary<Tuple<AvatarMask,AnimationClip>,AnimClipPlayInfo> AvatarMaskClipInfoDictionary;
private bool isPaused = false;
private PlayableGraph playableGraph;
private AnimationLayerMixerPlayable finalLayerMixerPlayable;
private bool resetRootMotionDelta;
private void Start()
{
if(Layers.Count==0)
Layers.Add(new LayerInfo()) ;
Layers[0].mask = null;
Layers[0].isAdditive = false;
Layers[0].maxWeight = 1;
InitializeGraph();
}
private void OnDestroy()
{
playableGraph.Destroy();
}
private void InitializeGraph()
{
DeltaPosition = Vector3.zero;
DeltaRotation = Quaternion.identity;
playableGraph = PlayableGraph.Create(Animator.gameObject.name);
Animator.updateMode = AnimatorUpdateMode.UnscaledTime;
var playableOutput = AnimationPlayableOutput.Create(playableGraph, "AnimOutPut", Animator);
finalLayerMixerPlayable = AnimationLayerMixerPlayable.Create(playableGraph, 1);
playableOutput.SetSourcePlayable(finalLayerMixerPlayable);
//初始化Layer Playables
for (int i = 0; i < Layers.Count; i++)
{
var layer = Layers[i];
layer.index = i;
layer.currentAnimClipPlayInfo = new AnimClipPlayInfo();
layer.clipInfoDictionary = new Dictionary<AnimationClip, AnimClipPlayInfo>();
layer.playable = AnimationMixerPlayable.Create(playableGraph);
if (i == 0) //base layer 默认连接到Animator
{
var animatorPlayable = AnimatorControllerPlayable.Create(playableGraph, Animator.runtimeAnimatorController);
//Animator.runtimeAnimatorController = null; //解决StateMachineBehavior被重复clone的问题但是这段代码会导致runtimeAnimatorController引用丢失
layer.playable.SetInputCount(1);
playableGraph.Connect(animatorPlayable, 0, layer.playable, 0);
}
finalLayerMixerPlayable.SetInputCount(i+1);
playableGraph.Connect( layer.playable , 0, finalLayerMixerPlayable, i);
finalLayerMixerPlayable.SetInputWeight(i,layer.maxWeight);
finalLayerMixerPlayable.SetLayerAdditive((uint)i, layer.isAdditive);
if(layer.mask!=null)
finalLayerMixerPlayable.SetLayerMaskFromAvatarMask((uint)i, layer.mask);
}
playableGraph.Play();
}
public void PlayAnimator(float fadeTime)
{
animatorPlayableInfo.fadeInTime = fadeTime;
var baseLayer = Layers[0];
baseLayer.currentAnimClipPlayInfo = animatorPlayableInfo;
}
public void PlayAnimationClip(AnimationClip clip,float fadeInTime, float fadeOutTime,
AvatarMask mask = null, bool isAdditive = false, float maxWeight = 1.0f, bool resetAfterPlay = true)
{
#region layer
var layerIndex = -1;
foreach (var layer in Layers) //查找已有layer
{
if (layer.mask == mask && layer.isAdditive == isAdditive)
{
layerIndex = layer.index;
break;
}
}
if (layerIndex<0)//没有找到合适的layer创建新的layer
{
var newLayer = new LayerInfo()
{
mask = mask,
isAdditive = isAdditive,
maxWeight = maxWeight,
};
Layers.Add(newLayer);
Layers.Sort((a, b) => a.index.CompareTo(b.index));
newLayer.index = isAdditive?Layers.Count-1: 1; //IsAdditive层加在最后否则在BaseLayer之后
newLayer.currentAnimClipPlayInfo = new AnimClipPlayInfo();
newLayer.clipInfoDictionary = new Dictionary<AnimationClip, AnimClipPlayInfo>();
newLayer.playable = AnimationMixerPlayable.Create(playableGraph);
finalLayerMixerPlayable.SetInputCount(Layers.Count);
foreach (var layer in Layers)//整理layerIndex重新链接layer playables
{
if (layer.index >= newLayer.index)
{
if(layer!= newLayer)
layer.index++;
playableGraph.Disconnect(finalLayerMixerPlayable,layer.index);
playableGraph.Connect( layer.playable , 0, finalLayerMixerPlayable, layer.index);
}
}
finalLayerMixerPlayable.SetInputWeight(newLayer.index,newLayer.maxWeight);
finalLayerMixerPlayable.SetLayerAdditive((uint)newLayer.index, newLayer.isAdditive);
if(newLayer.mask!=null)
finalLayerMixerPlayable.SetLayerMaskFromAvatarMask((uint)newLayer.index, newLayer.mask);
layerIndex = newLayer.index;
}
var currentLayer = Layers[layerIndex];
#endregion
#region
//暂停住目标layer的当前动画
if(currentLayer.currentAnimClipPlayInfo.index!=0)
{
currentLayer.currentAnimClipPlayInfo.playable.Pause();//Freeze animation self between skill action
}
//通过clip获取clipInfo若不存在则创建
var clipInfoDictionary = currentLayer.clipInfoDictionary;
if (!clipInfoDictionary.TryGetValue(clip, out var info))
{
var clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
clipPlayable.SetDuration(clip.length);
info = new AnimClipPlayInfo
{
clip = clip,
index = currentLayer.playable.GetInputCount(),
fadeInTime = fadeInTime,
playLength = clip.length - fadeOutTime,
fadeOutTime = fadeOutTime,
resetAfterPlay = resetAfterPlay,
maxWeight = maxWeight,
playable = clipPlayable
};
clipInfoDictionary.Add(clip,info);
currentLayer.playable.SetInputCount(info.index + 1);
playableGraph.Connect(clipPlayable, 0, currentLayer.playable, info.index);
}
else
{
if (info.currentWeight!=0 && EnableBlendSameAnim)
{
if (!info.playable2.IsValid())
{
info.playable2 = AnimationClipPlayable.Create(playableGraph, clip);
info.playable2.SetDuration(clip.length);
info.index2 = currentLayer.playable.GetInputCount();
currentLayer.playable.SetInputCount(info.index2 + 1);
playableGraph.Connect(info.playable2, 0, currentLayer.playable, info.index2);
}
//交换playabe和plabelable2playble永远是当前播放的动画
(info.playable,info.playable2) = (info.playable2, info.playable);
(info.index,info.index2) = (info.index2, info.index);
info.currentWeight2 = info.currentWeight;
info.playable2.Pause();
info.playable.SetTime( info.playable2.GetTime());
info.playable.SetTime( info.playable2.GetTime());
}
else
{
info.fadeInTime = fadeInTime;
info.fadeOutTime = fadeOutTime;
info.maxWeight = maxWeight;
info.resetAfterPlay = resetAfterPlay;
}
}
info.currentWeight = 0;
currentLayer.currentAnimClipPlayInfo = info;
#endregion
//SetTime两次解决rootMotion拉回问题
//https://github.com/Unity-Technologies/SimpleAnimation/blob/master/Assets/SimpleAnimationComponent/CustomPlayableExtensions.cs
info.playable.SetTime(0);
info.playable.SetTime(0);
info.playable.SetDone(false);
info.playable.Play();
}
public void SetPause(bool value)
{
isPaused = value;
if (isPaused)
{
finalLayerMixerPlayable.Pause();
}
else
{
finalLayerMixerPlayable.Play();
}
}
private void OnAnimatorMove()
{
DeltaPosition = Vector3.zero;
DeltaRotation = Quaternion.identity;
RootMotionVelocity = Vector3.zero;
if (resetRootMotionDelta)
{
resetRootMotionDelta = false;
return;
}
if (IsRootMotion && !isPaused)
{
DeltaPosition = Animator.deltaPosition;
DeltaRotation = Animator.deltaRotation;
RootMotionVelocity = Animator.deltaPosition / Time.deltaTime;
}
}
private void OnAnimatorIK(int layerIndex)
{
OnAnimationIK?.Invoke(DeltaPosition,DeltaRotation);
}
private void Update()
{
if(isPaused)
return;
finalLayerMixerPlayable.SetSpeed(Time.timeScale);
foreach (var layer in Layers)
{
var currentClipPlayInfo = layer.currentAnimClipPlayInfo;
var weightSum = 0.0f;
foreach (var pair in layer.clipInfoDictionary)
{
var clipInfo = pair.Value;
var clipPlayable = clipInfo.playable;
//clipInfo.currentWeight = layer.playable.GetInputWeight(clipInfo.index);
var fadeSpeed = currentClipPlayInfo.index == clipInfo.index && clipPlayable.GetTime() < clipInfo.playLength
? Mathf.Clamp01(Time.deltaTime / clipInfo.fadeInTime)
: -Mathf.Clamp01(Time.deltaTime / clipInfo.fadeOutTime);
clipInfo.currentWeight = Mathf.Clamp( clipInfo.currentWeight + fadeSpeed,0,clipInfo.maxWeight);
weightSum += clipInfo.currentWeight;
if (EnableBlendSameAnim && clipInfo.index2 > 0)
{
clipInfo.currentWeight2 = Mathf.Max(clipInfo.currentWeight2 - Mathf.Clamp01(Time.deltaTime / clipInfo.fadeInTime), 0);
weightSum += clipInfo.currentWeight2;
}
}
if (layer.index == 0) //对于基础层如果当前动画播放完毕则播放Animator
{
layer.playable.SetInputWeight(0, Mathf.Clamp01(1-weightSum));
if (currentClipPlayInfo.resetAfterPlay && currentClipPlayInfo.index != 0 &&
currentClipPlayInfo.playable.GetTime() >= currentClipPlayInfo.playLength)
{
PlayAnimator(Mathf.Max(currentClipPlayInfo.fadeOutTime, 0.1f));
}
}
if (layer.index == 0)
{
weightSum += layer.playable.GetInputWeight(0);
}
foreach (var pair in layer.clipInfoDictionary)
{
var clipInfo = pair.Value;
clipInfo.currentWeight = weightSum > 1.0f ? clipInfo.currentWeight/weightSum : clipInfo.currentWeight;
layer.playable.SetInputWeight(clipInfo.index, clipInfo.currentWeight);
if (clipInfo.index2 > 0)
{
layer.playable.SetInputWeight(clipInfo.index2, clipInfo.currentWeight2);
}
}
finalLayerMixerPlayable.SetInputWeight(layer.index,weightSum);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f1c679e4256c0db4d83c567a6d9161c5

View File

@@ -0,0 +1,32 @@
using UnityEngine;
namespace AnimatorPlus
{
public interface IAnimatorPlus
{
public Animator Animator { get; }
public Vector3 DeltaPosition { get; }
public Quaternion DeltaRotation { get; }
public Vector3 RootMotionVelocity { get; }
public bool IsPlaying { get; }
public float AnimatorPlayWeight { get; }
public void SetPause(bool value);
public void PlayAnimator(float fadeTime);
public void PlayAnimationClip(
AnimationClip clip,
float fadeInTime,
float fadeOutTime,
AvatarMask mask = null,
bool isAdditive = false,
float maxWeight = 1.0f,
bool resetAfterPlay = true);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cde0aa89a1076b24b8b1bb24b86df839

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace AnimatorPlus
{
public class AnimClipPlayInfo
{
public int index;
public Playable playable;
public AnimationClip clip;
public float fadeInTime;
public float playLength;
public float fadeOutTime;
public bool resetAfterPlay;
public float maxWeight;
public float currentWeight;
//Use to cross fade between the same clip
public int index2 = -1;
public Playable playable2;
public float currentWeight2;
}
[Serializable]
public class LayerInfo
{
public AvatarMask mask = null;
public bool isAdditive = false;
[Range(0, 1)] public float maxWeight = 1.0f;
public int index { get; set; }
public AnimationMixerPlayable playable { get; set; }
public AnimClipPlayInfo currentAnimClipPlayInfo { get; set; }
public Dictionary<AnimationClip, AnimClipPlayInfo> clipInfoDictionary { get; set; }
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 09d28a57314dc664eb348ec7d47c7f5e