Programming
-
코루틴(Coroutine) 다루기 2(코루틴 중단하기 + 코루틴 매개변수 + yield break)
작성 기준 버전 ::2019.2
[이 포스트는 유튜브 영상으로도 시청하실 수 있습니다]
이번 포스트에서는 지난 코루틴 포스트에서 다루지 못했던 코루틴 중단하기와 코루틴 함수에 매개변수 전달하기 그리고 yield break에 대해서 다뤄보도록 하자.
코루딘 중단하기
public class CoroutineTest : MonoBehaviour
{
IEnumerator enumerator;
void Start()
{
// 코루틴 함수를 직접 호출해서 중단시키려면 IEnumerator를 저장해서 사용
enumerator = TestCoroutine();
StartCoroutine(enumerator);
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
// 코루틴 함수를 직접 호출해서 중단시키려면 IEnumerator를 저장해서 사용
StopCoroutine(enumerator);
}
}
IEnumerator TestCoroutine()
{
int i = 0;
while(true)
{
yield return null;
Debug.Log("Coroutine " + i);
i++;
}
}
}
코루틴을 정지시키는 기본적인 방법의 위의 코드와 같다.
위 코드는 게임이 시작되면 Start 함수에 StartCoroutine으로 TestCoroutine 함수를 실행시켜 준다. 그러면 코루틴 함수 내용에 따라서 "Coroutine"이라는 로그와 함께 반복된 횟수를 출력한다. 그리고 플레이 도중에 스페이스 키를 누르면 코루틴이 멈추면서 로그 출력이 중단된다.
StartCoroutine(TestCoroutine());
보통 때는 바로 위 코드처럼 코루틴 함수를 호출했을 텐데 IEnumerator에 저장해서 실행한 이유는 TestCoroutine 함수에서 받아온 IEnumerator를 StopCoroutine에 넣어주기 위해서 이다.
StartCoroutine과 StopCoroutine은 이 IEnumerator를 통해서 어떤 코루틴을 실행하고 중단시킬지 확인할 수 있다.
코루틴 함수 이름을 문자열로 이용하기
StartCoroutine("TestCoroutine");
StopCoroutine("TestCoroutine");
이전 코루틴 포스트에서는 알려주지 않은 방법이 있는데, 코루틴을 실행시킬 때 그 코루틴 함수의 이름만으로도 실행시킬 수 있다는 것이다. 그리고 코루틴의 이름으로도 코루틴을 정지시킬 수 있.
어떤 면에서 보면 코루틴의 이름으로 코루틴을 시작하고 멈추는 방법이 더 낫다고 여길 수도 있다. 하지만 한 오브젝트에서 같은 이름의 코루틴이 2개 이상 실행되고 있는 상태에서 코루틴의 함수 이름 문자열로 StopCoroutine을 호출하면 이름으로 실행된 모든 코루틴이 동시에 멈춰버린다.
StartCoroutine(TestCoroutine()); // 코루틴 함수를 호출해서 실행한 코루틴은
StopCoroutine("TestCoroutine"); // 코루틴 이름 문자열로 중단시킬 수 없음
그와 더불어 위 코드처럼 코루틴 함수를 호출해서 실행한 코루틴은 코루틴 이름 문자열로 중단시킬 수 없다.
문자열로 코루틴을 실행하는 방법은 편리하지만 사용을 권장하지는 않는다. 그 이유는 문자열이기 때문에 오타가 발생해도 에러 표시가 되지 않아서 문제가 발생할 소지가 높기 때문이다. 그리고 이렇게 상수 문자열은 게임을 출시하는 과정에서 앱 보안을 위한 암호화 과정을 거칠 때, 코루틴 이름과 다른 문자열로 변경되어서 코루틴 함수 호출에 실패하게 되는 경우가 발생하기도 한다.
모든 코루틴 동시에 중단시키기
StopAllCoroutines();
코루틴을 중단시키는 마지막 방법으로는 StopAllCoroutines가 있다. StopAllCoroutines 함수를 사용하면 이 컴포넌트가 실행하고있는 모든 코루틴을 중단시킨다.
코루틴 함수에 매개변수 전달하기
IEnumerator TestCoroutine(int count)
{
int i = 0;
while(i < count)
{
yield return null;
Debug.Log("Coroutine " + i);
i++;
}
}
그럼 이번에는 코루틴 함수에 매개변수를 전달하는 방법을 알아보자.
TestCoroutine 코루틴 함수를 위와 같이 매개변수를 받을 수 있게 약간 변경한다. int 타입의 count 매개변수를 받아서 count 횟수만큼 반복하게 되었다.
StartCoroutine(TestCoroutine(10));
코루틴 함수 호출 방식에서는 TestCoroutine의 매개변수에 바로 값을 넣어주면된다.
StartCoroutine("TestCoroutine", 10);
코루틴 이름 문자열로 코루틴을 실행시킬 때는 문자열의 이름 뒤에 콤마를 찍고 매개변수를 넣어주면 된다.
Coroutine StartCoroutine(string methodName, object value);
코루틴 이름 문자열로 코루틴을 실행시키면서 매개변수를 받는 StartCoroutine의 오버로드 형식은 string으로 코루틴 함수의 이름을 받고 object 타입으로 매개변수를 받는다.
참고로 object 타입은 C# 프로그래밍에서 모든 변수 타입의 최상위 타입이다. 그래서 이렇게 int 타입의 숫자를 넣어주면 object 타입으로 바꿔서 받는다. 그리고 TestCoroutine 함수를 호출하면서 내부적으로 int 타입으로 바꿔서 전달해준다다.
StartCoroutine(TestCoroutine(10));
StartCoroutine("TestCoroutine", 10);
그렇기 때문에 이 두 가지 호출 방식은 똑같이 동작한다.
코루틴 함수 이름 문자열 실행 방식의 매개변수 전달 방식의 약점
박싱/언박싱의 오버헤드
// 박싱(Boxing)
int i = 10;
object obj = i;
// 언박싱(Unboxing)
int j = (int)obj;
하지만 이렇게 object로 매개변수를 전달하는 방법에는 약점이 몇 가지 있다. 먼저 프로그래밍에서 다른 타입의 변수를 object 타입으로 만드는 과정을 박싱(Boxing)이라고 부르고 object 타입의 변수를 원래 타입의 변수로 되돌리는 과정을 언박싱(Unboxing)이라고 부른다.
이 박싱/언박싱 과정은 미세하지만 분명히 성능적인 오버헤드를 일으킨다. 게임 최적화를 위해서는 남발하지 않는게 좋다.
전달 가능한 매개변수의 갯수
IEnumerator TestCoroutine(int count, float time)
{
yield return new WaitForSeconds(time);
int i = 0;
while(i < count)
{
yield return null;
Debug.Log("Coroutine " + i);
i++;
}
}
그리고 두 번째 약점을 설명하기 위해서 TestCoroutine의 기능을 조금 변경하기로 했다고 가정해보자.
매개변수에 float 타입으로 time 변수를 추가로 받아서 그 시간만큼 기다렸다가 count 횟수만큼 반복하도록 변경했다. 이렇게 되면 매개변수가 2개로 바뀌게 된다.
StartCoroutine(TestCoroutine(10, 3f));
그러면 코루틴 함수 자체로 호출하는 방식에서는 새로운 매개변수를 넣어달라고 에러가 표시되기 때문에 추가된 기능에 맞게 매개변수를 넣어주기만 하면 된다.
하지만 코루틴 함수의 이름으로 호출하는 방식에서는 매개변수를 전달할 object가 하나 뿐이라 두 번째 매개변수를 전달할 방법이 없다. 그러니까 이름으로만 호출할 때는 매개변수를 하나 밖에 쓸 수 없는 것이다.
물론 클래스나 구조체로 묶어서 보내는 방법도 있겠지만 굳이 그렇게 번거로운 방법쓰는 것 보다는 코루틴 함수에 바로 매개변수 여러 개를 사용하는 것이 편할 것이다.
yield break
IEnumerator ReturnCoroutine()
{
Debug.Log("Return 1");
yield return null; // 코드의 제어권을 잠시 양보했다가 돌려받아서 아래 코드를 계속 진행
Debug.Log("Return 2");
}
IEnumerator BreakCoroutine()
{
Debug.Log("Break 1");
yield break; // 코루틴 함수를 이 시점에 종료
Debug.Log("Break 2");
}
마지막으로는 yield break 문에 대해서 알아보도록 하자.
yield return을 사용할 ReturnCoroutine과 yield break를 사용할 BreakCoroutine을 만든다.
이 두 코루틴을 실행하면 ReturnCoroutine은 Return 1과 Return 2가 모두 출력되지만 BreakCoroutine에서는 Break 1만 출력되고 Break 2는 출력되지 않는 것을 볼 수 있다.
yield break가 호출된 순간에 코루틴 함수가 완전히 멈춰버린 것이다.
yield return은 코드의 제어권을 유니티 엔진에 잠시 넘겼다가 특정 시점이 되면 다시 받아서 코드를 진행하지만 yield break는 그 시점에 코루틴을 완전히 멈춰버린다.
코루틴 내부에서 특정 조건을 만족하면 yield break로 코루틴을 멈추는 방식으로 사용할 수 있다.
[유니티 어필리에이트 프로그램]
아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.
[투네이션]
[Patreon]
[디스코드 채널]
'Unity3D > Programming' 카테고리의 다른 글
[Unity3D] Programming - TPS 캐릭터 조작 기능 구현하기 (4) | 2020.06.01 |
---|---|
[Unity3D] Programming - 클릭한 위치로 캐릭터를 이동시키는 기능 구현하기 (8) | 2020.05.14 |
[Unity3D] Programming - 씬 불러오기 (0) | 2020.04.02 |
[Unity3D] Programming - 코루틴(Coroutine) 다루기 (1) | 2020.04.01 |
[Unity3D] Programming - 스크립트로 게임 오브젝트 생성하고 파괴하기 (0) | 2020.03.18 |