[섹션 11] Coroutine(코루틴)

<Coroutine 코루틴>

 

  • Coroutine 개념

: 굉장히 큰 작업을 하나의 로직으로 해야할 때, 한번에 처리하기엔 너무 많은 시간이 든다.

 -> 분할하여 작업하여 일정 시간 내에 끝내야 할 때 어떻게 처리해야하는가?

ex) 아래의 코드를 보면 일정 작업을 1000000 만큼 반복하여 진행하고 있다. 10000번씩 끊어서 실행시키고자 할때 어떻게 해야하는가?

void VeryComplicated()
    {
        for (int i = 0; i < 1000000; i++)
        {
            // 굉장히 힘든 작업
            Debug.Log("Hello");
        }
    }

 

=> 일시 정지를 시킨 후 모든 상태를 복원된 상태로 시작을 할 수 있음 

 

1. 다음과 같이 CoroutineTest class를 생성하여 실험해 본다. 

CoroutineTest는 IEnumerable을 상속 받아서 인터페이스를 다음과 같이 정의하였다. 

이때 yield를 붙여주어 return을 하면 다음과 같이 console창에 순서대로 1,2,3,4가 나오는 것을 확인할 수 있다. 

 

*GameScene.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameScene : BaseScene
{
    class CoroutineTest : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            yield return 1;
            yield return 2;
            yield return 3;
            yield return 4;

        }
    }
    protected override void Init()
    {
        base.Init();
        // Scene Type setting
        SceneType = Define.Scene.Game;
        // TEMP
        Managers.UI.ShowSceneUI<UI_Inven>();

        // Coroutine Test
        CoroutineTest test = new CoroutineTest();
        foreach(int t in test)
        {
            Debug.Log(t);
        }
    }

    // 해당 Scene이 종료됐을 때 날려줘야하는 것을 정의
    public override void Clear()
    {
        
    }

}

 

2. 이때 test 를 int로 받아오지않고 var 형식으로 받아오면 GameObject 형식으로 반환한다. 위에서 한 것은 GameObject를 boxing하여 int형식으로 변환한 것이다. 

 

3. 다음과 같이 Class를 반환하여도 값이 나오는 것을 확인할 수 있다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameScene : BaseScene
{
    class Test
    {
        public int Id = 0;
    }
    class CoroutineTest : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            yield return new Test() { Id = 1 };
            yield return new Test() { Id = 2 }; ;
            yield return new Test() { Id = 3 }; ;
            yield return new Test() { Id = 4 }; ;

        }
    }
    protected override void Init()
    {
        base.Init();
        // Scene Type setting
        SceneType = Define.Scene.Game;
        // TEMP
        Managers.UI.ShowSceneUI<UI_Inven>();

        // Coroutine Test
        CoroutineTest test = new CoroutineTest();
        foreach(System.Object t in test)
        {
            Test value = (Test)t;
            Debug.Log(value.Id);
        }
    }

    // 해당 Scene이 종료됐을 때 날려줘야하는 것을 정의
    public override void Clear()
    {
        
    }

}

 

4. 그렇다면 Coroutine에서 완전히 멈추고 싶으면 yield break; 를 해줘야한다. 

 

 

  • 실제 적용

코루틴의 특징 정리

1. 함수의 상태를 저장/복원이 가능

   -> 엄청 오래 걸리는 작업을 잠시 끊거나

   -> 원하는 타이밍에 함수를 잠시 Stop/복원하는 경우

2. return -> 우리가 원하는 타입으로 가능(class도 가능)

 

어떻게 적용?

예를들어, 어떤 아이템을 만들어서 DB에 저장해야할 때 DB에 저장을 하고 응답을 받은 뒤에 다음 로직으로 넘어가야한다. -> 이때 잠시 멈추기 가능

 

시간관리에도 유용

: 4초 후에 Explore 된다고 할때 하나하나 매번 틱 마다 4초를 count하여 로직을 실행하는 것은 매우 휴율이 떨어진다. 

-> 코루틴 유용

 

1. 4초를 기다린 후 로직을 실행하는 함수를 만들어보자. Coroutine 함수는 IEnumerator를 이용하여 만든다.

유니티 엔진 자체에 Coroutine을 사용한 WaitForSceconds라는 클래스를 return할 수 있다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameScene : BaseScene
{
    protected override void Init()
    {
        base.Init();
        // Scene Type setting
        SceneType = Define.Scene.Game;
        // TEMP
        Managers.UI.ShowSceneUI<UI_Inven>();

        StartCoroutine("ExplodeAfterSeconds", 4.0f);
    }

    IEnumerator ExplodeAfterSeconds(float seconds)
    {
        Debug.Log("Explode Enter");
        yield return new WaitForSeconds(seconds);
        Debug.Log("Explode Execute!!!");

    }

    // 해당 Scene이 종료됐을 때 날려줘야하는 것을 정의
    public override void Clear()
    {
        
    }

}

다음과 같이 4초 후에 Explode Execute!! 가 console창에 뜨는 것을 알 수 있다. 

 

2. 다음과 같이 새로운 코루틴을 작성하여 2초후에 모든 코루틴 작업을 취소 시킬 수 있다. 

* GameScene.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameScene : BaseScene
{
    Coroutine co;
    protected override void Init()
    {
        base.Init();
        // Scene Type setting
        SceneType = Define.Scene.Game;
        // TEMP
        Managers.UI.ShowSceneUI<UI_Inven>();

        Coroutine co = StartCoroutine("ExplodeAfterSeconds", 4.0f);
        StartCoroutine("coStopExplode", 2.0f);
    }

    IEnumerator coStopExplode(float seconds)
    {
        Debug.Log("Stop Enter");
        yield return new WaitForSeconds(seconds);
        Debug.Log("Stop Execute!!");
        if (co != null)
        {
            StopCoroutine(co);
            co = null;
        }

    }
    IEnumerator ExplodeAfterSeconds(float seconds)
    {
        Debug.Log("Explode Enter");
        yield return new WaitForSeconds(seconds);
        Debug.Log("Explode Execute!!!");
        yield return null;

    }

    // 해당 Scene이 종료됐을 때 날려줘야하는 것을 정의
    public override void Clear()
    {
        
    }

}

'Development > 유니티' 카테고리의 다른 글

[섹션8] Scene Manager #2  (0) 2021.08.06
[섹션8] Scene Manager  (0) 2021.08.06
[섹션7] 인벤토리 실습 & 코드 정리  (0) 2021.08.01
[섹션 7] UI Manager  (0) 2021.07.30
[섹션7] UI - UI 자동화  (0) 2021.07.29