코루틴 (Coroutine)
코루틴은 Update 함수와 별개로 동작하는 함수이다.
Update 함수는 매 프레임마다 호출되기 때문에 1초마다 수십번의 호출이 발생한다.
그러나 그렇게 많은 호출이 요구되지 않는 코드들이나 Update 함수와 별개로 작동하는 코드들은 코루틴을 사용하여
처리할 수 있다.
코루틴 함수 작성
코루틴 함수는 IEnumerator 반환형으로 선언해야하며 yield return 값이 필요하다.
Update 함수와는 다르게 프레임을 기준으로 동작하는 것이 아니라 시간을 기준으로 동작하기 때문에
yield return 값으로는 시간을 지정해주어야한다.
코루틴 함수의 형태는 아래 코드와 같다.
IEnumerator FunctionName()
{
yield return // return value
// code
}
yield return 반환형과 함수에 대한 이해
코루틴 함수는 yield return 값을 필수적으로 요구한다.
코루틴 함수 내에서 yield return 이전에 작성된 코드는 함수가 실행된 후 즉시 실행되지만 yield return 이후의 코드는
yield return 으로 지정한 만큼 지연된 후 실행된다.
이 yield return 값에는 여러 가지 종류가 있다.
1. yield return null
Update 함수가 끝난 후 다음프레임으로 넘어가기 전에 코드가 실행된다.
2. yield return new WaitForFixedUpdate()
yield return null 과 유사하다.
FixedUpdate가 종료된 후에 코드가 실행된다.
3. yield return new WaitForSeconds(float)
지정한 시간만큼 대기 한 후 코드가 실행된다.
4. yield return new WaitForSecondsRealtime(float)
3번과 마찬가지로 지정한 시간만큼 대기 한 후 코드가 실행되지만 TimeScale의 영향을 받지 않는다.
5. yield return startCoroutiune(string)
다른 코루틴이 끝난 후 코드가 실행된다.
기본적인 yield return 값을 열거해보았는데 이외에도 다른 yield return 값들도 존재한다.
다음으로 넘어가기 전에 yield return null 반환값을 사용했을 때 함수의 동작 순서를 알아보겠다.
yield return null 윗 부분 코드는 함수가 호출되는 즉시 실행될 것이다.
그러나 yield return null 아랫 부분의 코드는 Update 함수가 종료된 후 실행된다.
따라서 Update 함수 내에서 코루틴 함수를 호출했다고 가정한다면
yield return null 윗 부분 코드 - Update 함수 - yield return null 아랫 부분 코드 - 프레임 종료 와 같은 순서로 코드가 진행된다.
그림으로 보자면 다음과 같다.
당연히 Start 함수에서 코루틴 함수를 호출했을 경우에는 순서가 달라진다.
Start 함수 - yield return null 이전 코드 - Update 함수 시작 - Update 함수 종료 - yield return null 이후 코드 - 다시 Update 함수 시작
Start 함수에서 호출했을 경우에는 위와 같은 순서로 동작하게 된다.
코루틴 함수의 사용
코루틴 함수를 아래 코드처럼 작성하면 15초마다 원하는 동작을 실행시킬 수 있다.
IEnumerator CoFun1()
{
while (true)
{
yield return new WaitForSecondsRealtime(15.0f);
Debug.Log("Hi");
}
}
코루틴 함수를 호출할 때에는 StartCoroutine 함수를 사용하는데 이 때 2가지 방법을 사용할 수 있다.
코루틴 함수를 이용하는 방법과 문자열을 이용하는 방법이다.
따라서 CoFun 이라는 코루틴 함수를 선언했다고 가정했을 때 다음과 같이 작성할 수 있다.
StartCoroutine(CoFun());
StartCoroutine("CoFun");
이 때 첫번째 방법으로 호출할 경우 StopCoroutine 함수를 사용하여 코루틴을 중지시킬 수 있지만
두번째 방법으로 호출한 경우에는 불가능하다.
첫 번째 방법으로 호출했을 때에도 아래 코드처럼 작성할 경우에는 중지되지 않는다.
public class EnemyGenerate : MonoBehaviour
{
IEnumerator CoFun()
{
yield return new WaitForSecondsRealtime(5.0f);
Debug.Log("Hi");
}
// Start is called before the first frame update
void Start()
{
StartCoroutine(CoFun());
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.W))
StopCoroutine(CoFun());
}
}
분명 제대로 작성했는데 어이가 없을 것이다.
위 코드가 동작하지 않는 이유는 IEnumerator 메서드가 실행될 때마다 참조값이 변경되기 때문이다.
따라서 정상적으로 코루틴을 종료시키기 위해서는 변수를 선언한 후 코루틴 함수를 할당해주어야 한다.
public class EnemyGenerate : MonoBehaviour
{
IEnumerator IECoFun;
IEnumerator CoFun()
{
yield return new WaitForSecondsRealtime(5.0f);
Debug.Log("Hi");
}
// Start is called before the first frame update
void Start()
{
IECoFun = CoFun();
StartCoroutine(IECoFUn);
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.W))
StopCoroutine(IECoFun);
}
}
이제 w를 입력하면 5초마다 "Hi"가 출력되던 코루틴 함수가 더 이상 동작하지 않을 것이다.
비동기성
모든 코루틴함수들은 비동기적이다.
여러 개의 코루틴함수들이 각자의 주기를 갖고 있다는 뜻이다.
따라서 다음 코드에서 출력되는 순서는 아래 그림과 같다.
public class EnemyGenerate : MonoBehaviour
{
IEnumerator CoFun1()
{
Debug.Log("Hello");
yield return new WaitForSecondsRealtime(5.0f);
Debug.Log("Hi");
}
IEnumerator CoFun2()
{
Debug.Log("World");
yield return new WaitForSecondsRealtime(5.0f);
Debug.Log("Thanks");
}
IEnumerator CoFun3()
{
Debug.Log("End");
yield return null;
Debug.Log("Func");
}
// Start is called before the first frame update
void Start()
{
StartCoroutine(CoFun1());
StartCoroutine(CoFun2());
StartCoroutine(CoFun3());
}
// Update is called once per frame
void Update()
{
}
}
우선 Start 함수에서 3개의 코루틴 함수를 실행시켜주었으므로 순서대로 Hello, World, End가 출력된다.
CoFun3의 경우에는 Start 이후 실행되는 처음 Update가 종료된 후 Func가 출력된다.
CoFun1과 CoFun2의 yield return 이후 코드는 5초 뒤에 실행될 것이다.
Update가 몇 번 실행되었던 상관이 없다. 5초 후 yield return이 동작할 때 동시에 Update도 동작 중일 수도 있다.
위 그림에서 보는 것처럼 각각의 함수가 비동기적으로 동작되기 때문이다.
'유니티 > 유니티 엔진' 카테고리의 다른 글
[유니티] SetActive, Destory 차이점 (0) | 2023.11.13 |
---|---|
[유니티] 프레임 고정 (0) | 2023.11.13 |
[유니티] FixedUpdate (0) | 2023.11.12 |
[유니티] 프리팹 (Prefab, Instantiate) (0) | 2023.11.09 |
[유니티] 자연스러운 좌표이동 (Vector2.Lerp) (0) | 2023.11.08 |