最初的想法是希望能够完全不改变美工的工作流程,通过代码解决所有问题。但是以笔者目前的认知水平还不行,还得麻烦一下美工,郁闷。
本来以为Animator.speed这个值设置为负数就可以倒播动画了,但是实际上设置为小于0的数和0没有区别,就是等同于暂停而已。
那么剩下就是改AnimatorState的speed了。本来以为只要获取到当前的AnimatorState就好办了,但是发现这是不可能的!你只能通过GetCurrentAnimatorStateInfo获取到当前的AnimatorStateInfo,而AnimatorStateInfo的speed值是只读的,国内国外搜了好几圈,没找到能在运行时获取AnimatorState的办法。
那就只能麻烦美工了,如图:
默认的AnimatorState是moveUpDown,复制这个AnimatorState,改名叫moveUpDown-1,Speed改成-1,这样虽然两个AnimatorState引用的是一个AnimatorClip,但是一个可以正向播放,一个可以反向播放。
不过还有问题,如果使用Animator.Play(string stateName)这个重载去播放的话,每次都是重头播放,这样假如用户正向播放动画的时候,如果在动画没有播放到结尾就选择倒播,我们会发现动画不是在当前状态开始倒播,而是从结尾往回倒播,这样就会产生跳跃感。解决的办法就是,先获取当前动画已经正向播放了的归一化时间,就是Animator.normalizedTime,用1-Animator.normalizedTime这个时间作为开始反向播放的其实时间就好了,代码上用的是Animator.Play(string stateName,int layer,float normalizedTime)这个重载。反向播放改正向播放道理一样。
代码示例如下:
using UnityEngine;
public class AnimOnOff : MonoBehaviour
{
[SerializeField]
[Header("可暂停动画")]
Animator[] anims;
public void Play(float playSpeed)
{
bool enabled = !Mathf.Approximately(playSpeed, 0);
if (anims != null)
{
foreach (Animator anim in anims)
{
if (!anim) continue;
//
anim.enabled = enabled;
if (anim.enabled)
{
AnimatorClipInfo clipInfo = anim.GetCurrentAnimatorClipInfo(0)[0];
AnimationClip clip = clipInfo.clip;
if (!clip)
{
Debug.Log("ULog:animator clip is null.");
continue;
}
string clipName = clip.name;
if (clipName.Contains("-1"))
{
if (playSpeed > 0)
{
clipName = clipName.Replace("-1", "");
}
}
else
{
if (playSpeed < 0)
{
clipName += "-1";
}
}
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
float startPlayTime = stateInfo.normalizedTime;
if (!stateInfo.IsName(clipName))
startPlayTime = 1 - startPlayTime;
anim.speed = Mathf.Abs(playSpeed);
anim.Play(clipName, 0, startPlayTime);
}
}
}
}
}
playSpeed形参获取的值如果是0,那么动画就停止了,如果是正数就正播,负数就倒播,绝对值的大小会影响播放速度。