Unity 2D - 顺利停止循环动画

Unity 2D - Stop looping animation smoothly

所以,我有一个显示覆盖整个屏幕的动画的屏幕。

现在,我有 7 个循环动画,所有动画都在同一帧开始和结束以实现兼容性。但是,我怎样才能在按下按钮后等待每个动画完成,然后再播放下一个动画,这样看起来很流畅?

您可以为每个动画脚本添加一个自定义 variable.These 变量应该与您 want.When 每个动画结束的顺序完全匹配,为该变量分配一个自定义值并根据该变量启动下一个动画脚本您刚刚分配的值。

您需要整理的第一件事是动画控制器。这个动画控制器知道所有可以播放的必要动画。如果您不想,则不必将它们连接起来,因为它有 7 个动画,可以按任何顺序播放……这是很多链接。

为了使其正常工作,您的动画控制器需要代表每个转换的 bool 参数,因此当您从脚本中设置它们时,控制器将按预期的方向移动。要进行转换,当剪辑到达结尾时,将转换退出时间设置为 1。请记住,您仍然需要管理前端队列数据结构并在转换开始时重置布尔值,这将防止它到达下一个状态并立即转换到另一个状态。

相反,您可以为此编写自定义处理程序来设置当前播放的动画。按照这些思路应该可以解决问题:

class YourAnimController : MonoBehaviour
{
       private Queue<int> queuedStateHashes = new Queue<int>();

       private int currentStateHash;

       public string defaultState;
       private int defaultHash;

       public Animator theAnimator;

       private void Awake()
       {
           defaultHash = Animator.StringToHash(defaultState);
           StartCoroutine(PlayStates());
       }

       //how you start and exit this is up to you, in this case, 
       //I'll assume it starts on awake
       private IEnumerator PlayStates()
       {
            while(true)
            {          
                SetAnimStates();

                yield return null;
            }                              
       }

       private void SetAnimState()
       {
           AnimatorStateInfo info = theAnimator.GetCurrentAnimatorStateInfo(0);

           if(queuedStates.Count > 0)
           {
               if(info.normalizedTime >= 1)
               {
                   currentStateHash = queuedStateHashes.Dequeue();

                   theAnimator.Play(currentStateHash, 0, 0);                                                                       
               }
           }               
           else if(currentStateHash != defaultStateHash)
           {
               queuedStateHashes.Enqueue(defaultStateHash);                  
           }                     
       }

       private void Update()
       {
            if(Input.GetButtonDown("Your button1"))
            {
                 int stateHash = Animator.StringToHash("First state");
                 queuedStateHashes.Enqueue(stateHash);                                         
            }
            //repeat for all additional anims
       }

       //Any other methods
}

现在进行解释: 队列用于将状态排队播放,这允许它们以特定顺序播放,先到先得。

PlayStates 方法逻辑可以转换为 Update 方法。您将在输入检查之后执行此操作,并且您将删除 while 循环。我这样做是因为它可以让您更好地控制它何时以及如何停止和开始,而更新将不断评估。如果队列中没有任何状态,这种方法允许您关闭协程,如果您选择这样做的话。您面临挑战 :)。按下按钮时不要忘记重新启动它。

动画器状态信息抓取告诉我们当前在动画器控制器中播放什么。使用标准化时间是因为您需要知道动画进行了多远。归一化时间基本上是当前动画已播放的百分比。如果动画剪辑没有打开循环,在这种情况下,它会告诉您播放的百分比和次数。调试并亲自看看,如果你很好奇。

需要修改此方法以考虑循环,因此它只会在动画完成其循环后更改动画。您可能需要修改此位:

if(info.normalizedTime >= 1 && queuedStates.Count > 0)

让它工作,另一个挑战:)。

现在一些文件:

AnimatorStateInfo:https://docs.unity3d.com/ScriptReference/AnimatorStateInfo.html

队列: https://msdn.microsoft.com/en-us/library/7977ey2c(v=vs.110).aspx

动画师: https://docs.unity3d.com/ScriptReference/Animator.html

动画控制器方法,到处都有链接,使用了类似的想法,它可能更难实现,并且在设置控制器时更耗时,而上面概述的方法不需要转换,如果要相信文档: https://docs.unity3d.com/ScriptReference/Experimental.Director.IAnimatorControllerPlayable.html

希望这会引导您朝着正确的方向前进。

让我们试试 Animator.speed: https://docs.unity3d.com/ScriptReference/Animator-speed.html

您可以尝试 Mathf.Lerf(1f, 0f, 0.5f) 但我认为处理起来可能很复杂。 :D