Unity零基础到入门 ☀️| 小万字教程 对 Unity 中的 协程 ❤️全面解析+实战演练❤️

Posted 呆呆敲代码的小Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity零基础到入门 ☀️| 小万字教程 对 Unity 中的 协程 ❤️全面解析+实战演练❤️相关的知识,希望对你有一定的参考价值。

  • 📢博客主页:https://blog.csdn.net/zhangay1998
  • 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
  • 📢未来很长,值得我们全力奔赴更美好的生活✨


📢前言

  • 为了让Unity基础知识专栏更加完善,又写了一篇 协程 来学习一下

  • 协程 在Unity中还是很常用的,有着不可获取的地位!

  • 本文对 协程 做一个通俗易懂的介绍,并结合实例加深对 协程 的认识和运用能力

  • 协程 一般都是与多线程一并被提及,那本篇文章就结合 多线程 的一些基本概念来介绍 协程


🎬协程

❤️协程概念(IEnumerator)

先来看一下 线程 协程 的简单概念

一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。

线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

协程基本概念:伴随着 主线程 ⼀起运⾏的⼀段程序。

注意点 协程 协程 之间是并⾏执⾏,与主线程也是并⾏执⾏,同一时间只能执行一个 协程

提起 协程 ,自然是要想到 线程 ,因为协程的定义就是伴随主线程来运行的!

大家应该都知道一个程序运行的时候,是可以 多线程 运行的,就是相当于我们的"一心二用"

那既然Unity也有多线程运行,为什么还要用 协程 呢?

因为有一个很重要的点:在Unity中,只能在主线程中去获取物体的组件、方法和游戏对象!

这一点在Unity中至关重要,如果多开辟了一个 线程 ,并不能对Unity中的这些属性进行访问和修改,那这个 线程 也就没什么意义了!

那这个时候 协程 就站了出来,多线程不能用了,那就来协程我呀! 协程 中是可以正常获取游戏对象信息的!

这里就延伸出来一个问题,为什么要用多线程或者协程?

原因:当我们主线程在执行一个对资源消耗很大的操作时,在这一帧我们的程序就会出现帧率下降,画面卡顿的现象!
那这个时候我们就可以利用协程来做这件事,因为协程是伴随着主线程运行的,主线程依旧可以丝滑轻松的工作,把脏活累活交给协程处理就好了!


🧡协程原理

协程是通过迭代器来实现功能的,通过关键字IEnumerator来定义一个迭代方法

提起IEnumerator就会想到IEnumerable,可千万不能搞混了!

  • IEnumerator 是一个实现迭代器功能的接口
  • IEnumerable 是在IEnumerator基础上的一个封装接口,有一个GetEnumerator()方法返回IEnumerator

线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。

协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。


💛使用协程

🚩定义协程

首先我们需要通过IEnumerator 定义一个协程,要通过yield return来定义返回值

我们先来创建一个简单协程看一下代码,下面就是一个简单的协程

    IEnumerator Test(string str)
    {
        //代码块
        Debug.Log("协程被启动了!"+ str);
        yield return null;
        //代码块
    }

🚩启动协程

协程定义完了需要我们进行启动,启动协程有以下几种方法

  1. StartCoroutine(string methodName):通过协程的方法名(字符串形式)启动
  2. StartCoroutine(string methodName,object values):带参数的通过方法名(字符串形式)进行调用
  3. StartCoroutine(IEnumerator routine):通过调用方法的形式启动

如果不是很明白,看一下代码就清楚了

    void Start()
    {
        //通过调用方法名来启动协程(第一种方法)
        StartCoroutine("Test1");

        //通过调用方法名来启动协程(第二种方法)
        StartCoroutine("Test2", "Hello World");

        //直接调用方法启动协程(第三种方法)
        StartCoroutine(Test1());
        StartCoroutine(Test2("Hello World"));
    }

    IEnumerator Test1()
    {
        //代码块
        Debug.Log("协程被启动了!");
        yield return null;
        //代码块
    }
    IEnumerator Test2(string str)
    {
        //代码块
        Debug.Log("协程被启动了!" + str);
        yield return null;
        //代码块
    }

🚩停止协程

协程有一个启动的方法,也有对应的停止协程的方法

StopCoroutineStopAllCoroutines两种方式都可以停止协程

StopAllCoroutines的作用是停止所有该脚本中启动的协程
使用方法也很简单,直接调用就可以了!

        //关闭该脚本中启动的所有协程!
        StopAllCoroutines();

StopCoroutine中又有三种方式

  • StopCoroutine(string methodName):通过方法名(字符串)来关闭协程
  • StopCoroutine(IEnumerator routine):通过调用方法的形式来关闭协程
  • StopCoroutine(Coroutine routine):通过指定的协程来关闭

看一下代码实际操作

    void StopTest()
    {
        //第一种方式:通过调用方法的形式来关闭协程
        StopCoroutine(Test1());

        //第二种方式:通过方法名(字符串)来关闭协程
        StopCoroutine("Test1");

        //第三种方式:通过指定的协程来关闭
        Coroutine a = StartCoroutine(Test1());
        StopCoroutine(a);

        //关闭该脚本中启动的所有协程!
        StopAllCoroutines();
    }

这里有一个地方一定要注意:使用哪一种开启协程的方法,就要使用哪一种方式来关闭协程!

比如是使用字符串的方式启用协程,
例:StartCoroutine("Test1"); 那就要使用字符串的方式来关闭,StopCoroutine("Test1");

