前段时间终于能抽出一点时间去总结整理一下Unity3D的一些基础原理的东西。后边还会持续整理更新,相关知识点,需要的可以关注一下我的博客,希望能帮助初学者迅速掌握Unity3D
先明确一点,Unity3D协程不是进程或线程,其执行过程更类似于子例程。(子例程是某个主程序的一部分代码,该代码执行特定的任务并且与主程序中的其他代码相对独立。子例程又被称为子程序、过程、方法、函数等。在主程序中可以调用子例程来执行。)
协程中常用到的停留等待语句有以下四种:
(yield return null , yield return new WaitForSeconds ,yield return new WaitForFixedUpdate和yield return new WaitForEndOfFrame)
其中协程(Coroutine)、WaitForSeconds类、WaitForFixedUpdate类、WaitForEndOfFrame类都是YieldInstruction类的派生类
yield return null:表示暂缓一帧,在下一帧接着往下处理;
yield return new WaitForSeconds:这个要注意的是1·实际时间等于给定的时间乘以Time.timeScale的值。2·触发间隔一定大等于1中计算出的实际时间,而且误差的大小取决于帧率,因为它是在每帧处理协程的时候去计算时间间隔是否满足条件,如果满足则继续执行。例如,当帧率为5的情况下,一帧的时间为200ms,这时即使时间参数再小,最快也要200ms之后才能继续执行剩余部分。
yield return new WaitForEndOfFrame:顾名思义是在等到本帧的帧末进行在进行处理
yield return new WaitForFixedUpdate:暂停协程知道下一个FixedUpdate时才会继续执行协程(等待所有脚本中的FixedUpdate执行后继续执行)
yield return new WWW(url) 等待url下载完后继续执行
yield return StartCoroutine(MyFunc()) 等待协程结束在执行
协程的开启方法和暂停方法:
1.开启方法两种:
StartCoroutine(IEnumerator routine)
这个里面是以 IEnumerator类型的变量作为参数
eg:有协程 IEnumerator asta(string a){} 则开启协程的方法为 StartCoroutine(asta(“name”)) ;无参则不用写参数
StartCoroutine(string methodName,object value=null)
这个里面使用一个String类型和一个object类型作为参数;
其中methodName 为协程的方法名, 而value则是协程的参数(由于value有一个默认值null,因此使用StartCoroutine方法时也可以省略第二个参数,只传入一个string类型的参数就可以)
这个两种开启协程方法的区别:
在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。
2.暂停协程的两种方法
对应的暂停协程也有两种方法
StopCoroutine(IEnumerator routine)
StopCoroutine(string methodName)
除了这两个还有一个比较霸道的停止协程的方法
StopAllCoroutines(); //只对Coroutine起作用,会停掉此脚本里所有的Coroutine。
注:StopCoroutine方法只能停止在同一个脚本中方法名和传入的string型参数相同的协程,而无法影响别的脚本中开启的协程,同时要注意StopCoroutine方法只能用来停止那些使用了StartCoroutine的string类型参数的重载版本开启的协程
下面就是协程的使用:
协程主要用于需要延时执行的逻辑或者是实现逻辑在一段时间内逐步执行
1.协程在一段时间内逐步执行实现逻辑
以随着时间而逐渐减小一个对象的的alpha值为例,协程实现代码如下:
IEnumerator Fade(){
for(float f=1f;f>=0;f-=0.1f)
{
Color c=renderer.material.color;
c.a=f;
renderer.material.color=c;
yield return null;
}
}
yield return 所在的位置就是协程暂停,把控制权移交给Unity3D引擎以及之后继续执行余下逻辑的地方。
2.使用协程实现延时效果
一下分别用WaitForSeconds、WaitForFixedUpdate、WaitForEndOfFrame举例:
(1) WaitForSeconds(Time) Time为停留等待的时间
void Start(){
StartCoroutine("Example");
}
IEnumerator Example(){
print(Time.time);
yield return WaitForSeconds(5);//暂停五秒之后执行
print(Time.time);
}
(2) WaitForFixedUpdate() 这个暂停的时间取决于Unity3D编辑器中的TimeManager的FixedTimestep中的值
void Start(){
StartCoroutine("Example");
}
IEnumerator Example(){
while(true){
Debug.log(Time.frameCount);
Debug.log(Time.time);
yield return new WaitForFixedUpdate();
}
}
(3) WaitForEndOfFrame() 我们常用它来处理等待帧结束再恢复执行的逻辑。它的作用是等到所有的摄像机和GUI被渲染完成后,在恢复协程的执行
下面这个代码实现是截取当前屏幕的画面,并作为PNG图片保存到本地
void Start(){
StartCoroutine(ScreenShotPNG()));
}
IEnumerator ScreenShotPNG()
{
yield return new WaitForEndOfFrame();
int width=Screen.width;//屏幕的宽
int height=Screen.height;//屏幕的高
Texture2D tex=new Texture2D(width,height,TextureFormat.RGB24,false); //创建一个Texture2D图片
tex.ReadPixels(new Rect(0,0,width,height),0,0);
tex.Apply();//开始执行
byte[] bytes=tex.EncodeToPNG();//转换为PNG图片
Destory(tex);
File.WriteAllBytes(Application.dataPath+"/../SavedScreen.png",bytes);//存储到本地
}
协程迭代机制
协程迭代机制的执行步骤 一下为一个示例代码:
void Start () {
foreach (string s in GetIEnumerablesss())
{
Debug.Log(s);
}
}
IEnumerable<string> GetIEnumerablesss()
{
yield return "begin";
for (int i = 0; i < 10; i++)
{
yield return i.ToString();
}
yield return "end";
}
执行结果:
协程的实现其实是迭代器在起作用,而深入了解迭代器的内部,发现原来迭代器的实现主要依靠的是一个状态机,
而状态机是靠着goto语句实现半路插入,进而实现了从yield return 语句处继续执行的功能。(详细讲解可参考Unity基础的238页 即第八章协程背后的迭代器)
转载请标明出处,谢谢!!!