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;
//代码块
}
🚩启动协程
协程定义完了需要我们进行启动,启动协程有以下几种方法
StartCoroutine(string methodName)
:通过协程的方法名(字符串形式)启动StartCoroutine(string methodName,object values)
:带参数的通过方法名(字符串形式)进行调用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;
//代码块
}
🚩停止协程
协程有一个启动的方法,也有对应的停止协程的方法
StopCoroutine
与StopAllCoroutines
两种方式都可以停止协程
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首选❤️(万字长文建议收藏)
❤️六万字《算法和数据结构》之《画解数据结构》总纲,算法零基础教程❤️(建议收藏)