游戏开发过程中经常会遇到要加载一片场景资源的情况,先不考虑如何加载的情况,对于一大片场景的加载和显示,如果在一帧内完成的话,对性能会有很大的小号,造成瞬间帧率下降,产生性能峰值。
一般这种不需要实时性的加载都会分帧处理,把压力平摊下去,为了使加载过程更加平滑与受控,博主写一个协程队列去控制我们加载过程中协程的调用顺序与次数,更好的平滑我们的加载过程。
因为这里协程的调用是使用迭代器的
MoveNext,并非调用StartCoroutine开启动迭代器,所以无法实现计时器的功能(WaitForSeconds),
仅支持yield return null,能够满足此条件的才能使用该脚本,
同时这种实现方法也带来性能优势,减少每次调用一次StartCoroutine都会带来24B的内存消耗,若开启协程很平凡,这个消耗还是很明显的。
使用方法是找个GameObject挂载CoroutineManager脚本,需要管理的协程通过CoroutineManager.EnqueueWork方法加到协程队列,下面源码中也有测试代码。
协程队列处理:
EnqueueWork(Test1());
EnqueueWork(Test3());
EnqueueWork(Test3());
正常开启协程:
StartCoroutine(Test1());
StartCoroutine(Test3());
StartCoroutine(Test3());
可以看出,使用协程队列可以更加平滑而且容易控制的去控制协程。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class CoroutineManager : MonoBehaviour
{
//协程队列
private Queue
mCoroutineQueue = new Queue
();
//当前处理的协程
private IEnumerator mCurrentWork = null;
private static CoroutineManager instance;
public static CoroutineManager Instance
{
get { return instance; }
}
void Awake()
{
instance = this;
}
public void EnqueueWork(IEnumerator work)
{
mCoroutineQueue.Enqueue(work);
}
void Update()
{
while (mCoroutineQueue.Count > 30)
DoWork();
//如果协程队列>20个,则一次执行3个语块
if (mCoroutineQueue.Count > 20)
DoWork();
//如果协程队列>10个,则一次执行2个语块
if (mCoroutineQueue.Count > 10)
DoWork();
DoWork();
}
void DoWork()
{
if (mCurrentWork == null && mCoroutineQueue.Count == 0)
return;
if (mCurrentWork == null)
{
mCurrentWork = mCoroutineQueue.Dequeue();
}
//这个协程片段是否执行完毕
bool mElementFinish = !mCurrentWork.MoveNext();
if (mElementFinish)
{
mCurrentWork = null;
}
//如果协程里面嵌套协程
else if (mCurrentWork.Current is IEnumerator)
{
mCurrentWork = (mCurrentWork.Current as IEnumerator);
}
}
#region 这一部分为测试代码
void Start()
{
//协同队列处理
EnqueueWork(Test1());
EnqueueWork(Test3());
//正常开启协同
//StartCoroutine(Test1());
//StartCoroutine(Test3());
}
IEnumerator Test1()
{
Debug.Log(string.Format("第{0}帧:1",Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:2", Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:3", Time.frameCount));
yield return Test2();
}
IEnumerator Test2()
{
Debug.Log(string.Format("第{0}帧:4", Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:5", Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:6", Time.frameCount));
}
IEnumerator Test3()
{
Debug.Log(string.Format("第{0}帧:7", Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:8", Time.frameCount));
yield return null;
Debug.Log(string.Format("第{0}帧:9", Time.frameCount));
}
#endregion
}