프로그래밍 농장

코루틴(Coroutine)과 IEnumerator [ Unity ] 본문

Unity

코루틴(Coroutine)과 IEnumerator [ Unity ]

Tennessee201 2022. 7. 4.
728x90

1. 코루틴 (Coroutine)

코루틴은 시간의 경과에 따른 절차적 단계를 수행하는 로직을 구현하는 데 사용되는 함수이다. 시간의 경과에 따른 절차적 단계에 대한 로직을 구현하는 것은 Update() 함수들에서도 가능하다. 매 프레임마다 호출되는 로직은 Update()에서 구현하면 된다. 하지만 초당 호출이나, 매 프레임마다 호출이 필요하지 않은부분을 매 프레임마다 호출하는 것은 바람직한 로직이 아니다. 

추후 유지보수를 위하여 한 컴포넌트 내에서 Update() 함수와 별도로 일시적으로 돌아가는 서브 동작을 구현하거나, 어떤 다른 작업이 처리되는 것을 기다리는 기능을 구현하는데 쓰이는 것이 바로 코루틴이다. 

코루틴(Coroutine)은 함수를 호출한다. -> 함수는 한 프레임에 호출되어 완료가 된다. 이에 IEnumerator 형식을 반환 값으로 가지는 함수를 사용한다. IEnumerator는 함수 내부에 실행을 중지하고, 다음 프레임에서 실행을 재개할 수 있는 yield return 구문을 사용하게 된다. 


2. yield return

: 코루틴에서 동작하던 제어권을 유니티에 다시 돌려준다는 뜻 

yield return 구문에는 다음과 같은 YieldInstruction 클래스를 사용한다. 

yield return null : 다음 프레임에 실행을 재개한다.

yield return new WaitForSeconds : 지정된 시간 후에 재개한다.

yield return new WaitForSecondsRealtime :  Time.timescale 값에 영향을 받지 않고 지정된 시간 후에 재개한다. 

yield return new WaitForFixedUpdate : 모든 스크립트에서 모든 FixedUpdate가 호출된 후에 재개한다.

yield return new WaitForEndOfFrame : 모든 카메라와 GUI가 렌더링을 완료하고, 스크린에 프레임을 표시하기 전에 호출된다. 

yield return StartCoroutine() : 코루틴을 연결하고 코루틴이 완료된 후에 재개한다.


3. StartCoroutine()과 StopCoroutine()

Coroutinedms 3개의 전달 인자를 사용한다.

3.1. StartCoroutine() : string MethodName을 사용하는 경우, 두 번째 매개변수로 전달 인자를 사용한다. 

Coroutine StartCoroutine(string MethodName, object = null)

Coroutine StartCoroutine(IEnumerator routine)

Coroutine StartCoroutine(Coroutine routine)

 

3.2. StopCoroutine()

StopCoroutine(string MethodName)

StopCoroutine(IEnumerator routine)

StopCoroutine(Coroutine routine)

 

유니티는 코루틴을 사용할 때, 전달 인자를 혼합하여 사용하지 말 것을 권장한다.   

만약 StartCoroutine(string MethodName)을 사용했다면, StopCoroutine(string MethodName)을 사용하여 중지한다. 실제 사용해 보면, 대상 코루틴을 찾지 못한다.


4. Coroutine 예제

4.1 StartCoroutine

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    float time;
    IEnumerator myCoroutine;
    // Start is called before the first frame update
    void Start()
    {
        myCoroutine = MyCoroutine(1.0f);
         StartCoroutine(myCoroutine);
        time = 3.0f;
    }

    // Update is called once per frame
    void Update()
    {
        time -= Time.deltaTime;
        if (time < 0)
        {
            StopCoroutine(myCoroutine);
        }
    }

    IEnumerator MyCoroutine(float t)
    {
        Debug.Log("MyCoroutine;" + t);
        yield return StartCoroutine(MySecondCoroutine(.1f));

        while (true)
        {
            Debug.Log("MyCoroutine");
            yield return new WaitForSeconds(0.2f);
        }
    }

    IEnumerator MySecondCoroutine(float t)
    {
        Debug.Log("MySecondCoroutine;" + t);
        yield return new WaitForSeconds(0.1f);
    }
}

 

4.2 StopCoroutine

코루틴을 정지하는 방법은 몇 가지 방법이 있으며, 확실한 방법은 코루틴에 대한 인스턴스를 가지고 있는 것이다.

상황에 맞는 코루틴을 사용한다.

 

4.2.1 StartCoroutine(IEnumerator) → StopCoroutine(IEnumerator) 

StartCoroutine(MyCoroutine()) → StopCoroutine(MyCoroutine())은 동작하지 않는다.

 

4.2.2 StopCoroutine(stringName)

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    float time;
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine("MyCoroutine", 1.0f);
        time = 3.0f;
    }

    // Update is called once per frame
    void Update()
    {

        time -= Time.deltaTime;
        if (time < 0)
        {
            StopCoroutine("MyCoroutine");
        }
    }

    IEnumerator MyCoroutine(float t)
    {
        Debug.Log("Coroutine;" + t);
        yield return new WaitForSeconds(0.1f);

        while (true)
        {
            Debug.Log("Coroutine");
            yield return new WaitForSeconds(0.2f);
        }
    }
}

 

4.2.3 IEnumerator 변수

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    float time;
    IEnumerator myCoroutine;
    // Start is called before the first frame update
    void Start()
    {
        myCoroutine = MyCoroutine(1.0f);
         StartCoroutine(myCoroutine);
        time = 3.0f;
    }

    // Update is called once per frame
    void Update()
    {
        time -= Time.deltaTime;
        if (time < 0)
        {
            StopCoroutine(myCoroutine);
        }
    }

    IEnumerator MyCoroutine(float t)
    {
        Debug.Log("Coroutine;" + t);
        yield return new WaitForSeconds(0.1f);

        while (true)
        {
            Debug.Log("Coroutine");
            yield return new WaitForSeconds(0.2f);
        }
    }
}

 

 

4.2.4 Coroutine 변수

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{    
    float time;
    Coroutine myCoroutine;
    // Start is called before the first frame update
    void Start()
    {
        myCoroutine = StartCoroutine(MyCoroutine(1.0f));
        time = 3.0f;
    }

    // Update is called once per frame
    void Update()
    {
        time -= Time.deltaTime;
        if (time < 0)
        {
            StopCoroutine(myCoroutine);
        }
    }

    IEnumerator MyCoroutine(float t)
    {
        Debug.Log("Coroutine;" + t);
        yield return new WaitForSeconds(0.1f);

        while (true)
        {
            Debug.Log("Coroutine");
            yield return new WaitForSeconds(0.2f);
        }
    }
}

 

+ 코루틴을 생성할떄, gameObject를 생성하지않거나, Awake() 이후 바로 코루틴을 돌리게 되면 제어권을 유니티가 갖지 못하여 응답없음이나 무한루프 상태에 빠지게 되는 문제가 발생한다. 

728x90