首页 > 解决方案 > Unity 中的队列方法和协程

问题描述

我正在尝试创建一个方法队列,一旦前一个方法完全执行,该方法就会开始执行下一个方法,该方法队列对于除 IEnumerator 返回类型一之外的所有场景都可以正常工作。

以下是我尝试一个接一个执行的方法列表。

 public void CallMethod()
{
    
    
    UnityMainThreadDispatcher.Schedule(() =>
    {
        ShowMessage("Minimum!");
    }
    , 0.3f);
    
    Debug.Log("Winner of this round is " + winnerPlayer.GetName());
    UnityMainThreadDispatcher.Schedule(() => 
    {
        scoreboardPopup.ShowPopup();
    }
    , 5.0f);
    
    UnityMainThreadDispatcher.Schedule(() =>
    {
        CardDistributionAnimation.instance.PlayCardDistributionAnimation(false);
    }, 0.5f);

    UnityMainThreadDispatcher.Schedule(() => StartNextRound(),0.5f);
   
    Debug.Log("Call Minimum Completed");
    
}

UnityMainThread 类

public class UnityMainThreadDispatcher : MonoBehaviour
{

    private Queue<IEnumerator> coroutineQueue = new Queue<IEnumerator>();
    public delegate void Task();
    
    
public static void Schedule(Task task, float delay)
    {
        Debug.Log("Task Scheduled " + task.Method);
        //Instance().Enqueue(task, delay);
        Instance().coroutineQueue.Enqueue(DoTask(task, delay));

    }

    private static IEnumerator DoTask(Task task, float delay)
    {
        Debug.Log("Inside DoTask Coroutine");
        yield return new WaitForSeconds(delay);
        task();
    }

    IEnumerator CoroutineCoordinator()
    {
        while (true)
        {
            while (coroutineQueue.Count > 0)
                yield return StartCoroutine(coroutineQueue.Dequeue());
            yield return null;
        }
    }


    private static UnityMainThreadDispatcher _instance = null;

    public static bool Exists()
    {
        return _instance != null;
    }

    public static UnityMainThreadDispatcher Instance()
    {
        if (!Exists())
        {
            throw new Exception("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
        }
        return _instance;
    }

    private void Start()
    {
        StartCoroutine(CoroutineCoordinator());
    }

}

CoroutineQueue 只会在其队列中启动下一个方法,一旦前一个方法成功执行,除了以下方法外,它对所有方法都正常工作

CardDistributionAnimation.instance.PlayCardDistributionAnimation(false);

这是因为 PlayCardDistributionAnimation 在 Coroutine 方法上执行。

PlayCardDistributionAnimation 方法

 public void PlayCardDistributionAnimation(bool isNewGame)
    {
        
        generateCards(isNewGame);
        StartCoroutine(DistributeCardsToPlayer());
    }

 public void generateCards(bool isNewGame)
    {
        int size = 0;
        if (generatedCards.Count > 0)
            generatedCards.Clear();
        GameObject distributionobject = GameObject.Find("CardDistributionObject");
        if (isNewGame)
            size = playersPosition.Count * 2;
        else
            size = playersPosition.Count;
        for (int i = 0; i < size; i++)
        {
            GameObject vector2 = Instantiate(cardsBack, distributionobject.transform);
            generatedCards.Add(vector2);
            vector2.SetActive(true);
        }

    }
  private IEnumerator DistributeCardsToPlayer()
    {
        Debug.Log("Inside Distribute Cards To Player");
        for(int i=0;i< generatedCards.Count();i++)
        {
            var cover = Instantiate(cardsBack, generatedCards[i].transform.position, Quaternion.identity, generatedCards[i].transform);
            cover.GetComponent<RectTransform>().localScale = Vector3.one;
            var tween = cover.transform.DOMove(playersPosition[i%(playersPosition.Count)].transform.position, 0.5f);
            tween.OnComplete(() => Destroy(cover));
            yield return new WaitForSeconds(0.6f);

        }
        yield return new WaitForSeconds(1f);
        //playersPosition.First().SetActive(true);

        foreach (GameObject gameObject in generatedCards)
            Destroy(gameObject);
        isCardDistributionCompleted = true;
        Debug.Log("Card Distribution method executed succussfully");
    }

在我的协程完全执行之前,我不确定我如何无法停止其他方法的执行。我尝试了几种方法,但到目前为止都没有奏效,任何建议都会非常有帮助。

标签: c#unity3dcoroutine

解决方案


首先,您的委托Task非常令人困惑.. 已经有一个Task用于运行异步任务的类。

这也是非常不必要的,因为已经有一个参数较少的委托类型 void: Action;)

然后我会创建一个重载,它只需要协程,就像

public class UnityMainThreadDispatcher : MonoBehaviour
{
    private Queue<IEnumerator> coroutineQueue = new Queue<IEnumerator>();

    public static void Schedule(IEnumerator routine, float delay)
    {
        Instance().coroutineQueue.Enqueue(DoTask(routine,delay));
    }
    
    public static void Schedule(Action task, float delay)
    {
        Debug.Log("Task Scheduled " + task.Method);
        //Instance().Enqueue(task, delay);
        Instance().coroutineQueue.Enqueue(DoTask(task, delay));

    }

    private static IEnumerator DoTask(Action task, float delay)
    {
        Debug.Log("Inside DoTask Coroutine");
        yield return new WaitForSeconds(delay);
        task();
    }

    private static IEnumerator DoTask(IEnumerator task, float delay)
    {
        Debug.Log("Inside DoTask Coroutine");
        yield return new WaitForSeconds(delay);
        yield return StartCoroutine(task);
    }

    private IEnumerator Start()
    {
        while (true)
        {
            while (coroutineQueue.Count > 0)
                yield return StartCoroutine(coroutineQueue.Dequeue());

            yield return null;
        }
    }


    private static UnityMainThreadDispatcher _instance = null;

    public static bool Exists()
    {
        return _instance != null;
    }

    public static UnityMainThreadDispatcher Instance()
    {
        if (!Exists())
        {
            throw new Exception("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
        }
        return _instance;
    }
}

然后宁愿做你的方法

public void PlayCardDistributionAnimation(bool isNewGame)
{ 
    StartCoroutine(PlayCardDistributionAnimationRoutine(isNewGame));
}

public IEnumerator PlayCardDistributionAnimationRoutine(bool isNewGame)
{   
    generateCards(isNewGame);
    yield return DistributeCardsToPlayer();
}

对于预定版本,请改用例程

UnityMainThreadDispatcher.Schedule(
    CardDistributionAnimation.instance.PlayCardDistributionAnimationRoutine(false), 
    0.5f
);

有趣的是,您使用了主线程分派器——它实际上用于将来自其他线程的异步内容分派回 Unity 主线程——并将其变成完全不同的东西^^


注意:在智能手机上打字,但我希望这个想法很清楚


推荐阅读