前言
前置知识:设置参数后,下一个循环才会切换对应动画,所以在下一个循环获取真实的动画长度
AnimatorStateInfo是结构体!值类型,要不断重复获取才是最新的
主要是自动设置trigger切换的动画自动切回上一个动画,需要在异步中等待动画结束
但是我用的连击动画为了好的手感将动画结束时间提前,这就导致进入这里的currentAm 可能是上一次的攻击动画
AnimatorStateInfo重要属性
normalizedTime
:动画播放进度,播放完则是1,每次循环+1,需要注意不循环的动画可能只到9.x就切换了shortNameHash
:状态名字 转换成的hash值length
:动画时长,单位秒IsName
: 将字符串转为hash进行判断
代码
直接放管理器
!!!注意除非是循环动画,否则normalizedTime 不会超过1
public class AnimationMgr : SingletonMonoGlobal<AnimationMgr>
{
//处理局部顿帧
public event Action<float> onLocalFrame;
//局部顿帧动画列表
/// <summary>
/// 组合用法 等待当前真实动画播放完毕
/// </summary>
/// <param name="animator"></param>
/// <param name="callback"></param>
public void AwaitCurrentAnimWhenDelay(Animator animator, Action callback = null)
{
AwaitAnim(animator, () =>
{
AwaitAnimDelay(animator, callback);
});
}
/// <summary>
/// 等待动画 严格等待 注意无法处理自循环的动画!只有一个动画用delay版本
/// </summary>
/// <param name="animator"></param>
/// <returns></returns>
public void AwaitAnim(Animator animator, Action callback = null)
{
AwaitAnimAsync(animator, callback).Forget();
}
public async UniTask AwaitAnimAsync(Animator animator, Action callback = null)
{
var animInfo = animator.GetCurrentAnimatorStateInfo(0);
var nameHash = animInfo.fullPathHash;
// 等待直到当前动画发生改变
await UniTask.WaitUntil(() =>
{
var info = animator.GetCurrentAnimatorStateInfo(0);
return nameHash != info.fullPathHash;
});
callback?.Invoke();
}
public void AwaitNextAnim(Animator animator, Action callback = null)
{
AwaitNextAnimAsync(animator, callback).Forget();
}
public async UniTask AwaitNextAnimAsync(Animator animator, Action callback = null)
{
await AwaitAnimAsync(animator);
await AwaitAnimAsync(animator, callback);
}
public void AwaitAnimDelay(Animator animator, Action callback = null)
{
AwaitAnimDelayAsync(animator, callback).Forget();
}
public async UniTask AwaitAnimDelayAsync(Animator animator, Action callback = null)
{
while (animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 0.95f || animator.IsInTransition(0))
{
// 在动画未结束或者在过渡中时继续等待
await UniTask.Yield();
}
callback?.Invoke();
}
}