2017-03-09 263 views
0

所以,我有一个屏幕显示覆盖整个屏幕的动画。Unity 2D - 平滑停止循环动画

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

+0

你能发表一些代码吗? – LaneL

+0

对不起,这里还没有代码,因为我还没有想出一个好方法。动画事件看起来不错,但也有点过分 – uncanny

回答

0

你需要首先解决的是动画控制器。该动画制作者控制器知道可以播放的所有必要动画。如果你不想要,你不需要连接任何东西,因为它代表了可以以任何顺序播放的7个动画...这是很多链接。

为了让它工作,您的动画师控制器需要代表每个转换的bool参数,因此,当您通过脚本设置它们时,控制器将按照它应有的方向移动。为了进行转换,当剪辑到达结尾时,将转换退出时间设置为1.请记住,在转换开始时,您仍然需要管理前端队列数据结构并重置bools,阻止它到达下一个状态并立即转换到另一个状态。

相反,您可以为此设置自定义处理程序,它将设置当前正在播放的动画。一个解释

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

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

+0

看来这对我来说有点太难了。它完美的工作,但我得到一个内存溢出:代码:http://pastebin.com/bm3dqSHm PROFILER:http://imgur.com/a/dB2pl 尖峰发生后,我按下一个按钮,并结束后动画完成。动画全部不循环,这就是43行应该是。它会被取消注释,内存使用量会上升,直到发生溢出。这里的背景究竟发生了什么? – uncanny

+0

更新,当我只是用Play()而不用排队启动状态时,这种行为似乎更加明显。一旦纹理被读取,内存不会再次释放,即使我再次启动相同的状态,它只是再次读取它并分配两倍的内存。 – uncanny

+0

不知道是什么问题。我运行代码并测试它,它工作正常。它没有正确处理循环行为,这对你来说是一个挑战,但是代码很好,并且不会产生垃圾。在播放模式打开时检查您是否正在录制,可能会导致问题。另一件事,要循环动画,您需要在实际的动画文件中检查“循环时间”。 – JJC

0

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

+0

顺序是动态的(如,如果你推“平滑过渡到3”按钮,它会等到当前动画结束,然后开始动画3),所以可以你解释一下更详细一点吗?我不确定这是否对我在屏幕上的按钮的“控制面板”有效,因为每个按钮都需要能够访问每个动画的变量而不仅仅是控制器。 – uncanny