问题描述
因此,我有一个script A
,它从script B
调用特定的协程。 gameobjects
中有6个script B
,因此在for循环中调用了6个不同的协程。
类似这样的东西
foreach (Transform child in allChildren)
{
if (child.gameObject.GetComponent<B>() != null)
{
child.gameObject.GetComponent<B>().CallCoroutine();
}
}
coroutines
运行了一段时间。所有6个coroutine
的{{1}}同时结束。我想在这些gameobjects
之后将事件发送回script A
。但是,如果我从coroutines
发送事件,则该事件将被触发6次。解决此问题的最佳方法是什么?
解决方法
您可以让Script A
等待所有协同程序完成,然后调用该事件。看起来像这样:
IEnumerator WaitForChildren() {
List<Coroutine> running = new List<Coroutine>();
foreach (Transform child in allChildren) {
if (child.gameObject.GetComponent<B>() != null) {
running.Add(child.gameObject.GetComponent<B>().CallCoroutine());
}
}
foreach (var coroutine in running) {
yield return coroutine;
}
ChildrenFinishedEvent();
}
您需要使CallCoroutine()
返回由StartCoroutine()
返回的协程对象。
一种方法是将Action
传递给协程以使其在完成时调用,然后在该Action
中递减一个计数器,以使所有Action
的共同点,如果该计数器的计数为零,则调用您要调用的事件:
// B.cs
void CallCoroutine(Action callback)
{
StartCoroutine(MyCoroutine(arg1,arg2,arg3,callback));
}
IEnumerator MyCoroutine(int a,float b,string c,Action callback)
{
// ... coroutine logic here
callback();
}
// A.cs
int counter = 6;
Action callback = delegate()
{
if (--counter == 0)
{
LastCoroutineCompleteEvent();
}
};
foreach (Transform child in allChildren)
{
B childB = child.gameObject.GetComponent<B>();
if (childB != null)
{
childB.CallCoroutine(callback);
}
}
如果协程的数量可变,则可以计算调用CallCoroutine
的次数,并相应地设置counter
的起始值。为了安全起见,您可能需要在调用counter
之前完成设置CallCoroutine
的起始值。所以,像这样:
// A.cs
int counter;
Action callback = delegate()
{
if (--counter == 0)
{
LastCoroutineCompleteEvent();
}
};
List<B> childBs
foreach (Transform child in allChildren)
{
B childB = child.gameObject.GetComponent<B>();
if (childB != null)
{
childBs.Add(childB);
}
}
counter = childBs.Count;
foreach (B childB in childBs)
{
childB.CallCoroutine(callback);
}
,
您可以为CallCoroutine函数提供类型为bool的参数,该参数确定是否应触发事件。
foreach (Transform child in allChildren)
{
bool triggerOnce = true;
if (child.gameObject.GetComponent<B>() != null)
{
child.gameObject.GetComponent<B>().CallCoroutine(triggerOnce);
if(triggerOnce) { triggerOnce = false; }
}
}