Unity | Coroutine, UnityEvent

Clean·2025년 4월 18일

Unity

목록 보기
7/24

Coroutine

시간의 흐름에 따라 함수를 제어할 때 자주 사용하는 함수다.

기능을 분리하여 비동기처럼 실행되지만,

✨사실은 멀티스레드가 아닌 싱글 스레드의 동기 작업이다.

즉, 병렬성이 아닌 동시성 방식이다.

아직은 글로 설명하기 애매하니 코드부터 보자.


코드

Coroutine co;

void Update()
{
	if (Input.GetKeyDown(KeyCode.Space) && co == null)
		co = StartCoroutine(MyRoutine());

	if (Input.GetKeyDown(KeyCode.Escape) && co != null)
	{
		StopCoroutine(co);
		co = null;
	}
}

IEnumerator MyRoutine()
{
	// 실행 흐름
	yield return new WaitForSeconds(1f);
	Debug.Log("1초 후 실행");

	// 끝나면 초기화
	co = null;
}

주의할 점

우선 코루틴을 사용할 때는 주의할 점이 있는데,

1. 코루틴은 변수에 담아 사용할 것 (메모리 단편화 방지)
2. 사용이 끝나면 중지할 것 (메모리 누수 방지)

그래서 위의 코드도 Coroutine 타입의 필드변수 co를 선언한 후

Update() 함수에서 null 체크를 하고 변수에 담아 사용하고,

Routine() 함수에서 마지막에 co 변수에 null을 할당한다.


실행과 종료

코루틴을 실행할 때는 StartCoroutine() 을 사용하고,

코루틴을 종료할 때는 StopCoroutine() 을 사용한다.

실행할 때 인수로 IEnumerator 을 받기 때문에

코루틴에 사용할 함수의 반환 타입은 IEnumerator 타입으로 해야 한다.

그래야 코루틴의 장점인 시간제어를 할 수 있는 yield return 을 사용할 수 있다.

yield return

명령어설명
yield return nullUpdate 끝날 때
yield return new WaitForSeconds(n)게임시간 n초간 기다리고, Update 끝날 때
yield return new WaitForSecondsRealtime(n)현실시간 n초간 기다리고, Update 끝날 때
yield return new WaitForFixedUpdate()FixedUpdate 끝날 때
yield return new WaitForEndOfFrame()프레임이 끝날 때 (LateUpdate 다음)
yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Space))(조건 true) 스페이스바 누를떄까지 기다리기
yield return new WaitWhile(() => Input.GetKeyDown(KeyCode.Space));(조건 false)

yield return에 여러가지 클래스들을 추가해서 시간이나 타이밍조절을 할 수 있다.

또한 new 키워드로 객체를 생성하기 때문에 중복하여 사용하는 것이라면

필드 변수에 할당하여 사용하는 것이 좋다.


사용 이유?

코루틴의 최대 장점은 로직 분리라고 생각한다.

물론 시간제어도 장점 중 하나지만,

이전의 작성했던 탱크 구현 에서는 Update() 에 여러가지 시간이나 기능들을 넣어뒀는데

코루틴을 사용하여 각 기능들을 따로 함수로 관리할 수 있다.

즉, 기능의 책임을 떠넘길 수 있다. 😆


Invoke 와의 차이

Invoke 함수도 함수를 n초 뒤에 실행하는 함수의 시간제어가 가능하지만,

코루틴과 달리 실행할 함수에 매개변수가 있으면 실행할 수 없다는 큰 단점이 있다.


UnityEvent

UnityEvent는 유니티에서 제공하는 이벤트 시스템 클래스로,
델리게이트와 비슷하게 특정 함수들을 실행시킬 수 있다.
주로 UI에 사용한다.

  • using UnityEngine.Events; 를 선언해야 사용할 수 있다.

  • UnityEventdelegateevent처럼 다른 함수들을 등록해두고 실행하는 기능이다.

  • Invoke()로 실행할 수 있다.


코드

// 이벤트 클래스
public UnityEvent staticEventTest1;
public UnityEvent<int> staticEventTest2;
public UnityEvent<int, float, string, bool> staticEventTest3;

void Awake()
{
	staticEventTest1.AddListener(StaticTest.TestFunc1);
	staticEventTest2.AddListener(StaticTest.TestFunc2);
	staticEventTest3.AddListener(StaticTest.TestFunc3);
}

void Update()
{
	if (Input.GetKeyDown(KeyCode.T))
	{
		staticEventTest1.Invoke();
		staticEventTest2.Invoke(5);
        // 인수는 4개까지 가능
		staticEventTest3.Invoke(1, 5, "Asd", true);
	}
}
// 정적 클래스
public static class StaticTest
{
	public static void TestFunc1()
	{
		Debug.Log("테스트함수 실행");
	}
	public static void TestFunc2(int value)
    {
        Debug.Log($"테스트함수 실행 {value}");
    }
	public static void TestFunc3(int v1, float v2, string v3, bool b4)
	{
		Debug.Log($"{v1} / {v2} / {v3} / {4}");
	}
}

이벤트 추가

유니티 에디터에서 게임 오브젝트를 추가하고,

게임 오브젝트에 포함되어 있는 컴포넌트들에 있는 함수를 선택하여 추가할 수 있다.

다만 정적 클래스는 게임 오브젝트에 포함할 수 없기 때문에 AddListener 함수로 추가해야 한다.


💥 UnityEvent vs Delegate

사실 UnityEvent는 C#의 Delegate보다 성능적으로는 안좋다.

다만 델리게이트와 달리 유니티이벤트는 유니티 에디터에서 시각적으로 보거나

이벤트 객체, 이벤트 함수를 설정할 수 있다는 장점이 있다.

하지만 어떤 객체들이 이벤트에 등록되었는지 알 수 없다는 단점이 있다.

(델리게이트는 가능)


여태 코루틴을 메모리 생각없이 그냥 실행하고 그냥 종료하고 했었는데,

그때 흐름이 잘못됐었던 이유를 이제서야 알았다. 🤣

그리고 시각적으로 알 수 있는 유니티 이벤트가 더 편해보이는데

성능적으론 델리게이트가 더 좋다니...

아직은 익숙하지 않으니 쉬워보이는 유니티 이벤트부터 익혀야겠다.

0개의 댓글