协程(一)基本使用
协程(二)协程什么时候调用
协程(三)IEnumerable、IEnumerator、foreach、迭代
协程(四)yield与迭代器
协程(五)简单模拟协程
协程(六)有关优化
参考:https://blog.csdn.net/here4one/article/details/83053417
一.类似上一节的代码:
IEnumerator TestCoroutine()
{
yield return null; //返回内容为null
yield return 1; //返回内容为1
yield return "sss"; //返回内容为"sss"
yield break; //跳出,类似普通函数中的return语句
yield return 999; //由于break语句,该内容无法返回
}
void Start()
{
IEnumerator e = TestCoroutine();
while (e.MoveNext())
{
Debug.Log(e.Current); //依次输出枚举接口返回的值
}
}
二. 简单模拟协程
- 测试类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Text : MonoBehaviour
{
public MyCoroutines myCoroutines;
// Start is called before the first frame update
void Start()
{
myCoroutines.MyStartCoroutine(h1());
myCoroutines.MyStartCoroutine(h2());
}
private IEnumerator h1()
{
Debug.Log("h1 1");
yield return null;
Debug.Log("h1 2");
yield return null;
Debug.Log("h1 3");
yield return new MyWaitForSeconds(2.0f);
Debug.Log("h1 4");
yield return null;
Debug.Log("h1 5");
}
private IEnumerator h2()
{
Debug.Log("h2 1");
yield return new MyWaitForSeconds(5.0f);
Debug.Log("h2 2");
yield return null;
Debug.Log("h2 3");
yield return null;
Debug.Log("h2 4");
yield return new MyWaitForSeconds(3.0f);
Debug.Log("h2 5");
yield return null;
}
}
- 协程类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyCoroutines : MonoBehaviour
{
private List<IEnumerator> coroutines = new List<IEnumerator>();
private bool isContinue;
// 协程是在Update之后,LateUpdate之前执行,Unity未暴露出接口,只能将就着放在LateUpdate中
private void LateUpdate()
{
if (coroutines.Count > 0)
{
for (int i = 0; i < coroutines.Count; i++)
{
isContinue = true;
if (coroutines[i].Current is MyWaitForSeconds)
{
MyWaitForSeconds myWaitForSeconds = coroutines[i].Current as MyWaitForSeconds;
myWaitForSeconds.AddTime(Time.deltaTime);
if (!myWaitForSeconds.CheckTime())
{
isContinue = false;
}
}
if (isContinue && !coroutines[i].MoveNext())
{
coroutines.RemoveAt(i);
i--;
}
}
}
}
public void MyStartCoroutine(IEnumerator routine)
{
if (!coroutines.Contains(routine))
{
coroutines.Add(routine);
}
}
}
- 延迟类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyWaitForSeconds
{
private float delay;
private float currentTime;
public MyWaitForSeconds(float delay)
{
this.delay = delay;
currentTime = 0f;
}
public void AddTime(float addTime)
{
currentTime += addTime;
}
public bool CheckTime()
{
if (currentTime >= delay)
{
return true;
}
return false;
}
}
-
测试结果
- 另外在放上一个协程的交叉调用类
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(GUIText))]
public class Hijack : MonoBehaviour {
//This will hold the counting up coroutine
IEnumerator _countUp;
//This will hold the counting down coroutine
IEnumerator _countDown;
//This is the coroutine we are currently
//hijacking
IEnumerator _current;
//A value that will be updated by the coroutine
//that is currently running
int value = 0;
void Start()
{
//Create our count up coroutine
_countUp = CountUp();
//Create our count down coroutine
_countDown = CountDown();
//Start our own coroutine for the hijack
StartCoroutine(DoHijack());
}
void Update()
{
//Show the current value on the screen
guiText.text = value.ToString();
}
void OnGUI()
{
//Switch between the different functions
if(GUILayout.Button("Switch functions"))
{
if(_current == _countUp)
_current = _countDown;
else
_current = _countUp;
}
}
IEnumerator DoHijack()
{
while(true)
{
//Check if we have a current coroutine and MoveNext on it if we do
if(_current != null && _current.MoveNext())
{
//Return whatever the coroutine yielded, so we will yield the
//same thing
yield return _current.Current;
}
else
//Otherwise wait for the next frame
yield return null;
}
}
IEnumerator CountUp()
{
//We have a local increment so the routines
//get independently faster depending on how
//long they have been active
float increment = 0;
while(true)
{
//Exit if the Q button is pressed
if(Input.GetKey(KeyCode.Q))
break;
increment+=Time.deltaTime;
value += Mathf.RoundToInt(increment);
yield return null;
}
}
IEnumerator CountDown()
{
float increment = 0f;
while(true)
{
if(Input.GetKey(KeyCode.Q))
break;
increment+=Time.deltaTime;
value -= Mathf.RoundToInt(increment);
//This coroutine returns a yield instruction
yield return new WaitForSeconds(0.1f);
}
}
}