同理 使用调用方法的形式开启,那就要使用调用方法的方式来关闭协程!

具体为什么要有这样的规则,俺也不知道,遵从使用即可,就是这样规定的,以后有时间可以研究源码看看~


🚩Yield Return

既然说完了怎样启动停止协程,那接下来就说一下Yield Return

用到了协程,就一定会用的Yield Reruen

再来看一下Unity中的生命周期图,可以发现Yield穿插在其中!

下面我们来对各个不同的 Yield 来做一个说明

  • yield return null; :暂停协程等待下一帧继续执行

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

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

  • yield return new WaitForFixedUpdate():等到下一个固定帧数更新

  • yield return new WaitForEndOfFrame();:等到所有相机画面被渲染完毕后更新

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

了解了一些常用的yield之后,我们写一个简单的测试用例来看一下

    void Start()
    {
        Debug.Log("a");
    }

    void Update()
    {
        Debug.Log("b");
        StartCoroutine(Test1());
        Debug.Log("d");
    }

    IEnumerator Test1()
    {
        Debug.Log("c");
        yield return null;
        Debug.Log("e");
    }

上述代码第一帧肯定打印:a,b,c,d

那小伙伴们你们觉得第二帧会打印什么呢?

第二帧:b,c,d,e。有没有答对呢!

代码很好理解,遇到yield return之后会暂停一帧,跳出协程,等到下一帧的时候再根据yield的生命周期位置来进行打印!

差不多就这些内容,下面结合几个实例再来深入了解一下协程!


💚案例演示

🚩简单计时器

协程中有一个yield方法是:yield return new WaitForSeconds(时间);

每当碰到这个方法,意思就是要在这停止对应的时间才执行下面的方法,这个停止的时间是指协程中的时间

下面看一下代码具体用法

IEnumerator Test()
{
    Debug.Log("开始协程了");
    yield return new WaitForSeconds(3);//等待三秒执行下方代码块
    Debug.Log("三秒时间到了,执行此处代码!");
}

上述代码启动协程后,先打印"开始协程了",然后等待三秒之后再打印"三秒时间到了,执行此处代码!"

我们可以利用yield return new WaitForSeconds(时间);执行许多需要延迟的功能!

🚩通过WWW异步请求下载资源

之前有发过一篇文章介绍了在Unity中访问 URL 连接网页 和 下载图片、文件

其中下载文件的时候就提到过,是通过协程的方法来下载的

那这里再简单演示一下,我们拿下载下面这张图片举例!

下载这张图片的代码

    public IEnumerator DownTexture()
    {
        //下载路径
        string url = "https://img-blog.csdnimg.cn/ff4862dd35e840938edab06ee0a33809.jpg";
        UnityWebRequest WebRequest = new UnityWebRequest(url);
        DownloadHandlerTexture Download = new DownloadHandlerTexture(true);
        WebRequest.downloadHandler = Download;
        yield return WebRequest.SendWebRequest();
        //等待资源下载完成
        while (!WebRequest.isDone)
        {
            yield return null;
        }
        if (string.IsNullOrEmpty(WebRequest.error))
        {
            //文件下载成功
            //读取的图片
            Texture2D rexture = Download.texture;

            texture2D.sprite = GetSpriteByTexture(rexture);
            Debug.Log("图片下载成功");
        }
        else
        {
            //文件下载失败
            Debug.Log("图片下载失败");
        }
    }
    //将texture转成image的Sprite
    Sprite GetSpriteByTexture(Texture2D tex)
    {
        Sprite _sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
        return _sprite;
    }

在Unity中运行一下,结果如下

还有需要异步加载的情况都可以用到协程

比如AB包资源的异步加载Reaources资源的异步加载场景的异步加载等等,就不在一一举例了

主要是介绍一下协程可以用到的地方!


👥总结

本篇文章主要对协程概念原理使用简单案例做了一个介绍说明

真正做项目的时候协程用到的地方也是很多

借助本篇文章可以让你对Unity中的协程有一个简单的概念使用,具体用到的时候可以加深印象!


  • 🎄如果感觉文章看完了不过瘾,可以来我的其他 专栏 看一下哦~
  • 🎄比如以下几个专栏:Unity基础知识学习专栏Unity游戏制作专栏Unity实战类项目 算法学习专栏
  • 🎄可以学习更多的关于Unity引擎的相关内容哦!直接点击下面颜色就可以跳转啦!
🚀 优质专栏分享 🚀
🎄 Unity基础知识学习专栏 🎄
⭐️ Unity游戏制作专栏 ⭐️
🍇 Unity实战类项目 🍇
💦 小Y学算法 💦
🚀 优质专栏分享 🚀

以上是关于Unity零基础到入门 ☀️| 小万字教程 对 Unity 中的 协程 ❤️全面解析+实战演练❤️的主要内容,如果未能解决你的问题,请参考以下文章

Unity零基础到入门☀️| 万字教程 讲解Unity中的数据存储 PlayerPrefsXMLJSON建议收藏

Unity零基础到进阶 ☀️| 近万字教程 对 Unity 中的 动画系统基础 全面解析+实战演练,你确定要错过吗?

❤️Docker超详细基础教程,快速入门docker首选❤️(万字长文建议收藏)

❤️六万字《算法和数据结构》之《画解数据结构》总纲,算法零基础教程❤️(建议收藏)

❤️ 万字Python MySQL从入门到精通详细教程❤️ 再也不用担心学不会数据库了❤️

❤️六万字《算法和数据结构》之《画解数据结构》总纲,算法零基础教程❤️(建议收藏)