[유니티] yield return과 stopcoroutine 상관 관계

jh Seo·2024년 9월 11일
0

유니티

목록 보기
47/50

개요

기본적으로 코루틴을 실행하는데 yield return으로 코루틴을 기다리는 상황이다.
stopcoroutine으로 해당 코루틴을 중지시켰을 때, yield return을 빠져나오질 못해서 문제가 생긴 상황이였다.
어떤 원리인지 알기전에 기본적으로 IEnumerator의 특성을 보자.

IEnumerator

IEnumerator는 C#의 코루틴이나 지연된 실행을 지원하는 인터페이스이다.
yield 키워드를 사용해 코루틴의 실행을 일시 중지하거나 특정 조건이 만족될 때까지 대기할 수 있다.
간단히 말해, IEnumerator는 순차적으로 실행되며 중간에 일시정지된 상태를 유지할 수 있는 함수라고 볼 수 있다.

일시정지는 기본적으로 yield return 키워드를 만나면 적용된다.

yield return 키워드는 대표적으로

  • yield return null: 다음 프레임에서 다시 이어서 실행.

  • yield return new WaitForSeconds(time): 주어진 시간이 지난 후 다시 실행.

  • yield return Coroutine: 다른 코루틴이 완료될 때까지 대기.

등이 있는데, 이번에 내가 사용한건 yield return coroutine; 이다.
yield return 다음에 코루틴을 적어주면 해당 코루틴이 완료될 때까지 기다린다.

또한 IEnumerator는 movenext()라는 함수를 이용해
마지막 반환이 있던 코드의 다음 줄 부터 마지막 반환의 다음 반환까지의 코드를 실행한다고 한다.
movenext()의 리턴값으로는 마지막 yield return기준으로 실행할 코드가 있다면 true,
없다면 false를 반환한다고 한다.

문제가 생긴 코드 부분

private Coroutine playCoroutine = null;

public override IEnumerator PlayCutscene()
{
	playCoroutine = StartCoroutine(PlayScene());
	yield return playCoroutine;
}

이런 식으로 함수 내부에 코루틴을 할당했을 때,

private void Update()
{
    if (!isActivatedCutscene) return;

    //TODO: 컷신중일때만 작동해야 함
    if (Input.GetKeyDown(KeyCode.S))
    {
        for (int i = 0; i < subCoroutines.Length; i++)
        {
            if (subCoroutines[i] == null) break;
            StopCoroutine(subCoroutines[i]);
            subCoroutines[i] = null;
        }
        if (playCoroutine != null)
        {
            StopCoroutine(playCoroutine);
            playCoroutine = null;
        }
        isSkipped = true;
    }
}

update문에서 s키를 누르면 종료되도록 구현했다.
하지만 s키를 누르면 빠져나오지 못하고 PlayCutscene()함수에서 멈춰버린다.

이유

IEnumerator의 movenext()가 false를 반환을 해야 yield return 코루틴 부분을
빠져나가게 된다.

stopcoroutine(playCoroutine);

하지만 위 stopcoroutine함수를 통해 코루틴을 종료시켜버리면
코루틴이 끝이라는 false값을 반환하지 않고 종료되기 때문에
yield return 코루틴 부분에서 계속 대기중이였던 것이다.

따라서 yield return Coroutine 형식으로 사용할 때,
코루틴 실행 도중 stopcoroutine(coroutine);으로 중지시켜도
저 yield return에서 빠져나오지 못한다.

해결

따라서 중간에 코루틴이 끝났는지 확인하기 위해
yield return playCoroutine 보단

playCoroutine = StartCoroutine(PlayScene());
//yield return 으로 기다리면 영원히 멈춰버림
while(playCoroutine != null)
{
    yield return null;
}

이렇게 무한루프를 통해 코루틴이 null값인지 간단히 체크해서 빠져나가도록 구현했다.

profile
코딩 창고!

0개의 댓글