【问题标题】:Unity Animator.Play how to transition to another animation at the same timeUnity Animator.Play 如何同时过渡到另一个动画
【发布时间】:2019-02-04 01:39:01
【问题描述】:

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

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

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

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

if (shooting) {animator.Play("PlayerRunningShoot");}

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

如果其中任何内容对我的要求感到困惑,请告诉我。

【问题讨论】:

    标签: unity3d animation


    【解决方案1】:

    看起来实际使用Animation Layers 对你来说会更有趣!我无法在此处重新创建完整的手册 - 查看文档和 this tutorial


    但是,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);
    }
    

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

    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);
    }
    

    【讨论】:

    • 我测试了它,但我不断收到错误。无论如何感谢您的回答。
    • 我只在智能手机上,所以很遗憾我无法测试它......你到底在哪里得到错误,什么样的错误?
    • Assets/scripts/PlayerController.cs(73,60):错误 CS1061:类型 UnityEngine.AnimatorClipInfo[]' does not contain a definition for length' 并且找不到扩展方法 length' of type UnityEngine.AnimatorClipInfo[]'。您是否缺少程序集参考? AND Assets/scripts/PlayerController.cs(74,69): error CS1061: Type UnityEngine.AnimationClip[]' does not contain a definition for FirstOrDefault' and no extension method FirstOrDefault' of type UnityEngine.AnimationClip[]'可以找到。您是否缺少使用指令的 `System.Linq'? 仅 2 个,但 comnt spce lmted。
    • 是的,很抱歉,它必须是 clipInfo[0].clip.length ...第二个,因为它在错误中说您需要将 using System.Linq; 添加到脚本顶部。但是你真的应该看看 AnimationLayers,它会立即解决你的问题
    • 我认为你应该等到你能够测试它,因为我有大约八个不同的错误。感谢您的尝试!
    猜你喜欢
    • 2022-09-26
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    相关资源
    最近更新 更多