Unity3D协程

线程:实现多个任务在同一时间内执行(实际是在很短的时间片内对个多个任务的执行来回切换,从而达到“同时的效果”),比较消耗系统资源

协程:实现一个任务在不同时间内分段执行,相对游戏来说系统开销不大

1.        //开启协程
        //首先会调用下协程函数里面的内容

        StartCoroutine(Caculator());

2.



  1. IEnumerator Caculator()
  2. {
  3. for ( int i = 0; i <= 5; i++)
  4. {
  5. Debug.Log( "current value is:" + i);
  6. yield return null; //等到下一帧开始继续运行
  7. }
  8. }

具体知识:

1.什么是协调程序

unity协程是一个能暂停执行,暂停后立即返回,直到中断指令完成后继续执行的函数。

它类似一个子线程单独出来处理一些问题,性能开销较小,但是他在一个MonoBehaviour提供的主线程里只能有一个处于运行状态的协程。

协程不是多线程,协程还是在主线程里面

2.协同程序的特点

1、协程在中断指令(YieldInstruction)产生时暂停执行

2、协程一暂停执行便立即返回 //中断协程后返回主函数,暂停结束后继续执行协程剩余的函数。

3、中断指令完成后从中断指令的下一行继续执行

4、同一时刻、一个脚本实例中可以有多个暂停的协程,但只有一个运行着的协程

5、函数体全部执行完后,协程结束

6、协程可以很好的控制跨越一定帧数后执行的行为

7、协程在性能上、相比于一般函数几乎没有更多的开销


分步做一个比较耗时的事情

官方文档Monobehaviour的函数执行顺序图,就对协程再次执行的时机做了很好的描述. 
这里写图片描述 
以上只是一个示意图,详细信息请看官方文档. 
链接https://docs.unity3d.com/Manual/ExecutionOrder.html

yield null:协程将在下一帧所有脚本的Update执行之后,再继续执行. 
yield WaitForSeconds:协程在延迟指定时间,且当前帧所有脚本的 Update全都执行结束后才继续执行. 
yield WaitForFixedUpdate:协程在所有脚本的FixedUpdate执行之后,再继续执行. 
yield WWW:协程在WWW下载资源完成后,再继续执行. 
yield StartCoroutine:协程在指定协程执行结束后,再继续执行. 
WaitForSecondsRealtime:与WaitForSeconds类似,但不受时间缩放影响. 
WaitWhile:当返回条件为假时才执行后续步骤.

8.例子

lg1、举例说明协同程序的执行流程

 

using UnityEngine;
using System.Collections;

public class SimpleCoroutine : MonoBehaviour {
/// <summary>
/// Start, 协程的执行流程
/// Start函数运行,输出“1”,然后开始协程Do;
/// Do输出“2”,然后开始协程newDo;
/// newDo输出“3”,产生中断指令后暂停,立即返回Do;
/// Do产生中断指令后暂停,Do暂停并立即返回Start函数;
/// Start执行StartCoroutine的下一条语句:输出“4”;
/// 2秒后,newDo的中断指令完成并继续执行,输出“5”,协程newDo结束;
/// Do的中断指令因为协程newDo的结束而完成并继续执行,输出“6”,协程Do结束。
/// </summary>
void Start () {
Debug.Log(“1”);
StartCoroutine(Do());
Debug.Log(“4”);
}
IEnumerator Do() {
Debug.Log(“2”);
yield return StartCoroutine(newDo());//WaitForSeconds(5);
Debug.Log(“6”);
}
IEnumerator newDo() {
Debug.Log(“3”);
yield return new WaitForSeconds(2);
Debug.Log(“5”);
}
}
//输出结果顺序是,1,2,3,4,5,6

[/csharp]

lg2、加载指令(通过WWW加载本地文件)

?
1
 

private string path = “file://F:/Resource/Dragon.unity3d”;
void OnGUI(){
if(GUI.Button(new Rect(200,200,150,30),”点击进入协同程序”)){
Debug.Log(“1”);
StartCoroutine(loadLocalBundle(path));
Debug.Log(“3”);
}
}
private IEnumerator loadLocalBundle(string url){
Debug.Log(“2”);
using(WWW www = new WWW(url)){
yield return www;
Debug.Log(“4”);
if(www.error != null){
var bytes = www.bytes;
}
AssetBundle ab = www.assetBundle;
GameObject gameObject = ab.mainAsset as GameObject;
Instantiate(gameObject);
Debug.Log(“5”);
Debug.Log(“load local assetBundle finished…”+gameObject);
}
}
注意:
大概执行流程,点击按钮后开始执行协同程序,WWW按照提供的url进行加载,完毕后 yield return www;中断指令跳转到主线程。
主线程继续执行其他内容,www在加载完成后跳出中断继续执行余下内容。
加载完毕,实例化加载内容。


协程的真正用途是分步做一个短时间内比较耗时的事情,比如游戏里面的加载资源

private int num = 0;
private const  int total=30;

	void Start()
    {
        StartCoroutine(coRoutine());
    }

   IEnumerator coRoutine()
    {
        while (num<total)
        {
            num++;
            Debug.Log(num);
            yield return null;
        }   
    }
	
	void Update () {
        Debug.Log("update!");
	}
    void LateUpdate()
    {
        Debug.Log("lateUpdate!");
    }

 

上面的代码是个简单的例子,比如我们加载的资源有30个(total),但是一次加载完毕会耗费大量的时间,不可能让玩家在start中等待这么久,这时候协程的作用就出现了,协程是每帧lateUpdate之前执行yield return之前的代码,lateupdate之后执行yield return之后的代码,相当于每帧循环一次(前提是你的协程有循环体,否则一帧就执行完了),具体可以复制我的代码看一下日志,这样就不会卡在这加载30个资源这里,而是你在update里面继续做你的事情,我每次只加载1个,加载1个耗时显然远远小于30个。


  1. IEnumerator Caculator()
  2. {
  3. for ( int i = 0; i <= 5; i++)
  4. {
  5. Debug.Log( "current value is:" + i);
  6. yield return null; //等到下一帧开始继续运行
  7. }
  8. }

猜你喜欢

转载自blog.csdn.net/u013617851/article/details/80973678