# Unityで待機ができる処理：非同期処理

## 概念

Unityのスクリプトでは、`Start()`、`Update()`、`OnTriggerEnter()` などの定めたときに実行するメソッドがある（初期の時、フレーム毎、トリガーに入った）

この機能が大変便利であるが、ゲームを開発中には、上記のメソッドを呼び出される瞬間ではなく、少し時間たってから実行したい場合もたくさんある。

例えば：

- 体力がゼロになった場合、すぐにゲームオーバーを表示するのではなく、主人公が倒れるアニメーションを再生し終わってからゲームオーバーを表示したい。
- ローディング画面を表示し、次のステージの準備ができてからシーンを切り替える。
- サイコロをランダムに回し、プレーヤーを「停止」を押してからすごろくのコマを進む。

この場合は「待機」が発生する。何かの条件を満たすまで待たないといけない。Unityでは２つの作戦がある：コルーチン と Awaitable.

### コルーチン

コルーチンの書き方は以下の通りである

```c#
private IEnumerator コルーチン名 (引数)
{
  // 処理
  // yield return 待機命令
  // 処理
  // yield return 待機命令
  // ...
}
```

普通のメソッドとよく似ているが、戻り値は必ず `IEnumerator` になる。そして、中には普通の処理を行い、待機命令を見つけたらコルーチンが一時停止し、待機が終わったら再開する流れになる。

なお、コルーチンを開始するのは、普通のメソッドとして呼び出すことではなく、以下の通りになる：

```c#
StartCoroutine(コルーチン名(引数));
```

また、待機命令は以下から選択ができる

<table border="1" class="align-center" id="bkmrk-%E5%91%BD%E4%BB%A4-%E5%8A%B9%E6%9E%9C-yield-return-n" style="border-collapse: collapse; width: 74.0476%; height: 122px; border-width: 1px;"><thead><tr style="height: 29.4667px;"><td class="align-center" style="width: 56.4929%; height: 29.4667px;">**命令**</td><td class="align-center" style="width: 43.6171%; height: 29.4667px;">**効果**</td></tr></thead><tbody><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`yield return null;`

</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">次のフレームまで待つ</td></tr><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`yield return new WaitForSeconds(秒数);`</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">定めた秒数を待機する</td></tr><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`yield return StartCoroutine(他のコルーチン);`</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">別のコルーチンが終わるまで待機する</td></tr></tbody></table>

この他にもいくつかの待機命令があるが、最も多く使うのは上記に３つである。

#### 例：READY → GO！

あるゲーム開始の時に、「READY」を２秒を表示した後、「GO!」を表示１秒表示し、その後ゲームを開始ができる処理を実装しようとしたら：

```c#
// ゲーム開始
public void StartGame()
{
	// コルーチンを開始
	StartCoroutine(ReadyGo());
}

// レディー → ゴー！を表示するコルーチン
private IEnumerator ReadyGo()
{
	// READY を表示
	Debug.Log("READY");
	
	// 2秒待機
	yield return new WaitForSeconds(2.0f);
	
	// GO! を表示
	Debug.Log("GO!");
	
	// 1秒待機
	yield return new WaitForSeconds(1.0f);

	// 実際にゲームを開始
	Debug.Log("ゲーム開始");
}
```

### Awaitable

Awaitable（アウェイタブル）は改善されたコルーチンといわれる。基本的に同じことするのが、書き方が少し難しくなる。

```c#
private async Awaitable 非同期処理 (引数)
{
  // 処理
  // await 待機命令
  // 処理
  // await 待機命令
  // ...
}
```

そして、開始するのは、普通のメソッドと同じである

```c#
非同期処理 (引数);
```

また、待機命令は以下の通りになる：

<table border="1" class="align-center" id="bkmrk-%E5%91%BD%E4%BB%A4-%E5%8A%B9%E6%9E%9C-await-awaitabl" style="border-collapse: collapse; width: 74.0476%; height: 122px; border-width: 1px;"><thead><tr style="height: 29.4667px;"><td class="align-center" style="width: 56.4929%; height: 29.4667px;">**命令**</td><td class="align-center" style="width: 43.6171%; height: 29.4667px;">**効果**</td></tr></thead><tbody><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`await Awaitable.NextFrameAsync();`

</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">次のフレームまで待つ</td></tr><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`await Awaitable.<span class="sig-kw">WaitForSecondsAsync</span>(秒数);`</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">定めた秒数を待機する</td></tr><tr style="height: 30.8px;"><td class="align-left" style="width: 56.4929%; height: 30.8px;">`await 他の非同期処理(引数);`</td><td class="align-left" style="width: 43.6171%; height: 30.8px;">別のAwaitableが終わるまで待機する</td></tr></tbody></table>

#### 例：READY → GO！

コルーチンで作った処理をAwaitableにすると：

```c#
// ゲーム開始
public void StartGame()
{
	// 処理開始
	ReadyGo();
}

// レディー → ゴー！を表示する非同期メソッド
private async Awaitable ReadyGo()
{
	// READY を表示
	Debug.Log("READY");
	
	// 2秒待機
	await Awaitable.WaitForSecondsAsync(2.0f);
	
	// GO! を表示
	Debug.Log("GO!");
	
	// 1秒待機
	await Awaitable.WaitForSecondsAsync(1.0f);

	// 実際にゲームを開始
	Debug.Log("ゲーム開始");
}
```