Unity Animator.Play如何同时过渡到另一个动画

1 animation unity-game-engine

我目前有一个基于精灵的动画,其中播放器正在运行。我还有另一个动画,其中玩家奔跑并举起枪射击,其播放速度与玩家不带枪奔跑的速度完全相同。问题是,我正在使用 Animator.Play();

我想要的是在玩家运行动画当前所在的帧开始播放枪动画。例如,如果玩家奔跑动画位于第 20 帧,并且玩家按下射击按钮,则在第 20 帧播放持枪奔跑动画。

这是到目前为止我的代码的一个粗略示例:

if (!shooting) {animator.Play("PlayerRunning");}

if (shooting) {animator.Play("PlayerRunningShoot");}
Run Code Online (Sandbox Code Playgroud)

我认为最好的例子是 NES 洛克人游戏的洛克人射击动画之一,当你在跑步时按“B”时,他的手臂会立即弹出来射击。

如果这些内容对我的要求有任何困惑,请告诉我。

der*_*ugo 5

看起来实际使用动画层对您来说会更有趣!我无法在这里重新创建完整的手册 - 请查看文档和本教程


但是,Animator.Play 有一个可选参数

NormalizedTime:零和一之间的时间偏移。

这样您就可以使用当前动画所在的偏移量来启动新动画

您可以使用Animator.GetCurrentAnimatorStateInfo来获取当前状态和normalizedTime当前剪辑位于

Animator.GetCurrentAnimatorClipInfo获取剪辑的信息(例如长度)。

要么引用您的目标剪辑(我更喜欢这样),要么您可以使用Animator.runtimeAnimatorController来获取所有AnimationClips ,而不是使用LinQ FirstOrDefault来查找具有目标名称的剪辑:

(在我的智能手机上输入此内容,因此不提供任何保证)

using System.Linq;

// ...

if (!shooting)
{
    // assuming layer 0
    var state = animator.GetCurrentAnimatorStateInfo(0);
    var clipInfo = animator.GetCurrentAnimatorClipInfo(0);

    // so the time you want to start is currentNormalizedTime * current.length / newClip.length
    // if your clips will always have the exact same length of course you can
    // simply use the currentNormalizedTime
    var currentNormalizedTime = state.normalizedTime;
    var currentRealtime = currentNormalizedTime * clipInfo[0].clip.length;

    var newClip = animator.runtimeAnimatorController.animationClips.FirstOrDefault(c => string.Equals(c.name, "PlayerRunning"));

    var newNormalizedTime = currentRealtime / newClip.length;

    // for some reason it seems you can not use the optional parameters as you usually would
    // like ("PlayerRunningShoot", normaizedTime = newNormalizedTime)
    animator.Play("PlayerRunning", -1, newNormalizedTime);
}

if (shooting)
{
    var state = animator.GetCurrentAnimatorStateInfo(0);
    var clipInfo = animator.GetCurrentAnimatorClipInfo(0);
    var currentNormalizedTime = state.normalizedTime;
    var currentRealtime = currentNormalizedTime * clipInfo[0].clip.length;

    var newClip = animator.runtimeAnimatorController.animationClips.FirstOrDefault(c => string.Equals(c.name, "PlayerRunning"));

    var newNormalizedTime = currentRealtime / newClip.length;

    animator.Play("PlayerRunningShoot", -1, newNormalizedTime);
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用以下命令在运行时创建平滑过渡

Animator.CrossFadeAnimator.CrossFadeInFixedTime

if (!shooting) 
{
    // ...       

    // here the transition takes 0.25 % of the clip
    animator.CrossFade("PlayerRunning", 0.25f, -1, 0, newNormalizedTime);
}

if (shooting) 
{
    // ...

    // here the transition takes 0.25 seconds
    animator.CrossFadeInFixedTime("PlayerRunningShoot", 0.25f, -1, 0, newNormalizedTime);
}
Run Code Online (Sandbox Code Playgroud)