Unity中的协程

前言

在使用Unity,一般不考虑多线程,原因是在Unity中,只能在主线程中获取物体的组件、方法、对象,脱离这些,Unity的许多功能无法实现,这就失去了使用多线程的意义。

线程和协程的区别:

对于协程而言

markdown 复制代码
    同一时间只能执行一个协程,而线程是并发的,可以同时有多个线程运行;
    线程和协程的使用上是相同的,共享堆,不共享栈

协程

协程不是线程,协程依旧是在主线程中执行,协程是通过迭代器来实现的,通过IEnumerator定义迭代方法,主要使用的是IEnumerator,而不是IEnumerable。

IEnumerator和IEnumerable的区别:

IEnumerator:是一个实现迭代器的接口。
IEnumerable:是在IEnumerator基础上的一个封装接口

协程的使用

首先通过一个迭代器定义一个返回值为IEnumerator的方法,然后再程序中通过StartCoroutine来开启一个协程即可:

在正式开始代码之前,需要了解StartCoroutine的两种重载方式:

StartCoroutine(string methodName):这种是没有参数的情况,直接通过方法名(字符串形式)来开启协程

StartCoroutine(IEnumerator routine):通过方法形式调用

StartCoroutine(string methodName,object values):带参数的通过方法名进行调用

js 复制代码
    Coroutine coroutine1;
    IEnumerator Demo()
    {
        Debug.Log("Hello");
        yield return new WaitForSeconds(5);
        Debug.Log("World");
    }
    public void Test()
    {
        //第一种调用方式和第二种方式,通过方法名和参数调用
        //coroutine1=StartCoroutine("Demo");
        //第三种调用方式
       coroutine1= StartCoroutine(Demo());
    }
    private void Start()
    {
        Test();
       
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Z))
        {
            Debug.Log("按下了z键");
            // StopCoroutine("Demo");
            StopCoroutine(coroutine1);
        }
    }

在一个协程开始后,同样会对应一个结束协程的方法StopCoroutine与StopAllCoroutines两种方式,但是需要注意的是,两者的使用需要遵循一定的规则,在介绍规则之前,同样介绍一下关于StopCoroutine重载:

StopCoroutine(string methodName):通过方法名(字符串)来进行

StopCoroutine(IEnumerator routine):通过方法形式来调用

StopCoroutine(Coroutine routine):通过指定的协程来关闭

使用是有一定的规则的,规则是前两种结束协程方法的使用上,如果我们是使用StartCoroutine(string methodName)来开启一个协程的,那么结束协程就只能使用StopCoroutine(string methodName)和StopCoroutine(Coroutine routine)来结束协程

关于Yield

js 复制代码
yield return null; 暂停协程等待下一帧继续执行

yield return 0或其他数字; 暂停协程等待下一帧继续执行

yield return new WairForSeconds(时间); 等待规定时间后继续执行

yield return StartCoroutine("协程方法名");开启一个协程(嵌套协程)

yield return GameObject; 当游戏对象被获取到之后执行 yield return new WaitForFixedUpdate():等到下一个固定帧数更新 yield return new WaitForEndOfFrame():等到所有相机画面被渲染完毕后更新 yield break; 跳出协程对应方法,其后面的代码不会被执行

协程小用法

5.1、将一个复杂程序分帧执行:

如果一个复杂的函数对于一帧的性能需求很大,我们就可以通过yield return null将步骤拆除,从而将性能压力分摊开来,最终获取一个流畅的过程,这就是一个简单的应用

举一个案例,如果某一时刻需要使用Update读取一个列表,这样一般需要一个循环去遍历列表,这样每帧的代码执行量就比较大,就可以将这样的执行放置到协程中来处理:

public class Test : MonoBehaviour { public List nums = new List { 1, 2, 3, 4, 5, 6 };

csharp 复制代码
private void Update()
{
    if(Input.GetKeyDown(KeyCode.Space))
    {
        StartCoroutine(PrintNum(nums));
    }
}
//通过协程分帧处理
IEnumerator PrintNum(List<int> nums)
{
    foreach(int i in nums)
    {
        Debug.Log(i);
        yield return null;
             
    }

}

}

上面只是列举了一个小小的案例,在实际工作中会有一些很消耗性能的操作的时候,就可以通过这样的方式来进行性能消耗的分消

5.2、进行计时器工作

当然这种应用场景很少,如果我们需要计时器有很多其他更好用的方式,但是你可以了解是存在这样的操作的,要实现这样的效果,需要通过yield return new WaitForSeconds()的延时执行的功能:

csharp 复制代码
IEnumerator Test()
{
    Debug.Log("开始");
    yield return new WaitForSeconds(3);
    Debug.Log("输出开始后三秒后执行我");
}

5.3、异步加载等功能

只要一说到异步,就必定离不开协程,因为在异步加载过程中可能会影响到其他任务的进程,这个时候就需要通过协程将这些可能被影响的任务剥离出来

常见的异步操作有:

AB包资源的异步加载 Reaources资源的异步加载 场景的异步加载 WWW模块的异步请求

使用 StartCoroutine(函数()); 形式开启的,只能用接收返回值的形式去停止;【不限制参数个数】

使用 StartCoroutine("函数名"); 形式开启的,可以使用 StopCoroutine("函数名");

形式停止, 也可使用 接收返回值的形式去停止。【缺点:只可以传递一个参数】

两种开启形式均受到 StopAllCoroutines() 控制。StopAllCoroutines() 可以停止当前脚本中所有协程。

gameObject.SetActive(false); 可停掉所有此GameObject上的所有协程,且再次激活时协程不会继续。

StopCoroutine(函数()); 脚本.enabled = false; 不可停掉协程。

相关推荐
Thomas_YXQ4 天前
Unity3D Shader的阴影部分法线效果详解
开发语言·游戏·unity·架构·unity3d
氦客4 天前
Unity3D入门(四) : Android和Unity3D交互 - Unity调用Android
android·unity·交互·unity3d·调用·javaobject·javaclass
Thomas_YXQ7 天前
Unity3D PostLateUpdate为何突然占用大量时间详解
开发语言·数码相机·游戏·unity·架构·unity3d
Thomas_YXQ7 天前
Unity3D 中构建行为树插件详解
游戏·unity·架构·unity3d·游戏开发
随遇而安的生活11 天前
Unity android 接USBCamera
android·unity3d
留待舞人归12 天前
【Unity杂谈】iOS 18中文字体显示问题的调查
游戏·unity·ios·游戏引擎·unity3d
吾名招财13 天前
unity3d入门教程八-飞机大战
游戏引擎·unity3d
吾名招财19 天前
unity3d入门教程五
游戏引擎·unity3d
吾名招财19 天前
unity3d入门教程六
游戏引擎·unity3d
吾名招财20 天前
unity3d入门教程七
游戏引擎·unity3d