
일반적으로 메서드를 호출하면 실행을 완료한 뒤 호출한 메서드에 제어와 선택적 반환 값을 반환한다. 메서드 내에서 발생한 모든 행동은 단일 프레임 업데이트 내에서 발생해야 한다.
하지만 코루틴을 사용하면 작업을 다수의 프레임에 분산할 수 있다. 코루틴은 실행을 일시 정지하고 제어를 Unity에 반환하지만, 중단한 부분에서 다음 프레임을 계속할 수 있다.
코루틴은 스레드가 아니다. 코루틴의 동기 작업은 메인 스레드에서만 실행된다.
예를 들어, 오브젝트의 알파 값을 점점 줄여나가는 코드를 작성한다고 해보자.
private void Fade()
{
var color = renderer.material.color;
for(float alpha = 1f; alpha >= 0f; alpha -= 0.1f)
{
color.a = alpha;
renderer.material.color = color;
}
}
위의 코드는 알파 값을 점점 줄여나가는 데 실패한다. 페이드 효과를 주기 위해서는 프레임의 시퀀스에 알파 값을 줄여나가야 한다. 하지만 위의 코드는 단일 프레임 업데이트 내에서 전체를 실행한다.
이런 상황에서는 코루틴을 사용하는 것이 제격이다. 코루틴으로 작성한 다음 코드를 보자.
private IEnumerator Co_Fade()
{
var color = renderer.material.color;
for(float alpha = 1f; alpha >= 0f; alpha -= 0.1f)
{
color.a = alpha;
renderer.material.color = color;
yield return new WaitForSeconds(0.1f);
}
}
코루틴은 IEnumerator를 반환하는 메서드다. 반환형을 IEnumerator으로 선언한 코루틴은 반드시 yield를 사용하여 return을 반드시 해야 한다.
보통 대기 시간이 없는 경우에는 null을 반환하게 되며, 이 경우 한 프레임의 대기 시간을 가진다. 이것은 코루틴이 스레드가 아님을 다시 한번 확인할 수 있는 명목이다.
코루틴을 사용하기 위해서는 System.Collections 이름 공간의 사용을 선언해야 한다.
using System.Collections;
...
private IEnumerator Co_Print()
{
yield return new WaitForSeconds(1f);
Debug.Log("1초 후에 이 로그가 출력됩니다.");
}
코루틴을 실행하기 위해서는 StartCoroutine()을 사용하며 두 가지 오버로딩이 존재한다.
1. 실행할 코루틴의 이름을 매개변수로 전달
2. 실행할 코루틴의 시그니처에 맞추어 함수 형태로 전달
using System.Collections;
using UnityEngine;
...
private void Start()
{
StartCoroutine("Co_Print"); // 코루틴의 이름을 매개변수로 전달하는 경우
// 해당 코루틴의 중지를 제어할 수 있다.
StartCoroutine(Co_Print()); // 코루틴을 함수 형태로 매개변수로 전달하는 경우
// 성능 상에서 이득을 볼 수 있다.
}
private IEnumerator Co_Print()
{
yield return new WaitForSeconds(1f);
Debug.Log("1초 후에 이 로그가 출력됩니다.");
}
코루틴을 중지하기 위해서는 StopCoroutine()이나 StopAllCoroutines()를 사용한다.
| 종류 | 설명 |
|---|---|
StopCoroutine() | 매개변수로 전달된 문자열에 해당하는 코루틴을 정지 |
StopAllCoroutines() | 스크립트 내에서 실행 중인 모든 코루틴을 정지 |
추가적으로, 해당 컴포넌트가 비활성화되면 스크립트 내의 모든 코루틴이 정지된다.
using System.Collections;
using UnityEngine;
...
private void Start()
{
StartCoroutine("Co_Print");
StopCoroutine("Co_Print");
}
private IEnumerator Co_Print()
{
yield return new WaitForSeconds(1f);
Debug.Log("1초 후에 이 로그가 출력됩니다.");
}
using System.Collections;
using UnityEngine;
...
private void Start()
{
StartCoroutine("Co_Print1");
StartCoroutine(Co_Print2(1f));
StopAllCoroutines(); // Co_Print1() 코루틴과 Co_Print2() 코루틴이
// 모두 정지된다.
}
private IEnumerator Co_Print1()
{
yield return new WaitForSeconds(1f);
Debug.Log("1초 후에 이 로그가 출력됩니다.");
}
private IEnumerator Co_Print2(float duration)
{
yield return new WaitForSeconds(duration);
Debug.Log($"{duration}초 후에 이 로그가 출력됩니다.");
}