【问题标题】:Unity3D: Call an event once from multiple child gameobjectsUnity3D:从多个子游戏对象调用一次事件
【发布时间】:2020-08-17 15:09:42
【问题描述】:

所以我有一个script A,它从script B 调用一个特定的协程。 gameobjectsscript B 有 6 个,所以在一个 for 循环中调用了 6 个不同的协程。

类似的东西

foreach (Transform child in allChildren)
       {
           
           if (child.gameObject.GetComponent<B>() != null)
           {
               child.gameObject.GetComponent<B>().CallCoroutine();
           }

       }

coroutines 运行了一段时间。所有 6 个gameobjectscoroutine 同时结束。我想在这些coroutines 结束后将事件发送回script A。但是如果我从script B 发送一个事件,该事件将被触发 6 次。解决此问题的最佳方法是什么?

【问题讨论】:

    标签: c# unity3d events coroutine


    【解决方案1】:

    您可以让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() 返回的协程对象。

    【讨论】:

      【解决方案2】:

      一种方法是将Action 传递给协程以在协程完成时调用,然后在该Action 中减少一个所有Actions 共有的计数器,然后如果该计数器为零,请调用您要调用的事件:

      // 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的起始值。为了安全起见,您可能希望在调用CallCoroutine 之前完成设置counter 的起始值。所以,是这样的:

      // 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);
      }
      

      【讨论】:

        【解决方案3】:

        你可以给你的 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; }
        
           }
        
        }
        

        【讨论】:

        • 这不起作用,因为它会在第一个调用的协程开始后触发。 Asker 希望它在最后一个完成的协程结束后触发。
        • @Ruzihm 提问者写道,所有 6 个协程确实同时结束——在这种情况下,只需要一个回调。虽然我承认这是一种 hack,但在这种情况下它仍然可以工作。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多