骑士插图,UI调整
This commit is contained in:
358
Assets/OtherPlugins/AnimatorPlus/Core/AnimatorPlus.cs
Normal file
358
Assets/OtherPlugins/AnimatorPlus/Core/AnimatorPlus.cs
Normal 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和plabelable2,playble永远是当前播放的动画
|
||||
(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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1c679e4256c0db4d83c567a6d9161c5
|
||||
32
Assets/OtherPlugins/AnimatorPlus/Core/IAniamtorPlus.cs
Normal file
32
Assets/OtherPlugins/AnimatorPlus/Core/IAniamtorPlus.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cde0aa89a1076b24b8b1bb24b86df839
|
||||
40
Assets/OtherPlugins/AnimatorPlus/Core/PlableAniamtorUtils.cs
Normal file
40
Assets/OtherPlugins/AnimatorPlus/Core/PlableAniamtorUtils.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09d28a57314dc664eb348ec7d47c7f5e
|
||||
Reference in New Issue
Block a user