Tech · ArtUnity

「Unity」基础篇—Coroutine 协程与Timeline的使用

by Ayse, 2022-07-20


最近给一个展示项目手搓了一个关于动画/视角切换播放的状态机,但是这个最终的代码可能就不放上来了,记录一下自己学到的两个新东西。

协程

(协同程序)(StartCoroutine 和yield return和StopCoroutine )之前一直没有找到如何在某一帧后开启update,只是一股脑在update里面加入开关,但是这样其实并不优雅,update里面就会一大坨。这个时候我们就可以用协程实现我们的效果。协程(Coroutine)也有一个说法是微线程,实现一个类似多线程的操作。

协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程。可以简单理解为它是一个效率更高的多线程替代方案协程的最大使用上的问题就是如果在协程上加入IO阻塞(即等待输入这种)的话,会导致整个线程也陷入IO,所以当需要在协同程序中加入IO的过程,就最好通过异步调用或者多线程实现。这里俺不是程序,所以就简单理解一下即可。

而在Unity中,协程可以用于各种倒放,开始一个独立的Update,它在切换线程的过程中也比直接通过多线程切换要快,当然,如果我们是一些固定效果,用timeline做好了直接播放是可以在工作量上增加,性能或许为最优的状态

Coroutine的使用

那么在使用层面,大家可以跳转官方文档,还是非常清晰的。官方文档中提到了一个样例代码

    IEnumerator Fade() { 
       Color c = renderer.material.color;
        for(**float** alpha = 1f;alpha >= 0; alpha -= 0.1f)    
    {        c.a = alpha;        renderer.material.color = c;       
     yield return null;    } }

在完成了这句之后我们只需要在需要开启的时候调用 StartCoroutine即可

  StartCoroutine(Fade());

yield return null是配合协程使用的一个重要写法,代表每一帧到这里协程会被唤醒, 如果需要停止则yield return new WaitForSeconds(.1f); 。而IEnumerator 则是一个迭代器,

A coroutine is a method that you declare with anIEnumerator return type and with a yieldreturn statement included somewhere in the body. The yield return nullline is the point where execution pauses and resumes in the following frame.

这里的功能包括了我们控制物体的响应方式,因为Update是每一帧刷新,我们可以通过协程,不通过update内部的布尔值就可以实现协程的编写

    bool ProximityCheck() 
{    for (int i = 0; i < enemies.Length; i++) {        
if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) 
{ return true;  }  
 }  return false; }

    IEnumerator DoCheck() {  for(;;)    
{     if (ProximityCheck())       
 {            // Perform some action here        }     
yield return new WaitForSeconds(.1f);    } }

一般来说我们也可以写成是一个函数的嵌套,只要设定了中止条件即可,就比如下面这个是倒放timeline的实现代码。

public IEnumerator offsetRewind()
{
    yield return new WaitForSeconds(0.001f * Time.deltaTime);
    offsetwarning.time -= 1.0f * Time.deltaTime;  //1.0f是倒帶速度
    offsetwarning.Evaluate();
    if (offsetwarning.time < 0f)
    {
        offsetwarning.time = 0f;
        offsetwarning.Evaluate();
    }
    else
    {
        StartCoroutine("offsetRewind");
    }
}

然后stopcoroutine 则是随时可以通过此方法停止coroutine的更新。

知乎大佬的这个写法非常清晰的写出了协程的用法

IEnumerator CoroutineA(int arg1, string arg2)
{
    Debug.Log($"协程A被开启了");
    yield return null;
    Debug.Log("刚刚协程被暂停了一帧");
    yield return new WaitForSeconds(1.0f);
    Debug.Log("刚刚协程被暂停了一秒");
    yield return StartCoroutine(CoroutineB(arg1, arg2));
    Debug.Log("CoroutineB运行结束后协程A才被唤醒");
    yield return new WaitForEndOfFrame();
    Debug.Log("在这一帧的最后,协程被唤醒");
    Debug.Log("协程A运行结束");
}

这个功能在实现补间动画是非常方便的。当然现在还有就是用插件 Dotween,只需要一个transform.DOMove(new Vector3(1,2,3), 1);//move to place in 1s。


Timeline

Unity 中的动画系统

这里参考了知乎上的回复 远古时期,Unity只支持Legacy动画系统,他没有状态控制器,就是传统引擎的思路,状态就丢给上层开发者去控制吧。后来就开始用了状态机,即Mecanim动画系统,这个东西也不是特别好使,所以最后开发了playable来统一和组织,包括这里的playablegraph,而timeline就是一个基于playable的东西,它控制了一个playable文件的播放

Unity中播放动画的几个方法,一个是通过animation controller,这个就不多说了放上去就播放,一个是通过Playablegraph,设定好animationclip,通过api包装好playable对象,最后实现play方法即可

public AnimationClip clip;
...
void Start()
{
    m_Graph = PlayableGraph.Create();
    m_Graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
    m_Output = AnimationPlayableOutput.Create(m_Graph, "Animation", GetComponent<Animator>());
    AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(m_Graph, clip);
    m_Output.SetSourcePlayable(clipPlayable);
    m_Graph.Play();
}

当然这里还有更复杂的运用,这个只是一个最基础的动画树,但重点不是这个,就先略过 Timeline方面。timeline的模式是播放一个playable,而playable是管理一系列的track的,track的其中一种是animation track,当然我们如果需要混合,我们就肯需要MixerPlayerble

里面包含了animation track/control track等等都各种功能,具体的功能如下:

Activation Track(控制物体的显示和隐藏) Animation Track(为物体加入动画,可以在场景中方便地录制动画,也可以是已经制作好的Animation Clip) Audio Track(为动画添加音效,并可对音效进行简单的裁剪和操作) Control Track(在该轨道上可以添加粒子效果,同时也可以添加子Timeline进行嵌套) Playable Track(在该轨道中用户可以添加自定义的播放功能) Track Group(将不同的轨道进行分类,相当于文件夹功能)

其中animation timeline可以通过录制来进行k帧,还是蛮方便的。还有一个特殊的Signal track,它可以在timeline过程中发出一个信号来调用某一事件,当然只要经过就会触发。不论是否是协程。

Enjoy。

作者: Ayse

2024 © typecho & elise