본문 바로가기

💻 내 소개 안녕하세요 엄청짱 프로그래머 손다빈 입니다.
  • 나이 : 96년생
  • 특이사항 : MZ세대, INFJ, 오른손잡이, 아이폰 유저
  • 좋아하는 음식 : 햄버거피자치킨솥뚜껑삼겹살떡볶이오튀김밥
  • 취미 : 개발, Programming, 코딩, 프로그래밍, Coding

🥷기술
Unity
Godot
Cpp
Javascript
D3
Vue

🐱 우리집 고양이 소개
츄르 먹은 후 츄르 먹기 전
  • 이름 : 콜라
  • 나이 : 8살
  • 종 : Nado moreum

📱 개인 프로젝트
🏢 참여한 프로젝트
빌런즈 Life is Pair 도씨어부키우기 직장상사혼내주기 서바이벌빙고 SlitherCoin

🌱 내 잔디밭

MEC(More Effective Coroutines) 본문

글 묶음/유니티 에셋 사용법

MEC(More Effective Coroutines)

초긍정 개발자 다빈맨 2022. 12. 4. 12:19

| MEC (More Effective Coroutines)

MEC 에셋은 코루틴 강화버전(?) 같은 에셋 입니다.

기존 코루틴과 거의 유사한 구조로 호출 가능하면서도 성능은 더 좋습니다.

그리고 기존 코루틴에서 할 수 없던 여러가지 기능들이 지원됩니다.

 

가격 : 무료 / 유료 버전($20)


| 기본 코루틴과 MEC 기능 비교

  기본 코루틴 MEC 무료 버전 MEC 프로 버전
빈 코루틴 10만 개
실행 시간
~110.53 ~9.62 ~9.64
싱글톤 인스턴스로
코루틴 실행 가능
코루틴에 딜레이 걸기
특정 주기로 코루틴 걸기
코루틴 계속해서 호출
GameObject 인지
아닌지에 따라서 코루틴을 중단 가능
멀티스레드에 안전
코루틴 일시중지 및 이어서 실행하기
Late Update
Slow Update
Realtime Update
Editor Update
End Of Frame
Manual Timeframe
코루틴을 직접 제어 가능
연결된 코루틴 동시에 멈추게 하기
함수가 true 를 반환할 때 까지 지연 가능

 

| 기존 코루틴에서 전환하기

기존 코루틴을 사용할 때 호출하던 IEnumerator 를 반환하는 메소드들을 IEnumerator<float> 을 반환하는 형식으로 바꿉니다.

 

기존 코루틴 메소드 :

private IEnumerator CoroutineProcess()
{
    // Case 0
    yield return null;
    
    // Case 1
    yield return new WaitForSeconds(2.0f);
}

MEC 코루틴 메소드 :

private IEnumerator<float> CoroutineProcess()
{
    // Case 0
    yield return Timing.WaitForOneFrame; // yield return 0; 과 동일
    
    // Case 1
    yield return Timing.WaitForSeconds(2.0f);
}

케이스별로 MEC 에서 변경된 형식을 제공합니다.

 

코루틴을 실행할 때는 다음과 같은 형식으로 호출하면 됩니다.

// 1. 일반적인 코루틴과 동일하게 Update 시점에서 에서 동작
Timing.RunCoroutine(CoroutineProcess());
// 2. FixedUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.FixedUpdate);
// 3. LateUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.LateUpdate);
// 4. SlowUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.SlowUpdate);

인자 Segment 를 지정하지 않으면 기본적으로 Segment.Update 로 설정됩니다.

Timing.RunCoroutine(CoroutineProcess().CancelWith(gameObject));

위와 같이 CancelWith 와 함께 사용하면 지정한 게임오브젝트가 비활성화 되거나 null 이 되면 코루틴도 함께 중단됩니다.

때문에 씬이 전환되거나 했을때 오브젝트가 비활성화 되는 등의 상황을 고려해서 CancelWith 를 항상 의식해서 사용하면 좋습니다.

 

| 코루틴 일시중지 및 이어서 실행하기

// Pause
Timing.PauseCoroutines(gameObject);

// Resume
Timing.ResumeCoroutines(gameObject);

Timing.PauseCoroutines, Timing.ResumeCoroutines 메소드를 이용해서 일시정지 및 재개가 가능합니다. 대상은 코루틴을 핸들링 하는 핸들러가 되어야 합니다. 예를들면 게임오브젝트가 될 수도 있지만 MEC 설정 가능한 코루틴의 태그로 지정할수도 있습니다.

