본문 바로가기

[Unity3D] 코루틴(Coroutine)

·
2019. 10. 1. 13:46
반응형

코루틴(Coroutine)

코루틴(Coroutine)은 실행을 일시 정지하고 유니티로 제어를 넘겨주는 함수입니다.

일반적인 함수는 업데이트의 한 프레임에서 실행이 됩니다.

하지만 코루틴을 사용하면 시간에 따른 증가/감소, 다른 연산을 할때까지 대기 등을

구현할 때 유용하게 사용될 수 있습니다.

※ 단순히 함수에 딜레이를 줄 경우에는 코루틴보다 Invoke를 사용하는 것을 추천합니다.

 

코루틴 선언

코루틴은 기본적으로 IEnumerator의 반환형과 함수 안에 yield return 구문을 포함해서 선언합니다.

코루틴의 실행은 StartCoroutine(function()) 또는 StartCoroutine("function Name") 으로 실행합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CoroutineExample : MonoBehaviour 
{
    IEnumerator coroutine;
 
    void Start () 
    {
        coroutine = CoroutineTest();
        StartCoroutine(coroutine);
    }
    
    IEnumerator CoroutineTest()
    {
        yield return null;
    }
}
cs

IEmumerator : C#에서 컬렉션을 반복하기 위한 인터페이스입니다. MoveNext()로 컬렉션을 순환합니다.
코루틴을 시작하기 위해서는 IEnumerator를 인자로 넘겨주고 yield 문을 만날때까지 코루틴 내부에 있는 코드를 실행합니다.
yield return : 코루틴의 실행을 일시 정지하고 제어를 유니티에 넘겨줍니다. 이 지점에서 다시 코드가 실행됩니다.

 

이해를 돕기 위해 예를 들어보겠습니다.

5초동안 1초 간격으로 시간을 출력하는 타이머 코루틴 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class CoroutineTest : MonoBehaviour
{
    private IEnumerator coroutine;
 
    // Use this for initialization
    void Start()
    {
        coroutine = RunTimer(5);
        StartCoroutine(coroutine);
    }
 
    IEnumerator RunTimer(int maxTime)
    {
        Debug.Log("Timer Start");
        int time = 0;
 
        while (time < maxTime)
        {
            Debug.Log("time : " + time);
 
            yield return new WaitForSeconds(1f);
 
            time++;
        }
 
        Debug.Log("Timer End");
    }
}
 
cs

 

실행 결과는 다음과 같습니다.

타이머 코루틴 실행결과

 

코루틴 시작/일시정지

코루틴은 실행중에 StopCoroutine(coroutine)를 사용해서 일시 정지할 수도 있습니다.

일시 정지된 코루틴은 다시 StartCoroutine(coroutine)로 실행하면 일시 정지된 시점부터 다시 시작됩니다.

특정 조건에서 코루틴을 빠져나가려면 yield break를 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class CoroutineTest : MonoBehaviour
{
    private IEnumerator coroutine;
 
    // Use this for initialization
    void Start()
    {
 
    }
 
    IEnumerator RunTimer(int maxTime)
    {
        Debug.Log("Timer Start");
        int time = 0;
 
        while (time < maxTime)
        {
            Debug.Log("time : " + time);
 
            yield return new WaitForSeconds(1f);
 
            time++;
        }
 
        Debug.Log("Timer End");
    }
 
    public void StartTimer()
    {
        if (coroutine == null)
        {
            coroutine = RunTimer(5);
        }
 
        StartCoroutine(coroutine);
    }
 
    public void PauseTimer()
    {
        StopCoroutine(coroutine);
    }
}
 
cs

 

코루틴 반환 타입

yield return 구문은 지정된 초만큼 대기하는 WaitForSeconds 이외에도 여러가지 반환 타입을 사용할 수 있습니다.

다음은 코루틴 반환 타입 목록을 나타냅니다.

코루틴 반환 타입 설명
yield return null 다음 프레임까지 대기
yield return new WaitForSeconds(float time) 지정한 초만큼 대기
yield return new WaitForFixedUpdate() 다음 물리 프레임까지 대기
yield return new WaitForEndOfFrame() 모든 렌더링 작업이 끝날 때까지 대기
yield return new WaitUntil(Func<bool> predicate) 조건을 만족할 때까지 대기
yield return new WaitWhile(Func<bool> predicate) 조건을 만족하지 않을 때까지 대기
yield return StartCoroutine(string name) 다른 코루틴이 끝날 때까지 대기

 

코루틴 장단점

장점

코루틴을 사용하면 매 프레임마다 Update에서 처리할 필요가 없어지므로 프레임 드랍 같은 성능상의 저하를 막아줍니다.

코루틴을 사용하면 가독성 있는 코드가 만들어 집니다.

 

단점

StartCoroutine() 호출 시 가비지가 생성이 되므로 코루틴을 많이 호출하게 되면 가비지가 많이 생성이 됩니다. (아래 코루틴 최적화 방법 참조)

 

코루틴 최적화

yield return 구문이 여러번 사용될 경우에는 새로운 인스턴스를 계속 만들기 때문에 많은 가비지가 생성이 됩니다. 따라서 new를 사용해서 새로운 객체를 계속 생성하는것 보다 캐싱해서 사용하는 것이 효율적입니다.

1
2
3
4
5
6
7
8
9
10
11
12
IEnumerator Run()
{
    int count = 0;
    WaitForSeconds waitForSeconds = new WaitForSeconds(1f);
 
    while (true)
    {
        Debug.Log(count);
 
        yield return waitForSeconds;
    }
}
cs

 

참고 
 

Unity - Manual: Coroutines

Creating and Destroying GameObjects Coroutines When you call a function, it runs to completion before returning. This effectively means that any action taking place in a function must happen within a single frame update; a function call can’t be used to co

docs.unity3d.com

반응형
블로그 이미지
Frontend Engineer

댓글