我有一些协程:
IEnumerator a(){ /* code */ }
IEnumerator b(){ /* code */ }
IEnumerator c(){ /* code */ }
我想创建一个协程,它们并行调用a
,b
和c
,但是要等到它们全部完成后再进行操作,例如:
IEnumerator d(){
StartCoroutine(a());
StartCoroutine(b());
StartCoroutine(c());
wait until all of them are over
print("all over");
}
显然,我可以为每个协程使用一个布尔值来保存其当前状态,但是由于这种方法不可扩展,因此我希望使用一种更简单的解决方案。
答案 0 :(得分:2)
我使用的方法,它也是一个清晰易懂的代码:
IEnumerator First() { yield return new WaitForSeconds(1f); }
IEnumerator Second() { yield return new WaitForSeconds(2f); }
IEnumerator Third() { yield return new WaitForSeconds(3f); }
IEnumerator d()
{
Coroutine a = StartCoroutine(First());
Coroutine b = StartCoroutine(Second());
Coroutine c = StartCoroutine(Third());
//wait until all of them are over
yield return a;
yield return b;
yield return c;
print("all over");
}
答案 1 :(得分:1)
安装此package (source)时,可以将其实现为异步协程混合方法:
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
public class TestCoroutines : MonoBehaviour
{
void Start () => D();
IEnumerator A () { yield return new WaitForSeconds(1f); print($"A completed in {Time.time}s"); }
IEnumerator B () { yield return new WaitForSeconds(2f); print($"B completed in {Time.time}s"); }
IEnumerator C () { yield return new WaitForSeconds(3f); print($"C completed in {Time.time}s"); }
async void D ()
{
Task a = Task.Run( async ()=> await A() );
Task b = Task.Run( async ()=> await B() );
Task c = Task.Run( async ()=> await C() );
await Task.WhenAll( a , b , c );
print($"D completed in {Time.time}s");
}
}
控制台输出:
A completed in 1.006965s
B completed in 2.024616s
C completed in 3.003201s
D completed in 3.003201s
答案 2 :(得分:1)
有一个使用标准Unity库的解决方案。
您可以创建协程,以包装要调用的协程,并调用完成时设置标志的闭包。然后,您可以使用WaitUntil
等到它们全部成立:
IEnumerator a() {yield new WaitForSeconds(5f);}
IEnumerator b() {yield new WaitForSeconds(3f);}
IEnumerator c() {yield new WaitForSeconds(4f);}
IEnumerator aWrap(Action onDone){yield return a(); onDone();}
IEnumerator bWrap(Action onDone){yield return a(); onDone();}
IEnumerator cWrap(Action onDone){yield return c(); onDone();}
IEnumerator d(){
int finishedCount = 0;
Action onDone = new Action(()=>{finishedCount++;});
StartCoroutine(aWrap(onDone));
StartCoroutine(bWrap(onDone));
StartCoroutine(cWrap(onDone));
yield return new WaitUntil(()=>{finishedCount >= 3});
print("all over");
}
答案 3 :(得分:1)
您还可以使用协程背后的底层迭代器并自己调用MoveNext
在您的示例中,它将类似于
IEnumerator a(){ /* code */ }
IEnumerator b(){ /* code */ }
IEnumerator c(){ /* code */ }
IEnumerator d(){
IEnumerator iea = a();
IEnumerator ieb = b();
IEnumerator iec = c();
// Note the single | operator is intended here
while (iea.MoveNext() | ieb.MoveNext() | iec.MoveNext()) {
yield return null;
}
print("all over");
}
在https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#logical-or-operator-处查看有关|
运算符的文档
它基本上是一个||
运算符,但是它将评估您的所有表达式,从而即使每个迭代器都已经完成,也可以有效地推进每个迭代器。
答案 4 :(得分:0)
您可以尝试Invoke(“ MethodName”,timeinFloat)并在每个方法中添加一个counter(int)/ bool。当它们全部完成运行后,根据计数器/布尔条件,您可以继续执行。
如果Invoke时间设置为0,它将在下一个更新帧周期中运行