0

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

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

4

3 回答 3

0

您可以为每个动画脚本添加一个自定义变量。这些变量应该与您想要的顺序完全匹配。当每个动画结束时,为该变量分配一个自定义值,并根据您刚刚分配的变量值启动下一个动画脚本。

于 2017-03-09T18:14:00.567 回答
0

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

为了让它工作,你的动画控制器需要代表每个转换的布尔参数,所以当你从脚本中设置它们时,控制器将朝着它应该的方向移动。要进行过渡,当剪辑到达结尾时,将过渡退出时间设置为 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

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

于 2017-03-10T01:26:38.847 回答
0

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

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

于 2017-03-10T04:11:28.780 回答