[Unity] 코루틴(Coroutine) 총 정리 _ (feat. RPG 포션 딜레이 예제)

반응형
반응형

[목차]

#0 코루틴(Coroutine)을 사용하는 이유

#1 코루틴 사용 예제

#1.1 코루틴 선언 IEnumerator

#1.2 코루틴 실행 StartCoroutine()

#2 코루틴 중지

#3 yield return VS yield break

 

* 다음 포스팅은 개인적인 공부 내용을 기록한 글이기에, 잘못된 내용이 있을 수 있으며 지속적으로 수정해 나갈 예정입니다.


#0 코루틴(Coroutine)을 사용하는 이유

유니티에서 Update() 메소드는 화면에 변화를 일으킬 때 사용 하고는 합니다. Update() 메서드는 매 프레임마다 호출이 되기에, 60fps라면 1초에 60번이 호출 됩니다. 그런데 만약 5초동안 지연을 시켜야 하는 상황이 발생 한다면 어떻게 될까요?

Update() 메서드를 5 * 60 = 300번 호출하면 될 것입니다. 하지만 이러한 딜레이가 발생하는 상황을 모두 Update() 구문에 정의하면 기기의 성능에 따라서 프레임 드랍(Frame Drop) 을 발생하고 맙니다. 이 때 코루틴(Coroutine)을 사용하면, Update() 함수를 굳이 300번이나 호출하지 않고도 시간을 지연 시키는 것이 가능합니다.


#1 코루틴 사용 예제

코루틴을 사용하지 않은 예제와, 코루틴을 사용한 예제 두 가지 소스코드로 나누어 비교해 보도록 하겠습니다.

RPG게임에서 포션을 마시고 다음 포션을 마실 때 까지의 딜레이를 5초를 설정하여 포션을 연속으로 마시지 못하게 하는 상황을 예시로 들겠습니다.

우선, 빈 오브젝트(Character)와 C#스크립트(PotionDelay) 를 하나 씩 생성해 준 뒤 스크립트를 부착해 줍니다. 

아래는 코루틴을 사용하지 않은 PotionDelay 예제 입니다.

 

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

public class PotionDelay : MonoBehaviour
{
    public bool isDelay;
    public float delayTime = 5.0f;
    public float accumTime;

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            if(isDelay == false)
            {
                isDelay = true;
                Debug.Log("HP가 50 회복 되었습니다.");
            }
            else
            {
                Debug.Log("아직 포션을 사용할 수 없습니다.");
            }
        }

        if(isDelay)
        {
            accumTime += Time.deltaTime;
            if(accumTime >= delayTime)
            {
                accumTime = 0.0f;
                isDelay = false;
            }
        }
    }
}

 

Space 를 누르면 isDelay 변수가 false인 경우 "HP가 50 회복 되었습니다." 라는 문구를 출력하고, isDelay 변수가 true인 경우 "아직 포션을 사용할 수 없습니다." 라는 문구를 출력합니다. 

그렇게 어려운 코드는 아니기에 설명은 생략 하도록 하겠습니다. 이제 이 코드를 코루틴을 사용해 수정해 보도록 하겠습니다.

 

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

public class PotionDelay : MonoBehaviour
{
    public bool isDelay;
    public float delayTime = 5.0f;
    public float accumTime;

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            if(isDelay == false)
            {
                isDelay = true;
                Debug.Log("HP가 50 회복 되었습니다.");
                StartCoroutine(Drink());
            }
            else
            {
                Debug.Log("아직 포션을 사용할 수 없습니다.");
            }
        }
    }

    IEnumerator Drink()
    {
        yield return new WaitForSeconds(5.0f);
        isDelay = false;
    }
}

 

실행 결과는 동일합니다. 이제, 코루틴 사용방법을 설명 하도록 하겠습니다.


#1.1 코루틴 선언 IEnumerator

코루틴의 선언반환형을 IEnumerator 로 설정 합니다. 그리고 일반적인 함수와 달리 반환 시 return 이 아닌, yield return 으로 돌려 주어야 합니다.

yield return 뒤에는 반환 시간을 명시해 주는데, 명시한 반환 시간 만큼 유니티에 제어권을 돌려주어 코드 동작을 중지시키고, 시간이 지나면 다음 줄 부터 다시 코루틴이 동작합니다. 대표적인 반환 시간의 타입은 다음과 같습니다.

 

[1] null : 1frame 만큼 코드 동작을 중지 시킵니다.

[2] new WaitForSeconds(s) : s초 만큼 동작을 중지 시킵니다. 

(* 다른 반환 타입의 종류가 궁금하시다면, 유니티 공식 사이트의 메뉴얼을 참고해 주세요)


#1.2 코루틴 실행 StartCoroutine()

코루틴의 실행 방법은 일반 함수와는 달리, StartCoroutine() 메소드를 이용하여 괄호 안에 코루틴이름() 을 넣어 주어야 합니다.

혹은 아래와 같이 "코루틴 이름" 으로도 실행이 가능합니다.

StartCoroutine("Drink");

#2 코루틴 중지

다음으로, 코루틴을 중지 시키는 방법에 대해서 정리 하도록 하겠습니다. 아래는 코루틴이 1초마다 로그를 출력하고, space 키를 누르면 코루틴을 중지하는 예제입니다.

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

public class CourutineTest : MonoBehaviour
{

    void Start()
    {
        StartCoroutine("Test");
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            StopCoroutine("Test");
            Debug.Log("STOP CORUTINE");
        }
    }


    IEnumerator Test()
    {
        int i = 1;
        while (true)
        {
            yield return new WaitForSeconds(1.0f);
            Debug.Log(i + "초");
            i++;
        }
    }
}

코루틴은 StopCoroutine() / StopAllCoroutines() 함수로 중지 시킬 수 있습니다.

StopCoroutine() 함수는 해당하는 코루틴만 중지시키고, StopAllCoroutines() 함수는 모든 코루틴을 중지시킵니다.


#3 yield return VS yield break

마지막으로 yield return 과 yield break 의 차이에 대해서 설명하고 마치도록 하겠습니다.

#1에서 yield return은 지정한 시간만큼 유니티에 제어권을 넘겨주어 대기하는 키워드라고 설명했습니다. yield return과 달리 yield break 문은 해당 키워드를 만나자 마자 코루틴을 빠져나옵니다. 아래 코드를 실행시켜 보면,

public class CourutineTest : MonoBehaviour
{
    void Start()
    {

        StartCoroutine(Return());
        StartCoroutine(Break());
    }

    IEnumerator Return()
    {
        Debug.Log("Return() 1");
        yield return null;
        Debug.Log("Return() 2");
    }

    IEnumerator Break()
    {
        Debug.Log("Break() 1");
        yield break;
        Debug.Log("Break() 2");
    }

}

yield break; 아래의 Debug.Log("Break() 2")는 출력되지 않고 , 코루틴이 끝나 버렸음을 확인 가능합니다.


반응형

댓글

Designed by JB FACTORY