본문 바로가기

C#,Unity

Unity - 순차적으로 진행되는 코루틴 대기열 만들기(Queue 활용)

유니티에서 코루틴을 다루다 보면 WaitforSecond나 WaitUntil같이 일정 시간, 혹은 일정 조건까지 기다리게 하는 대기문을 사용하는 경우가 잦습니다.

'몇 초간 기다려라' 혹은 '무엇이 어떻게 될 때까지 기다려라' 외에도 '이 코루틴이 끝날 때까지 기다려라'라는 대기 조건도 있는데,

마지막의 경우는 yield return startcoroutine()으로 구현할 수 있습니다.

 

 

이번에는 여러 코루틴을 받아올 때마다 선입선출 방식으로 하나하나 실행하게 하는 스크립트를 만들어보겠습니다.

public class TempManager : MonoBehaviour
{
  private static TempManager instance = null;
  public static TempManager Instance {  get { return instance; } }
  private void Awake() => instance = this;	//임시 싱글톤 생성


  private Queue<IEnumerator> CoroutineQueue= new Queue<IEnumerator>();	//코루틴 목록
  private Queue<string> CoroutineNames= new Queue<string>();	//표시용 이름 목록
  
  public void AddCoroutineQueue(IEnumerator cor,string name)	//대기열에 코루틴 삽입
  {
    CoroutineQueue.Enqueue(cor);
    CoroutineNames.Enqueue(name);
    UpdateQueueText();			//큐에 코루틴과 이름을 넣고 디버그용 이름 목록 초기화
    
    if (WorkingCoroutine == null)	//대기열 코루틴이 작동하고 있지 않다면
    {								//새로 코루틴을 시작
      WorkingCoroutine = WorkingQueue();
      StartCoroutine(WorkingCoroutine);
    }
  }
  private IEnumerator WorkingCoroutine = null;
  private IEnumerator WorkingQueue()
  {
    while (CoroutineQueue.Count > 0)	//큐가 남아있는 한 반복
    {
      yield return StartCoroutine(CoroutineQueue.Dequeue());//대기열 하나 완료하면
      CoroutineNames.Dequeue();								//대기열 이름도 할당 해제
      UpdateQueueText();
      yield return null;
    }
    WorkingCoroutine = null;			//큐가 전부 동나면 코루틴 할당 해제
  }

  [SerializeField] private TextMeshProUGUI QueueText = null;	//디버그 이름 출력용
  private void UpdateQueueText()
  {
    var _list = CoroutineNames.ToList();
    StringBuilder _stb= new StringBuilder();
    for(int i=0;i< _list.Count;i++)
    {
      _stb.Append(_list[i]);
      if(i<_list.Count-1)_stb.Append("<br>");
    }
    QueueText.text = _stb.ToString();
  }
}
public class test : MonoBehaviour	//상하좌우 이동 코루틴을 전달
{
  [SerializeField] private Transform MovingObj = null;
  public void Click_up()=> TempManager.Instance.AddCoroutineQueue(moveobj(Vector2.up),"move_up");
  public void Click_right() => TempManager.Instance.AddCoroutineQueue(moveobj(Vector2.right), "move_right");
  public void Click_down() => TempManager.Instance.AddCoroutineQueue(moveobj(Vector2.down), "move_down");
  public void Click_left() => TempManager.Instance.AddCoroutineQueue(moveobj(Vector2.left), "move_left");

  private IEnumerator moveobj(Vector2 dir)
  {
    float _speed = 3.0f;
    float _time = 0.0f;
    while (_time < 1.0f)
    {
      MovingObj.Translate(dir * _speed*Time.deltaTime);
      _time += Time.deltaTime;
      yield return null;
    }
  }
}

 

버튼을 눌러 이동 코루틴을 전달할 때마다 큐에 해당 코루틴이 누적되고,

선입선출 방식으로 이동 명령을 하나하나 다 소화시키고 있습니다.

 

 

 

 

이를 활용해 각종 UI의 조작 결과를 겹치지 않고 순차적으로 연결되듯이 만들 수도 있습니다.