Unity/정보

[Unity] 유니티에서 코루틴(Coroutine) 사용하기

달시_Dalsi 2024. 9. 8. 23:05

코루틴이란?

코루틴은 IEnumerator를 반환하는 함수로, 비동기적으로 작업을 처리하거나 지연된 작업을 수행할 수 있습니다. yield를 사용하여 특정 시간 동안 대기하거나, 여러 프레임에 걸쳐 작업을 나누어 처리할 수 있습니다. 이는 게임에서 타이밍 제어나 비동기적 로딩, 애니메이션 제어 등 다양한 용도로 사용됩니다.

 

기본 사용법

코루틴은 다음과 같이 정의하고 호출할 수 있습니다:

using System.Collections;
using UnityEngine;

public class Greeting : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(GreetEverySecond());
    }

    IEnumerator GreetEverySecond()
    {
        while (true)
        {
            Debug.Log("Hello, World!");
            yield return new WaitForSeconds(1f); // 1초마다 "Hello, World!" 출력
        }
    }
}

 

 

주요 yield 반환 타입

  • WaitForSeconds: 지정한 시간 동안 대기
  • WaitForFixedUpdate: 다음 FixedUpdate 호출 전까지 대기
  • WaitForEndOfFrame: 현재 프레임이 끝날 때까지 대기
  • CustomYieldInstruction: 사용자 정의 조건을 만족할 때까지 대기

 

고급 응용 사례

1. 비동기 로딩 및 프로그래스 바

게임 내에서 리소스(예: 씬, 텍스처 등)를 비동기적으로 로드하고, 로딩 상태를 사용자에게 표시할 수 있습니다.

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class AsyncLoader : MonoBehaviour
{
    public Slider progressBar;

    void Start()
    {
        StartCoroutine(LoadSceneAsync("GameScene"));
    }

    IEnumerator LoadSceneAsync(string sceneName)
    {
        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName);

        while (!asyncOperation.isDone)
        {
            progressBar.value = Mathf.Clamp01(asyncOperation.progress / 0.9f);
            yield return null; // 프레임 단위로 진행 상태 확인
        }
    }
}

2. 애니메이션 및 타이밍 조절

특정 애니메이션 상태를 대기하거나 시간 기반의 애니메이션을 구현할 수 있습니다.

using System.Collections;
using UnityEngine;

public class AnimationController : MonoBehaviour
{
    public Animator animator;

    void Start()
    {
        StartCoroutine(PlayAnimationWithDelay("Jump", 2f));
    }

    IEnumerator PlayAnimationWithDelay(string animationName, float delay)
    {
        yield return new WaitForSeconds(delay); // 2초 대기
        animator.Play(animationName);
    }
}

3. 게임 이벤트 관리

게임 내에서 특정 조건이 충족될 때까지 대기하거나, 이벤트를 순차적으로 처리할 수 있습니다.

using System.Collections;
using UnityEngine;

public class EventManager : MonoBehaviour
{
    public GameObject objectToActivate;

    void Start()
    {
        StartCoroutine(HandleGameEvents());
    }

    IEnumerator HandleGameEvents()
    {
        yield return new WaitForSeconds(5f); // 5초 후 오브젝트 활성화
        objectToActivate.SetActive(true);

        yield return new WaitForSeconds(10f); // 10초 후 비활성화
        objectToActivate.SetActive(false);
    }
}

4. NPC 행동 패턴

코루틴을 사용하여 NPC의 행동을 순차적으로 처리하고, 시간 기반의 상태 전환을 구현할 수 있습니다.

using System.Collections;
using UnityEngine;

public class NPCBehavior : MonoBehaviour
{
    public Transform[] waypoints;
    private int currentWaypoint = 0;

    void Start()
    {
        StartCoroutine(Patrol());
    }

    IEnumerator Patrol()
    {
        while (true)
        {
            Transform target = waypoints[currentWaypoint];
            while (Vector3.Distance(transform.position, target.position) > 0.1f)
            {
                transform.position = Vector3.MoveTowards(transform.position, target.position, Time.deltaTime * 2f);
                yield return null; // 매 프레임마다 NPC를 이동
            }

            currentWaypoint = (currentWaypoint + 1) % waypoints.Length;
            yield return new WaitForSeconds(2f); // 2초 대기 후 다음 웨이포인트로 이동
        }
    }
}

 

 

코루틴 최적화 방법

코루틴을 효과적으로 사용하려면 다음과 같은 최적화 방법을 고려해야 합니다:

1. 불필요한 코루틴 최소화

코루틴이 너무 많으면 성능에 영향을 미칠 수 있습니다. 필요하지 않은 코루틴은 제거하고, 하나의 코루틴으로 여러 작업을 처리하도록 최적화합니다.

// 불필요한 코루틴 예시
IEnumerator Process1() { /* 작업 */ yield return null; }
IEnumerator Process2() { /* 작업 */ yield return null; }

// 최적화된 예시
IEnumerator ProcessAll()
{
    yield return StartCoroutine(Process1());
    yield return StartCoroutine(Process2());
}

2. 코루틴 종료 조건 명확히 설정

코루틴이 불필요하게 계속 실행되지 않도록 종료 조건을 명확히 설정합니다. yield break를 사용하여 코루틴을 명확하게 종료할 수 있습니다.

IEnumerator ExampleCoroutine()
{
    while (true)
    {
        // 조건에 따라 종료
        if (SomeCondition())
        {
            yield break;
        }
        yield return null;
    }
}​

3. WaitForSeconds 대신 WaitForSecondsRealtime 사용

게임이 일시 정지 상태일 때도 시간을 정확히 측정하고자 한다면 WaitForSecondsRealtime을 사용합니다.

// 일반적인 WaitForSeconds
yield return new WaitForSeconds(1f);

// 게임이 일시 정지 상태에서도 시간 측정 가능
yield return new WaitForSecondsRealtime(1f);

4. 매 프레임 호출되는 작업 최적화

매 프레임 호출되는 코루틴의 경우, 가능한 경우 yield return null 대신 yield return new WaitForSeconds를 사용하여 프레임 속도에 영향을 주지 않도록 합니다.

IEnumerator UpdatePerFrame()
{
    while (true)
    {
        // 매 프레임 작업
        yield return null;
    }
}

5. 사용자 정의 YieldInstruction 활용

복잡한 조건이 필요할 경우, 사용자 정의 YieldInstruction을 만들어서 지연을 보다 세밀하게 제어할 수 있습니다.

public class CustomYieldInstruction : YieldInstruction
{
    public override bool keepWaiting
    {
        get
        {
            // 사용자 정의 조건
            return false;
        }
    }
}

// 사용 예시
IEnumerator UseCustomYield()
{
    yield return new CustomYieldInstruction();
}

6. 미리 선언한 WaitForSeconds 객체 사용

yield return new WaitForSeconds(2f)를 매번 호출하는 대신, 해당 객체를 미리 선언하여 메모리 할당을 줄일 수 있습니다.
private WaitForSeconds wait = new WaitForSeconds(2f);

// 반복적으로 사용
yield return wait;​

 

결론

코루틴은 Unity에서 비동기 작업과 타이밍 제어를 유연하게 처리할 수 있는 방법입니다. 기본적인 사용법뿐만 아니라, 다양한 응용 사례와 최적화 방법을 이해하고 적용함으로써 게임의 성능을 효율적으로 관리할 수 있습니다.