关于协程就不多说了,随便一搜就有一堆关于协程的介绍和使用,直接看我要解决的问题吧:等一个协程执行完成再执行后面的逻辑。应用场景:等游戏开始动画执行完成,才能开启游戏逻辑;等洗牌完成才能进行发牌逻辑…
Unity 之 Lua模拟C#等一个协程执行
在 C# 中的使用方式:
在C#中使用使用 yield return StartCoroutine(fun()) 来处理,看下测试代码:
执行顺序为: 调用协程 Cor2 执行自己的逻辑,然后调用协程 Cor1 并且等协程 Cor1 执行完成之后,在继续执行Cor2自己后面的逻辑;
private void OnEnable()
{
StartCoroutine(Cor2());
}
private IEnumerator Cor1()
{
Debug.Log("Cor1 1111111111111111");
yield return new WaitForSeconds(2f);
Debug.Log("Cor2 2222222222222222");
}
private IEnumerator Cor2()
{
Debug.Log("Cor2 3333333333333333");
yield return StartCoroutine(Cor1());
Debug.Log("Cor2 4444444444444444");
}
使用 Lua 模拟:
主要逻辑:使用计算第一个协程(cor1)执行的时间,使第二个协程需要后执行的逻辑也等相同或者相同多一点的时间之后,再执行代码如下:
function CorTest()
local cor1 = coroutine.create(function()
print("cor1 1111111111111111");
WaitForSeconds(2);
print("cor1 2222222222222222");
end);
local cor2 = coroutine.create(function()
print("cor2 3333333333333333");
--开启cor1的逻辑
coroutine.resume(cor1);
-- 等cor1要执行的时间
WaitForSeconds(2);
-- 多等1帧
WaitForFixedUpdate();
print("cor2 4444444444444444");
end);
coroutine.resume(cor2);
end
缺陷:有可能因为显示卡顿或者逻辑复杂,导致虽然都是相同的等待时间cor2需要后执行的逻辑却先执行了。
改善版本,逻辑:判断 cor1 的状态来确定 cor2 后面的逻辑是否继续执行;
function CorTest()
local cor1 = coroutine.create(function()
print("cor1 1111111111111111");
WaitForSeconds(2);
print("cor1 2222222222222222");
end);
local cor2 = coroutine.create(function()
print("cor2 3333333333333333");
--开启cor1的逻辑
coroutine.resume(cor1);
--print("看下cor1当前状态",coroutine.status(cor1))
while true do
WaitForFixedUpdate();
if coroutine.status(cor1) == "dead" then
break;
end
end
print("cor2 4444444444444444");
end);
coroutine.resume(cor2);
end
扩展:使用StopCoroutine(Cor1());的问题:
代码如下这样写是不能停止掉Cor1的,
void CorTest()
{
// 使用字符串为参数的调用是没有问题的
StartCoroutine("Cor1");
StopCoroutine("Cor1");
// 错误的停止协程的方法
StartCoroutine(Cor1());
StopCoroutine(Cor1());
}
StopCoroutine的官方注释译文:停止名为methodName的第一个协同程序,或存储在例程中的协同程序运行此行为。
// 摘要:
// Stops the first coroutine named methodName, or the coroutine stored in routine
// running on this behaviour.
//
// 参数:
// methodName:
// Name of coroutine.
//
// routine:
// Name of the function in code.
public void StopCoroutine(IEnumerator routine);
我个人理解为StartCoroutine(Cor1()); 和 StopCoroutine(Cor1()); 这两个Cor1 它认为不是一个(不知道对不对啊);
看下能成功停止调用的方法吧:
private void OnEnable()
{
// 正确的操作:
Coroutine cor = StartCoroutine(Cor1());
StopCoroutine(cor);
// 或者这样:
IEnumerator cor1 = Cor1();
StartCoroutine(cor1);
StopCoroutine(cor1);
}