サーチ…
構文
- パブリックCoroutine StartCoroutine(IEnumeratorルーチン);
- public Coroutine StartCoroutine(文字列methodName、オブジェクト値= null);
- public void StopCoroutine(string methodName);
- public void StopCoroutine(IEnumeratorルーチン);
- public void StopAllCoroutines();
備考
パフォーマンスの考慮事項
柔軟性にはパフォーマンスコストが伴うため、コルーチンを適度に使用することが最善です。
- Coroutinesは、標準的なUpdateメソッドよりもCPUからの要求が多い。
- ユニティボクシングの
MoveNext
戻り値のためにコルーチンが各更新サイクルでゴミを生ずるUnityのいくつかのバージョンでは問題があります。これは5.4.0b13で最後に観察された。 ( バグレポート )
YieldInstructionsをキャッシュしてゴミを減らす
コルーチンで生成されるゴミを減らすための一般的なトリックは、 YieldInstruction
をキャッシュすることYieldInstruction
。
IEnumerator TickEverySecond()
{
var wait = new WaitForSeconds(1f); // Cache
while(true)
{
yield return wait; // Reuse
}
}
null
を返すと、余分なガベージが発生しません。
コルーチン
まず、ゲームエンジン(Unityなど)が「フレームベース」のパラダイムで動作することを理解することが不可欠です。
コードはすべてのフレームで実行されます。
これにはUnityのコードとコードが含まれます。
フレームについて考えるとき、フレームがいつ発生するかは絶対に保証されないことを理解することが重要です。彼らは定期的なビートで起こることはありません。フレーム間のギャップは、例えば、0.02632、0.021167、0.029778などとすることができる。この例では、すべて「約」1/50秒ですが、それらはすべて異なります。そして、いつでも、あなたはより長い、またはより短い時間がかかるフレームを得るかもしれません。フレーム内でいつでもコードを実行することができます。
それを念頭に置いて、あなたは質問するかもしれません:どのようにしてこれらのフレームにあなたのコード、Unityでアクセスしますか?
簡単に言うと、Update()コールを使用するか、コルーチンを使用します。 (まったく同じことです。つまり、フレームごとにコードを実行することができます)。
コルーチンの目的は次のとおりです。
いくつかのコードを実行して、 将来のフレームまで 「停止して待つ」ことができます。
次のフレームまで待つことができます。また、いくつかのフレームを待つこともできますし、将来的にはおおよその時間(秒単位)を待つこともできます。
たとえば、約1秒間待つことを意味する「約1秒」を待つことができます。そして、およそ1秒後にコードをいくつかのフレームに入れます。 (実際、そのフレーム内では、いつでもコードを実行することができます)。繰り返すには、ちょうど1秒ではありません。正確なタイミングは、ゲームエンジンでは意味がありません。
コルーチン内:
1つのフレームを待つには:
// do something
yield return null; // wait until next frame
// do something
3つのフレームを待つには:
// do something
yield return null; // wait until three frames from now
yield return null;
yield return null;
// do something
約 0.5秒待つ:
// do something
yield return new WaitForSeconds (0.5f); // wait for a frame in about .5 seconds
// do something
1つのフレームごとに何かする:
while (true)
{
// do something
yield return null; // wait until the next frame
}
この例は、Unityの「Update」コールの中に何かを入れることとまったく同じです。「何かをする」というコードは、すべてのフレームで実行されます。
例
TickerをGameObject
添付し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();
}
呼び出し元から特定のコルーチンを停止する方法は、起動方法によって異なります。
コルーチンを文字列名で開始した場合:
StartCoroutine("YourAnimation");
StopCoroutineを同じ文字列名で呼び出すことで停止できます。
StopCoroutine("YourAnimation");
または、コルーチンメソッドによって返されたIEnumerator
または StartCoroutine
によって返されるCoroutine
オブジェクトのいずれかへの参照を保持し、それらのいずれかでStopCoroutine
を呼び出す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メソッド
コルーチンにすることができる3つの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();
}
}
コルーチンの連鎖
コルーチンは内部で収穫し、 他のコルーチンを待つことができます。
だから、あなたは "もう一つの鎖"を連鎖させることができます。
これは非常に簡単で、Unityの中核となる基本技術です。
ゲームでは、特定のことが「順番どおりに」起こらなければならないのは当然のことです。ゲームのほぼすべての「ラウンド」は、時間の経過と共に、何らかの順序で起こっている一連のイベントから始まります。カーレースのゲームを始める方法は次のとおりです。
IEnumerator BeginRace()
{
yield return StartCoroutine(PrepareRace());
yield return StartCoroutine(Countdown());
yield return StartCoroutine(StartRace());
}
だから、BeginRaceを呼び出すと...
StartCoroutine(BeginRace());
それはあなたの "準備レース"ルーチンを実行します。 (おそらく、いくつかのライトを点滅させ、いくつかの群衆の騒音を鳴らし、スコアをリセットするなど)。これが終了すると、おそらくUIのカウントダウンをアニメーション化する「カウントダウン」シーケンスが実行されます。それが終わると、レーススタートコードが実行され、サウンドエフェクトを実行したり、AIドライバを起動したり、カメラを特定の方法で移動させたりします。
わかりやすくするために、3つの呼び出し
yield return StartCoroutine(PrepareRace());
yield return StartCoroutine(Countdown());
yield return StartCoroutine(StartRace());
コルーチンの中にいる必要があります 。つまり、 IEnumerator
型の関数でなければなりません。したがって、この例ではIEnumerator BeginRace
です。したがって、「通常の」コードから、 StartCoroutine
コールでそのコルーチンを起動します。
StartCoroutine(BeginRace());
連鎖をさらに理解するために、コルーチンを連鎖させる関数があります。コルーチンの配列を渡します。この関数は、順番に、順番に多くのコルーチンを実行します。
// 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;
}
ここでそれをどのように呼び出すかを説明します.3つの機能があるとしましょう。彼らはすべて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 ) );
繰り返すには、ゲームの最も基本的な要件の1つは、時間の経過とともにある種のものが次々と「シーケンス内で」起こるということです。あなたは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の「コルーチン」は単にフレームにアクセスすることができます。
Webリクエストが完了するのを待つのはとても簡単です。
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が進化するにつれて、正確な仕組みが少し変わるので、関連性があるならば、最新の情報をgoogleに送ってください。)