Unity C# Coroutine
코루틴 Coroutine
Enumerator를 이용해서 여러 프레임에 걸쳐 실행된다.
업데이트 메서드와 달리 메서드 제어권을 유니티에 반환하고,
특정 조건이 되면 다시 제어하는 기능을 가진다.
코루틴 사용조건
MonoBehaviour를 상속하는 클래스 안에서만 사용가능.IEnumerator를 반환하는 함수여야 한다.yield return을 사용한다.- 코드가 실행되는 시점을 다른 프레임으로 넘긴다.
yield break;는 코루틴을 종료시킨다.- 코루틴을 실행하는 게임오브젝트가 비활성화되거나 파괴되면 코루틴 종료.
관련 메서드
StartCoroutine(): 코루틴 실행 메서드Coroutine StartCoroutine(string methodName)Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value)Coroutine StartCoroutine(IEnumerator routine)- 권장- 특별한 경우가 아니라면,
methodName을string으로 받는 버전이 아닌,
IEnumerator를 매개변수로 받는 버전을 사용할 것을 권장. - 가비지 Garbage를 생성시킨다.
- 특별한 경우가 아니라면,
StopCoroutine(): 코루틴 종료 메서드void StopCoroutine(string methodName)void StopCoroutine(IEnumerator routine)void StopCoroutine(Coroutine routine)- 권장- 가급적이면 종료하고자 하는 코루틴을 정확하게 식별하기 위해,
다음과 같은 방식으로 사용하는 것을 권장.1 2
Coroutine co = StartCoroutine(Coroutine1()); StopCoroutine(co);
StopAllCoroutines(): 해당 스크립트의 모든 코루틴을 종료
작동 방식
C#Enumerator를 활용해서 만들어짐- 열거할 때 마다 특정 프레임에서 실행되도록 작동함.
- 코루틴을 사용할 때 가비지 컬렉션(Garbage Collection, GC)에 주의해야 함.
new WaitForSeconds(1.0f)와 같이 매번 새로운 인스턴스를 생성하는 대신, 가능한 한 캐싱하여 재사용하는 것이 좋음. 이는 메모리 사용량을 줄이고, 가비지 컬렉션으로 인한 프레임 드랍을 방지할 수 있음.
YieldInstruction 클래스
- 코루틴이 대기하고 실행하는 방식을 정의하는 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 다음 프레임의 시작까지 대기 후 실행.
yield return null;
// 다음 FixedUpdate() 호출 시 까지 대기 후 실행.
yield return new WaitForFixedUpdate();
// 정한 시간만큼 지난 후 첫 프레임까지 대기 후 실행.
yield return new WaitForSeconds(1.0f);
// 정한 시간만큼 지난 후 첫 프레임까지 대기 후 실행.
// TimeScale의 영향을 받지 않음.
yield return new WaitForSecondsRealtime(1.0f);
// 현재 프레임의 렌더링 작업이 모두 완료된 후까지 대기 후 실행.
yield return new WaitForEndOfFrame();
// 해당 조건이 참이 될 때까지 대기 후 실행.
yield return new WaitUntil(()=>true);
// 위 모든 방식은 new를 사용하기 때문에, 이러한 방식은 가비지를 생성시킨다.
// 동일한 YieldInstruction을 여러번 사용할 때에는, 캐싱해서 사용하는 것도 방법.
yield return new {WaitForSeconds(1.0f), WaitForSecondsRealtime(1.0f)}테스트 코드 & 결과
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
using System.Collections; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { private void Start() { StartCoroutine(Coroutine1()); StartCoroutine(Coroutine2()); } IEnumerator Coroutine1() { float time1, time2; time1 = Time.time; yield return new WaitForSecondsRealtime(1.0f); time2 = Time.time; Debug.Log("WaitForSecondsRealtime : " + (time2 - time1)); StartCoroutine(Coroutine1()); } IEnumerator Coroutine2() { float time1, time2; time1 = Time.time; yield return new WaitForSeconds(1.0f); time2 = Time.time; Debug.Log("WaitForSeconds : " + (time2 - time1)); StartCoroutine(Coroutine2()); } }
위 두
CustomYieldInstruction은 1초를 정확히 측정할 수는 없다.
WaitForSeconds로 인한 가비지 생성을 최소화하기 위한 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class WaitForSecondsDictionary : MonoBehaviour
{
public static readonly WaitForFixedUpdate WaitForFixedUpdate = new WaitForFixedUpdate();
public static readonly WaitForEndOfFrame WaitForEndOfFrame = new WaitForEndOfFrame();
private static readonly Dictionary<float, WaitForSeconds> WaitForSecondsDict = new Dictionary<float, WaitForSeconds>();
public static WaitForSeconds WaitForSeconds(float waitTime)
{
WaitForSeconds wfs;
if (WaitForSecondsDict.TryGetValue(waitTime, out wfs))
return wfs;
else
{
wfs = new WaitForSeconds(waitTime);
WaitForSecondsDict.Add(waitTime,wfs);
return wfs;
}
}
}
- 매개변수를 필요로 하는
YieldInstruction은 하나의 객체로 생성해서 캐싱, - 그리고
WaitForSeconds는 실수를 키로 갖는Dictionary를 만들어,
해당 시간만큼의WaitForSeconds가 만들어져있지 않다면, 새로 만들어 사용하도록하는 클래스.
이벤트 함수와 코루틴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private IEnumerator Start()
{
yield return null;
}
private IEnumerator OnCollisionEnter(Collision other)
{
yield return null;
}
private IEnumerator OnMouseEnter()
{
yield return null;
}
private IEnumerator OnBecameInvisible()
{
yield return null;
}
- 위와 같이, 유니티의 이벤트 함수를 코루틴 버전으로 동작시키는 것도 가능하다.
가비지 컬렉션을 최소화하는 CustomYieldInstruction 상속 클래스
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
using System;
using UnityEngine;
public class WaitForCustomCondition : CustomYieldInstruction
{
private Func<bool> _condition; // 대기를 계속할 조건을 체크하는 함수
// keepWaiting 프로퍼티 오버라이드. _condition 함수의 반환값이 false가 될 때까지 대기.
public override bool keepWaiting => !_condition();
// 생성자에서 대기 조건 함수를 받음
public WaitForCustomCondition(Func<bool> condition)
{
_condition = condition;
}
}
public class CoroutineExample : MonoBehaviour
{
// 코루틴 예제
IEnumerator ExampleCoroutine()
{
Debug.Log("코루틴 시작, 조건을 만족할 때까지 대기");
// CustomYieldInstruction을 사용하여 특정 조건이 참이 될 때까지 대기
yield return new WaitForCustomCondition(() => Time.time > 5);
// 예를 들어, 시간이 5초를 초과할 때까지 대기
Debug.Log("조건 만족, 코루틴 계속 진행");
}
void Start()
{
StartCoroutine(ExampleCoroutine()); // 코루틴 실행
}
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.