수색…
통사론
- 공용 코 루틴 StartCoroutine (IEnumerator 루틴);
- 공용 코 루틴 StartCoroutine (string methodName, object value = null);
- 공공 무효 StopCoroutine (문자열 methodName);
- 공공 무효 StopCoroutine (IEnumerator 루틴);
- 공공 무효 StopAllCoroutines ();
비고
성능 고려 사항
유연성이 성능 비용과 함께 제공되므로 적당히 coroutines를 사용하는 것이 가장 좋습니다.
- 큰 숫자의 코 루틴은 표준 업데이트 방법보다 CPU에서 더 많은 것을 요구합니다.
-
MoveNext
박스의MoveNext
반환 값으로 인해 coroutine이 가비지를 생성하는 Unity 버전에 문제가 있습니다. 이것은 5.4.0b13에서 마지막으로 관찰되었습니다. ( 버그 리포트 )
YieldInstructions를 캐싱하여 쓰레기 줄이기
코 루틴에서 생성되는 쓰레기를 줄이기위한 일반적인 트릭은 YieldInstruction
을 캐시하는 YieldInstruction
입니다.
IEnumerator TickEverySecond()
{
var wait = new WaitForSeconds(1f); // Cache
while(true)
{
yield return wait; // Reuse
}
}
yield null
은 여분의 쓰레기를 생성하지 않습니다.
코 루틴
먼저 게임 엔진 (예 : Unity)이 "프레임 기반"패러다임에서 작동한다는 것을 이해하는 것이 필수적입니다.
코드는 매 프레임마다 실행됩니다.
그것은 Unity의 코드와 코드를 포함합니다.
프레임을 생각할 때 프레임이 언제 발생하는지 절대적으로 보장하지 않는다는 것을 이해하는 것이 중요합니다. 그들은 규칙적인 박자에서 일어나지 않습니다 . 프레임 사이의 틈은 예를 들어 0.02632, 0.021167, 0.029778 등이 될 수 있습니다. 이 예에서는 모두 1 분의 1 정도의 "대략"약이지만 모두 다 다릅니다. 언제든지 프레임을 길게 또는 짧게 만들 수 있습니다. 귀하의 코드는 프레임 내에서 언제든지 실행될 수 있습니다.
이 점을 염두에 두면서, 여러분은 다음과 같은 질문을 할 것입니다 : 여러분의 코드와 Unity에서이 프레임들을 어떻게 접근합니까?
간단히 말해, Update () 호출을 사용하거나 코 루틴을 사용합니다. (실제로 - 정확히 똑같습니다. 모든 프레임에서 코드를 실행할 수 있습니다.)
코 루틴의 목적은 다음과 같습니다.
일부 코드를 실행 한 다음 미래의 프레임까지 "중지하고 대기" 할 수 있습니다 .
다음 프레임이 나올 때까지 기다리거나 프레임 수가 많을 때까지 기다리거나 나중에 대략적인 시간 (초)을 기다릴 수 있습니다.
예를 들어, "약 1 초"를 기다릴 수 있습니다. 즉, 약 1 초를 기다린 후 약 1 초 후에 코드를 프레임에 넣을 수 있습니다. (실제로 프레임 내에서 코드는 언제든지 실행할 수 있습니다.) 반복하려면 정확히 1 초가 아닙니다. 정확한 타이밍은 게임 엔진에서 의미가 없습니다.
코 루틴 내부 :
하나의 프레임을 대기하려면 다음을 수행하십시오.
// do something
yield return null; // wait until next frame
// do something
세 프레임을 기다리는 중 :
// do something
yield return null; // wait until three frames from now
yield return null;
yield return null;
// do something
약 30 초 기다리기 :
// do something
yield return new WaitForSeconds (0.5f); // wait for a frame in about .5 seconds
// do something
매 프레임마다 무언가를하십시오 :
while (true)
{
// do something
yield return null; // wait until the next frame
}
이 예제는 Unity의 "Update"호출 안에 뭔가를 넣는 것과 똑같습니다. "do something"의 코드는 매 프레임마다 실행됩니다.
예
Ticker를 GameObject
첨부하십시오. 해당 게임 개체가 활성화되어있는 동안 진드기가 실행됩니다. 게임 객체가 비활성 상태가되면 스크립트는 신중하게 코 루틴을 중지합니다. 이것은 대개 코 루틴 사용법을 올바르게 설계하는 중요한 측면입니다.
using UnityEngine;
using System.Collections;
public class Ticker:MonoBehaviour {
void OnEnable()
{
StartCoroutine(TickEverySecond());
}
void OnDisable()
{
StopAllCoroutines();
}
IEnumerator TickEverySecond()
{
var wait = new WaitForSeconds(1f); // REMEMBER: IT IS ONLY APPROXIMATE
while(true)
{
Debug.Log("Tick");
yield return wait; // wait for a frame, about 1 second from now
}
}
}
코 루틴 끝내기
종종 특정 목표를 달성 할 때 자연스럽게 종료되도록 코 루틴을 디자인합니다.
IEnumerator TickFiveSeconds()
{
var wait = new WaitForSeconds(1f);
int counter = 1;
while(counter < 5)
{
Debug.Log("Tick");
counter++;
yield return wait;
}
Debug.Log("I am done ticking");
}
코 루틴을 코 루틴의 "안쪽"에서 멈추려면, 일찍이 평범한 기능에서 빠져 나가는 것처럼 단순히 "돌아 오는"것은 불가능합니다. 대신 yield break
를 사용합니다.
IEnumerator ShowExplosions()
{
... show basic explosions
if(player.xp < 100) yield break;
... show fancy explosions
}
끝내기 전에 스크립트에 의해 시작된 모든 코 루틴을 강제로 멈출 수 있습니다.
void OnDisable()
{
// Stops all running coroutines
StopAllCoroutines();
}
호출자로부터 특정 코 루틴을 중지하는 방법은 시작한 방법에 따라 다릅니다.
coroutine을 문자열 이름으로 시작한 경우 :
StartCoroutine("YourAnimation");
다음과 같은 문자열 이름으로 StopCoroutine 을 호출하여 중지 할 수 있습니다.
StopCoroutine("YourAnimation");
또는 coroutine 메서드에서 반환 한 IEnumerator
또는 StartCoroutine
에서 반환 한 Coroutine
개체에 대한 참조를 유지하고 둘 중 하나 에서 StopCoroutine
을 호출 할 수 있습니다.
public class SomeComponent : MonoBehaviour
{
Coroutine routine;
void Start () {
routine = StartCoroutine(YourAnimation());
}
void Update () {
// later, in response to some input...
StopCoroutine(routine);
}
IEnumerator YourAnimation () { /* ... */ }
}
코 루틴 일 수있는 MonoBehaviour 방법
코 루틴으로 만들 수있는 MonoBehaviour 메서드가 세 가지 있습니다.
- 스타트()
- OnBecameVisible ()
- OnLevelWasLoaded ()
예를 들어 객체를 카메라에서 볼 수있을 때만 실행되는 스크립트를 작성하는 데 사용할 수 있습니다.
using UnityEngine;
using System.Collections;
public class RotateObject : MonoBehaviour
{
IEnumerator OnBecameVisible()
{
var tr = GetComponent<Transform>();
while (true)
{
tr.Rotate(new Vector3(0, 180f * Time.deltaTime));
yield return null;
}
}
void OnBecameInvisible()
{
StopAllCoroutines();
}
}
coroutines 연결하기
코 루틴은 내부에서 양보 할 수 있으며 다른 코 루틴을 기다릴 수 있습니다.
따라서 "하나씩 차례로"시퀀스를 연결할 수 있습니다.
이것은 매우 쉽고, Unity의 기본 핵심 기술입니다.
특정 상황이 "순서대로"이루어져야한다는 것은 게임에서 절대적으로 자연스러운 일입니다. 게임의 거의 모든 "라운드"는 시간의 흐름에 따라 일정한 순서로 일어나는 일련의 사건으로 시작됩니다. 다음은 자동차 경주 게임을 시작하는 방법입니다.
IEnumerator BeginRace()
{
yield return StartCoroutine(PrepareRace());
yield return StartCoroutine(Countdown());
yield return StartCoroutine(StartRace());
}
BeginRace를 부를 때 ...
StartCoroutine(BeginRace());
"준비 레이스"루틴을 실행할 것입니다. 아마도 일부 조명을 깜박이고 군중 소리를 내며 점수를 재설정하는 등의 작업을 수행 할 수 있습니다. 작업이 완료되면 UI에서 카운트 다운을 생생하게하는 "카운트 다운"시퀀스가 실행됩니다. 이 작업이 끝나면 경주 시작 코드가 실행되어 사운드 효과를 실행하고 AI 드라이버를 시작하고 카메라를 특정 방향으로 움직이는 등의 작업을 수행합니다.
명확하게하기 위해 세 가지 호출
yield return StartCoroutine(PrepareRace());
yield return StartCoroutine(Countdown());
yield return StartCoroutine(StartRace());
코 루틴 에 있어야합니다. 즉, IEnumerator
유형의 함수에 있어야합니다. 그래서 IEnumerator BeginRace
예제입니다. 따라서 "정상"코드에서 StartCoroutine
호출로 코 루틴을 시작합니다.
StartCoroutine(BeginRace());
연결을 더 잘 이해하기 위해 coroutine을 연결하는 함수가 있습니다. 당신은 coroutines의 배열을 전달합니다. 이 함수는 순차적으로 많은 코 루틴을 순차적으로 실행합니다.
// run various routines, one after the other
IEnumerator OneAfterTheOther( params IEnumerator[] routines )
{
foreach ( var item in routines )
{
while ( item.MoveNext() ) yield return item.Current;
}
yield break;
}
다음과 같이 호출하는 방법이 있습니다 ... 세 가지 기능이 있다고 가정 해 봅시다. 그들은 모두 IEnumerator
여야 함을 기억하십시오.
IEnumerator PrepareRace()
{
// codesay, crowd cheering and camera pan around the stadium
yield break;
}
IEnumerator Countdown()
{
// codesay, animate your countdown on UI
yield break;
}
IEnumerator StartRace()
{
// codesay, camera moves and light changes and launch the AIs
yield break;
}
너는 이렇게 부를거야.
StartCoroutine( MultipleRoutines( PrepareRace(), Countdown(), StartRace() ) );
또는 아마도 이것처럼
IEnumerator[] routines = new IEnumerator[] {
PrepareRace(),
Countdown(),
StartRace() };
StartCoroutine( MultipleRoutines( routines ) );
반복하기 위해 게임에서 가장 기본적인 요구 사항 중 하나는 시간이 지남에 따라 특정 순서가 다른 순서대로 발생한다는 것입니다. 당신은 Unity에서 매우 간단하게 그것을 달성합니다.
yield return StartCoroutine(PrepareRace());
yield return StartCoroutine(Countdown());
yield return StartCoroutine(StartRace());
양보하는 방법
다음 프레임까지 기다릴 수 있습니다.
yield return null; // wait until sometime in the next frame
원하는만큼의 프레임을 기다리기 위해 연속적으로 여러 번 호출 할 수 있습니다.
//wait for a few frames
yield return null;
yield return null;
약 n 초 동안 기다리십시오. 이것은 매우 근사한 시간이라는 것을 이해하는 것이 매우 중요합니다.
yield return new WaitForSeconds(n);
정확한 타이밍의 모든 형태에 대해 "WaitForSeconds"호출을 사용하는 것은 절대 불가능합니다.
액션을 연결하고자하는 경우가 많습니다. 그래서, 무언가를하고, 그것이 끝날 때 다른 것을하고, 끝나면 다른 것을하십시오. 이를 달성하기 위해 다른 코 루틴을 기다리십시오.
yield return StartCoroutine(coroutine);
코 루틴 안에서만 호출 할 수 있다는 것을 이해하십시오. 그래서:
StartCoroutine(Test());
이것이 바로 "정상적인"코드로부터 코 루틴을 시작하는 방법입니다.
그런 다음 실행중인 코 루틴 내부 :
Debug.Log("A");
StartCoroutine(LongProcess());
Debug.Log("B");
그러면 A가 인쇄되고 긴 프로세스가 시작되며 즉시 B가 인쇄 됩니다. 긴 프로세스가 끝나기를 기다리지 않습니다 . 반면에 :
Debug.Log("A");
yield return StartCoroutine(LongProcess());
Debug.Log("B");
그러면 A가 인쇄되고 긴 프로세스가 시작되고 완료 될 때까지 기다린 다음 B를 인쇄합니다.
코 루틴은 어떤 식 으로든 스레딩에 절대적으로 아무런 관련이 없음을 항상 기억해야합니다. 이 코드로 :
Debug.Log("A");
StartCoroutine(LongProcess());
Debug.Log("B");
백그라운드에서 다른 스레드에서 LongProcess를 시작하는 것과 같은 것으로 생각하는 것은 쉽습니다. 그러나 그것은 절대적으로 올바르지 않습니다. 그것은 단지 코 루틴 일뿐입니다. 게임 엔진은 프레임 기반이며, Unity의 "coroutines"는 단순히 프레임에 액세스 할 수있게 해줍니다.
웹 요청이 완료되기를 기다리는 것은 매우 쉽습니다.
void Start() {
string url = "http://google.com";
WWW www = new WWW(url);
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www) {
yield return www;
if (www.error == null) {
//use www.data);
}
else {
//use www.error);
}
}
완전성을 위해 : 매우 드물게 Unity에서 고정 된 업데이트를 사용합니다; 일반적으로 사용되지 않는 WaitForFixedUpdate()
호출이 있습니다. 개발 중에 화면 캡처를 생성하는 것과 관련된 특정 상황에서 사용되는 특정 호출 (Unity의 현재 버전에서는 WaitForEndOfFrame()
)이 있습니다. Unity가 진화하면 정확한 메커니즘이 약간 변경되므로 관련된 경우 최신 정보도 검색하십시오.