코루틴은 내가 유니티 엔진을 접하고 나서 유용하게 쓰고 있는 기능 중 하나이다.
주로 애니메이션 효과나 몇 초간의 딜레이를 줄 때 주로 사용했었는데 솔직히 사용하면서 정확히 알고 사용하지는 않았다. 그냥 경험에 의거해 코딩을 했었는데 이제는 좀 어떤 기술을 사용하더라도 정확히 알고 사용하는 것이 중요하다고 생각해 블로그에 정리하려한다.
코루틴은 유니티에서 제공하는 기능으로 코드 내에서 구문 실행 도중에 처리를 대기시키거나 함수를 병렬로 동시에 처리하도록 구현할 수 있는 기능이다.
유니티 공식 문서에 따르면
코루틴을 사용하면 작업을 다수의 프레임에 분산할 수 있다. Unity에서 코루틴은 실행을 일시 정지하고 제어를 Unity에 반환하지만 중단한 부분에서 다음 프레임을 계속할 수 있는 메서드임
대부분의 경우엔 메서드를 호출하면 실행을 완료한 뒤 호출한 메서드에 제어와 선택적 반환 값을 반환한다. 즉 메서드 내에서 발생한 모든 행동은 단일 프레임 업데이트 내에서 발생한다
하지만 코루틴은 스레드가 아니라는 점을 명심하자. 코루틴의 동기 작업은 여전히 메인 스레드에서 실행된다
오브젝트의 알파값을 1에서 0(안보일때까지)으로 점점 줄여가는 코드를 작성하려 할 때
void Fade()
{
Color c = renderer.material.color;
for(float alpha = 1f; alpha >= 0; alpha -=0.1f)
{
c.a = alpha;
renderer.material.color = c;
}
}
위 코드에서 Fade 함수는 우리가 기대한 서서히 사라지는 효과가 보이지 않고 바로 안보이게 될 것이다. 이 메서드는 단일 프레임 업데이트 내에서 전체를 실행하기 때문
쉽게 말해 for 루프에서 알파값은 빠르게 변경하긴 하지만 렌더링이 발생한 후에만 최종 결과를 볼 수 있다.
알파값이 프레임 끝에서 0으로 설정되기 때문에 점진적으로 투명해지는 현상 없이 즉시 사라지는 것 처럼 보이는 것이다
IEnumerator Fade()
{
Color c = renderer.material.color;
for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
{
c.a = alpha;
renderer.material.color = c;
yield return null;
}
}
코루틴 메서드에서 yield return null을 통해 코루틴 메서드의 실행이 일시 중지되고 Unity에 제어권을 넘겨 일반 프레임 업데이트 및 렌더링 프로세스를 해서 변경된 알파값에 대해 렌더링을 진행하기 때문에 부드럽게 사라지는 듯한 효과가 날 수 있다
Invoke 함수도 코루틴과 같이 일정 시간 만큼 지연시켰다가 코드를 동작하게 만드는 함수인데
간단히 비교하자면 코루틴은 Update문과는 별개로 동작하는 또 다른 서브루틴을 만들 수 있고 매개변수를 넘길 수 있다는 장점이 있다
코루틴을 사용하기 위해 알아두어야 할 점이 있다
yield return nullyield return new WaitForSeconds(float)yield break코루틴 메서드를 호출하려면 StartCoroutine 메서드를 사용해야 한다
public Coroutine StartCoroutine(IEnumerator routine)
// Fade라는 IEnumerator 반환 형의 메서드를 실행하려면
StartCoroutine("Fade");
StartCoroutine(Fade);
// 매개변수가 필요할 때에는 쉽게
StartCoroutine(Fade(10f));
실행중인 코루틴 메서드를 종료하려면 StopCoroutine 메서드를 사용한다
public void StopCoroutine(string methodName)
public void StopCoroutine(Coroutine routine)
int main()
{
StartCoroutine("Fade");
StopCoroutine("Fade");
Coroutine co = StartCoroutine(Fade());
StopCoroutine(co);
}
IEnumerator Fade();
public void StopAllCoroutines()
이 함수는 작성된 스크립트 안에 있는 모든 코루틴을 중지하는 함수이다.
코루틴은 어떻게 하나의 메서드에서 각 작업을 여러 프레임으로 분산시키는 특징을 가지게 되었을까?
코루틴은 유니티에서 제공하는 시스템이긴 하지만, 코루틴의 모든 것을 유니티에서 만든 것은 아님. 유니티 또한 C#에서 제공하는 반복자를 활용해서 코루틴이라는 시스템을 만들었다.
C#의 반복자는 배열과 같은 컬렉션을 단계적으로 순회하기 위해 만들어진 개념이기에, 일반적으로 한 프레임에 모든 반복이 끝나는 것이 기본임
하지만 유니티에서는 한 단계가 진행될 때마다 다음 프레임에서 실행되도록 하는 방식을 채택하면서 현재의 코루틴이 탄생하게 되었다.
유니티가 어떻게 다음 프레임에서 실행되도록 만들었을까?
유니티에는 내부적으로 DelayedCallManager라는 클래스가 있는데, 특정 코루틴을 실행할 때, 해당 코루틴은 일반 메서드와 똑같이 실행되다가 첫 번째 yield return 문을 만나면 현재 실행중인 코루틴이 DelayedCallManager에 등록된다.
그러면 이후 프레임부터는 DelayedCallManager를 통해 다음 단계가 실행되기 때문에 다음 프레임부터는 코루틴이 진행되는 것임
코루틴은 멀티 스레드처럼 보이는 단일 스레드이다!
코루틴은 GC가 발생하기 때문에 메모리를 많이 쓸 수 있다
유니티의 코루틴은 프레임마다 코드를 실행할 수 있게 해주는 기능이다. update와 달리 코루틴은 일시적으로 Unity에 제어권을 넘겨준 다음 실행을 재개할 수 있어서 비동기식 동작으로 인해 코루틴은 시간 종속, 애니메이션 등의 기능 구현을 위한 유용하게 쓸 수 있다.