Unityでゲームを開発していると非同期で処理をしたいということがあります。
- 重い処理を実行してゲームがフリーズする!
- データをダウンロードする間に他の処理を進めたい!
Unityでは、「同期処理(Synchronous)」と「非同期処理(Asynchronous)」を正しく使うことで、スムーズなゲーム体験を提供できます。
この記事では、同期・非同期の違い、コルーチンの使い方、async/awaitの活用方法、マルチスレッド処理の実践方法まで詳しく解説します!
この記事でわかること
- 同期処理と非同期処理の違い
- コルーチン(Coroutine)を使った非同期処理
- async/await を使った非同期プログラミング
- スレッド(Thread)を使った処理
同期処理(Synchronous)とは?
同期処理の特徴
同期処理とは、1 つの処理が終わるまで次の処理を待つ仕組みです。
ゲームのメインスレッドで実行される処理は基本的に同期処理になります。
➡ 処理が順番に実行されるので、デバッグが簡単
➡ 計算負荷の高い処理を実行すると、ゲームがフリーズする
//同期処理の例
void Start()
{
Debug.Log("処理開始");
HeavyProcessing(); // 時間がかかる処理
Debug.Log("処理終了");
}
void HeavyProcessing()
{
for (int i = 0; i < 10000000; i++) { }
}
※ デバッグについては以下のサイトを参考にしてください。
非同期処理(Asynchronous)とは?
非同期処理の特徴
非同期処理とは、処理が終わるのを待たずに、他の処理を並行して実行する仕組みです。
➡ ゲームが止まらず、スムーズに動作する!
➡ 重い処理(データロード・ダウンロードなど)を別スレッドで処理できる!
コルーチン(Coroutine)を使った非同期処理
コルーチン(Coroutine)の使い方
Unityで非同期処理を行う最も一般的な方法は、コルーチン(Coroutine)を使うことです。
コルーチンを使えば、特定の処理を一時停止し、一定時間後に再開することができます。
コルーチン(Coroutine)の基本
・ yield returnを使って非同期処理を実装
using UnityEngine;
using System.Collections;
public class CoroutineExample : MonoBehaviour
{
void Start()
{
Debug.Log("データロード開始");
StartCoroutine(LoadData());
Debug.Log("データロード完了(同期)");
}
IEnumerator LoadData()
{
yield return new WaitForSeconds(3); // 3秒待つ
Debug.Log("データロード完了(非同期)");
}
}
※ コルーチン(Coroutine)については以下のサイトを参考にしてください。
SceneManager.LoadSceneAsync()で非同期ロード
・非同期でシーンをロードし、進捗状況を表示可能!
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
//SceneManager.LoadSceneAsync()を使った非同期シーンロード
public class SceneLoader : MonoBehaviour
{
public void LoadNewScene()
{
StartCoroutine(LoadSceneAsync("GameScene"));
}
IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
while (!operation.isDone)
{
Debug.Log("ロード進捗: " + (operation.progress * 100) + "%");
yield return null;
}
}
}
※ SceneManagerについては以下のサイトを参考にしてください。
async/awaitを使った非同期処理
async/await とは?
async/await使うとより直感的に非同期処理を記述できます。
➡ コルーチンよりもスムーズな非同期処理が書ける!
➡ I/O 処理(Web API・ファイル読み込み)に最適!
async/await の基本
・awaitを使えば、コルーチンなしで非同期処理を記述可能!
using System.Threading.Tasks;
using UnityEngine;
//Task.Delay()を使った非同期処理
public class AsyncExample : MonoBehaviour
{
async void Start()
{
Debug.Log("処理開始");
await WaitForSecondsAsync(3);
Debug.Log("3秒後に処理実行");
}
async Task WaitForSecondsAsync(int seconds)
{
await Task.Delay(seconds * 1000);
}
}
Webリクエストを非同期処理
・ Web APIからデータを取得し、ゲームに反映可能!
using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;
//HttpClientを使った非同期ダウンロード
public class WebRequestExample : MonoBehaviour
{
async void Start()
{
string data = await FetchDataAsync("https://example.com/api");
Debug.Log("取得データ: " + data);
}
async Task<string> FetchDataAsync(string url)
{
using HttpClient client = new HttpClient();
return await client.GetStringAsync(url);
}
}
Thread(スレッド)を使ったライブラリ処理
Thread(スレッド)の基本
Thread(スレッド)を使うと重い処理を別スレッドで実行し、メインスレッドをブロックしないようにできます。
➡ 別スレッドで処理を実行し、メインスレッドの動作を止めない!
※ Thread(スレッド)を使用する際にひと手間あった気がするので、もしあれば他サイトを参考にしてください。
//Threadを使った並列処理
using System.Threading;
using UnityEngine;
public class ThreadExample : MonoBehaviour
{
void Start()
{
Thread thread = new Thread(HeavyProcessing);
thread.Start();
}
void HeavyProcessing()
{
for (int i = 0; i < 10000000; i++) { }
Debug.Log("処理完了");
}
}
まとめ
・同期処理(Synchronous)は順番に実行され、ブロックされることがある!
・コルーチン(Coroutine)を使う、時間経過や非同期処理を簡単に実装可能
・スムーズなasync/await非同期処理が書ける