| WaitUntilDone

유니티에서 기존 코루틴에서 중간에 또 다른 코루틴이나 비동기 작업을 기다리게 하기 위해 yield return (어떤 변수 or 함수) 형태로 구문이 들어가는 경우가 종종 있습니다. MEC 에서도 WaitUnitilDone 메소드를 호출하면 이런 작업이 가능합니다.

private IEnumerator<float> OtherCoroutine()
{
    yield return Timing.WaitForOneFrame;
}

private IEnumerator<float> CoroutineProcess()
{
    yield return Timing.WaitUntilDone(OtherCoroutine());
}

위와 같은 형태로 다른 코루틴이 끝날 때 까지 기다릴 수 있습니다.

yield return Timing.WaitUntilTrue(functionDelegateThatReturnsBool);
yield return Timing.WaitUntilFalse(functionDelegateThatReturnsBool);

위와 같이 WaitForUntilTrue, WaitForUntilFalse 를 이용하면 인자로 전달한 딜리게이트의 반환 값이 true 혹은 false 가 될 때 까지 대기시킬 수도 있습니다.

| SlowUpdate

SlowUpdate 는 기존 유니티에는 없는 컨셉이고, MEC 에서 만든 컨셉입니다. '거의' 매 프레임에 실행되어야 하지만 그렇다고 정말 매 프레임 실행시킬 필요까지는 없는 작업을 할 때 좋습니다. 예를 들면, UI 의 어떤 텍스트 값을 변수 값에 따라 갱신되게 하고 싶은 경우라면 좋은 예시가 됩니다. SlowUpdate1초에 7번 호출 되기 때문에 Update 보다 호출이 적어 퍼포먼스에 유리합니다.

Timing.Instance.TimeBetweenSlowUpdateCalls = 3f;

물론 7초가 아닌 3초로 간격을 바꾸고 싶으면 위와 같이 코드를 통해 변경할 수 있습니다.

 

| 태그 (Tags)

코루틴을 실행시킬 때, 코루틴 마다 태그를 달아서 관리할 수 있게됩니다.

void Start()
{
    Timing.RunCoroutine(CoroutineProcess(), "Tag1");
    Timing.RunCoroutine(OtherCoroutine(), "Tag2");

    Debug.Log($"Killed : {Timing.KillCoroutines("Tag1")}");
}

위와같이 RunCoroutine 할 때 태그를 설정하고, 해당 태그를 가진 모든 코루틴을 중단하거나 할 때 사용할 수 있습니다.

 

| LocalTime

MEC 에는 유니티에 없는 컨셉인 SlowUpdate 가 있는데, SlowUpdate 세그먼트에서 동작하는 코루틴은 Time.deltatTime 이 의도대로 동작하지 않습니다. (7초에 1회 호출되기 때문에..) 그래서 MEC 코루틴 안에서는 Time.deltatTime 보다는 Timing.LocalTime 을 사용해야 어느 세그먼트에 동작하던 원하는 의도대로 동작시킬 수 있습니다.

| 추가적인 함수들

  1. CallDelayed : 원하는 시간(초) 만큼 기다렸다가 호출합니다.
  2. CallContinously : 원하는 시간(초) 동안 호출합니다.
  3. CallPeriodicaaly : 원하는 시간(초) 동안 x 초 마다 주기적으로 호출합니다.

| CallDelayed

Timing.CallDelayed(3f, () => {
    Debug.Log("3초 후 실행");
});

| CallContinously 

Timing.CallContinuously(3f, () =>
{
    Debug.Log("3초 동안 실행");
});

| CallPeriodicaly

Timing.CallPeriodically(3f, 1.5f, () =>
{
    Debug.Log("3초 동안 1.5 초 간격으로 호출");
});

| 메소드 체이닝 구조로 호출하기

// 일반적인 MEC 호출
Timing.RunCoroutine(CoroutineProcess(2f).CancelWith(gameObject));

// 유동적인 구조로 호출
CoroutineProcess(2f).CancelWith(gameObject).RunCoroutine();

MEC 문서에서는 Fluid Architecture (유동적인 아키텍쳐) 라고 설명하고 있지만, 쉽게 말하면 메소드 체이닝을 활용해서 위와 같이 메소드를 호출 할 수 있습니다.