c# 코루틴(Coroutine, IEnumerator, yield), 코루틴 중단이 안될 때
nameof 연산자는 Type이나 메서드 등의 '이름'을 리턴해주는 것이다.
기존에는 이 이름들을 어딘가에 사용해야 할 때에는 string으로 직접 하드코딩을 해야 했으며, 이러한 하드코딩은 IDE에서 제대로 된 참조가 되지 않기 때문에 디버깅에 어려운 점이 있었다.
(유니티의 StartCoroutine은 string을 받기 때문에 이 코루틴이 사용되는 코루틴인지 아닌지 확인하는건 매우 까다롭다.
실제로 b스크립트에서 a스크립트의 코루틴을 실행하고 a에서 stopcoroutine을 했지만 동작하지 않는 오류가 발생했다.)
(IDE : 통합 개발 환경Integrated Development Environment ex) 비주얼스튜디오)
하지만 nameof 연산자를 이용하면 마법처럼 이름이라는 문자열을 반환해준다.
void Awake()
{
StartCoroutine(nameof(SomeCoroutine));
}
IEnumerator SomeCoroutine()
{
yield return null;
}
이제 IDE에서 SomeCoroutine이 정말로 사용되는 코루틴인지 확인할 수 있게 된 것이다.
바보같이 코루틴만 실행하면 내부가 자동으로 반복문이 된다고 생각한적이 있다.
따로 반복문으로 계속 반환해주면 된다.
void Awake()
{
StartCoroutine(nameof(SomeCoroutine));
}
IEnumerator SomeCoroutine()
{
while(true) 아무 조건 없이 true뿐이니까 무한 반복이 된다.
{
Debug.Log("1초마다 출력");
yield return new WaitForSeconds(1);
}
}
StopCoroutine이 제대로 작동하지 않는 경우
Coroutine 타입 변수 사용
Coroutine runningCoroutine = null; //코루틴 변수. 1개의 루틴만 돌리기 위해 저장한다.
//만약 이미 돌고 있는 코루틴이 있다면, 정지시킨 후 코루틴을 실행한다.
if(runningCoroutine != null)
{
StopCoroutine(runningCoroutine);
}
runningCoroutine = StartCoroutine(ScaleUp()); //코루틴을 시작하며, 동시에 저장한다.
--------------------------------------------------------------------------------
IEnumerator 타입 변수 사용
void Enter()
{
만약 stopcoroutine 할 때 작동이 안된다면,
StopCoroutine(nameof(SomeCoroutine));
IEnumerator CoTemp = null;
CoTemp = SomeCoroutine();
StartCoroutine(CoTemp);
if(CoTemp != null)
StopCoroutine(CoTemp);
}
출처 : https://killu.tistory.com/19
[Unity] 코루틴 중단하는 모든 방법 정리 (StopCoroutine)
유니티에서 코루틴을 중단할 때 쓰이는 StopCoroutine은 제대로 작동하지 않는 경우가 많다. 그 이유는 StopCoroutine 메서드를 잘못 사용했기 때문이다. StopCoroutine의 인자는 string, IEnumerator, Coroutine..
killu.tistory.com
<밑에는 좀 더 자세한 설명들>
IEnumerable - 스스로 상태(객체접근 횟수)를 저장하지 못해서
타입의 변수를 인풋으로 받았을 때, 다시 처음부터 콜렉션에 접근해서 객체에 접근한다.
IEnumerator - 스스로 상태(객체접근 횟수)를 저장함으로
스스로의 상태 state를 기억하고 있다가 다음 호출시, 그 시첨으로 부터
해당 객체를 뱉어낸다?
출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kimsung4752&logNo=220959490816
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
즉, IEnumerator는
- 지금 몇번쨰 까지 읽었는지(state)를 기억한다.
- MoveNext()호출 하면 다음 순번으로 이동.
- Current를 요구할 때 해당 순번의 개체를 리턴.
그러면 이런 구조로 볼 수 있겠다. IEnumerable에서 GetEnumerator()호출하면 -> IEnumerator는 Current(), MoveNext(), Reset()등 현재 객체 접근하는 구조. Enuerable 인터페이스에는 foreach 구문에서 필요한 멤버들을 약속한 IEnumerator 개체를 반환하는 GetEnumerator 메서드를 제공하고 있다. // 아직은 뭔소린지 도통 모르겠다..
public static System.Collections.IEnumerable SomeNumbers()
{
yield return 3;
yield return 5;
yield return 8;
}
- IEnumerable, IEnumerator클래스는 컴파일러가 코드를 보고 자동으로 만들어준다.(사용자 정의 컬렉션)
- IEnumrator가 가지는 state의 초기 값은 -1이다.
- 자동 생성된 IEnumerator에서 MoveNext() 실행하면 yield return 3; 이전까지 실행하고 state를 0으로 옮긴다.
- state가 0일 때 Current를 읽으면 3를 리턴한다.
- 마지막 부분(8)에서 MoveNext()실행 시 false를 리턴한다.
yield return new WaitForSeconds(1);
Current()에서 WaitForSeconds를 리턴 했다면??
- Update()에서 1초가 지났는지 매프레임 마다 체크.
- 만약 1초가 지났다면 IEnumerator의 MoveNext()를 호출 한다.
- 코드 다음 부분이 실행된다.
IEnumerable -> IEnumerator -> 반복기
출처 : https://postpiglet.netlify.app/posts/Coroutine-Considerationn/
출처 : https://www.slideshare.net/jungsoopark104/ienumerator
IEnumerator란 무엇인가?
유니티3D를 공부하면서 IEnumerator가 무엇인지 공부한 내용입니다.
www.slideshare.net
코루틴(Coroutine)
기능코루틴 | 시작코루틴 | 정지코루틴 | 재시작기타 | |
이름을 이용 | 가능 | 가능 | 가능[처음부터 재시작] | 매개변수 사용 불가능 |
함수를 이용 | 가능 | 불가능 | 불가능[정지가 불가능] | |
IEnumerator를 이용 | 가능 | 가능 | 가능[멈춘 지점에서 재시작] | |
Coroutine을 이용 | - | 가능 | 불가능[시작이 불가능] |
yield를 통해 IEnumerable, IEnumerator 를 상속받는 객체를 간단하게 구현할 수 있는 것이나 마찬가지다. 마치 일시정지와 같은 기능이다.
- yield break; 코루틴을 끝낸다.
- yield return new WaitForSecondsRealtime (float time); WaitForSeconds와 하는 역할은 동일하지만 결정적으로 다른것은, Scaled Time의 영향을 받지 않고 현실 시간 기준으로만 동작
- yield return new WaitForFixedUpdate (); 다음 FixedUpdate() 가 실행될때까지 기다리게 됩니다. 이 FixedUpdate()는 Update()와 달리 일정한 시간 단위로 호출되는 Update() 함수라고 생각하시면 됩니다.
- yield return new WaitForEndOfFrame (); 하나의 프레임워 완전yield return null;히 종료될 때 호출이 됩니다. Update(), LateUpdate() 이벤트가 모두 실행되고 화면에 렌더링이 끝난 이후에 호출
- yield return null; 다음 Update() 가 실행될때까지 기다린다는 의미를 갖게 됩니다. 좀 더 정확하게는 Update()가 먼저 실행되고 null을 양보 반환했던 코루틴이 이어서 진행 됩니다. 그 다음에 LateUpdate()가 호출
- yield return new WaitUntil (System.Func predicate); WaitUntil에 실행하고자 하는 식을 정의해 두면 매번 Update() 와 LateUpdate() 이벤트 사이에 호출해 보고 결과값이 true면 이후로 재진행
- yield return new WaitWhile(System.Func predicate); WaitWhile은 WaitUntil과 동일한 목적을 가지고 있지만 한가지만 다릅니다. WaitUntil은 람다식 실행 결과값이 true가 될때까지 기다린다면 WaitWhile은 false가 될때까지 기다립니다. 즉 WaitWhile은 결과가 true인 동안 계속 기다린다.
- yield return StartCoroutine (IEnumerator coroutine); 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다. 의존성 있는 여러작업을 수행하는데에 유리하게 사용.
yield return StartCoroutine (IEnumerator coroutine); 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다