[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