Unityで学ぶ async/await ― TextMeshProで非同期処理を実装する方法
目次
TL;DR
- Thread.Sleep などの同期待機は UIをフリーズさせる
- Unity では async/await を使うことで 待機中でもUIが動き続ける
- Task.Delay を使えば簡単に「待機付き処理」が書ける
- TextMeshPro (TMP) を使うと見やすいラベル更新が可能
- 処理中はボタンを無効化して 二重クリック防止 を実装すると安全
はじめに
C# の学習を進めていると「同期処理」と「非同期処理」の違いに直面します。
Windows Forms では Thread.Sleep を使うと UI が固まり、ユーザー体験が悪化します。
Unity でも同じで、重い処理や強制待機をそのまま実行するとゲームがフリーズしてしまいます。
そこで登場するのが async/await 構文です。
この記事では、Unity で async/await を使い ボタンを押すと数秒待機してラベルが変わるアプリ を TextMeshPro を使って実装します。
同期処理の例(ダメなパターン)
まず、典型的な「UIが固まる」処理を見てみましょう。
// Windows Forms 版
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "処理中...";
Thread.Sleep(5000); // 5秒間待機
label1.Text = "処理が完了しました";
}
この場合、ラベルの文字は変わりますが、5秒間はボタンやフォーム全体が応答不能になります。
Unity で同じことをやっても「ゲームが一時停止したように固まる」ので実用的ではありません。
Unityでの非同期処理 ― async/await を使う
Unity では以下のように書き換えられます。
サンプルコード(TextMeshPro版)
using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class AsyncAwaitSampleTMP : MonoBehaviour
{
[Header("UI (インスペクターでアサイン)")]
[SerializeField] private Button button1;
[SerializeField] private TMP_Text label1;
private CancellationTokenSource _cts;
private bool _isProcessing;
private void Awake()
{
_cts = new CancellationTokenSource();
}
private void OnEnable()
{
button1.onClick.AddListener(OnButtonClick);
}
private void OnDisable()
{
button1.onClick.RemoveListener(OnButtonClick);
}
private void OnDestroy()
{
_cts.Cancel();
_cts.Dispose();
}
private async void OnButtonClick()
{
if (_isProcessing) return;
_isProcessing = true;
button1.interactable = false;
label1.text = "処理中...";
try
{
// UIを止めずに5秒間待機
await Task.Delay(5000, _cts.Token);
label1.text = "処理が完了しました";
}
catch (TaskCanceledException)
{
label1.text = "処理はキャンセルされました";
}
finally
{
_isProcessing = false;
button1.interactable = true;
}
}
}
セットアップ手順(Unityエディター)
- Canvas を作成
- Hierarchy → 右クリック → UI → Canvas
- UI を配置
- Canvas 内に Button (TextMeshPro) を追加 → 名前は StartButton
- Canvas 内に Text (TextMeshPro) を追加 → 名前は StatusLabel
- スクリプトを配置
- 空の GameObject(例:GameController)を作成
- 上記スクリプトをアタッチ
- インスペクターで button1 に StartButton、label1 に StatusLabel をドラッグ
実行結果
- ボタンを押すと「処理中…」が表示
- 5秒間待機(UIは操作可能)
- 「処理が完了しました」に更新
- 処理中はボタンが押せないので二重実行も防止
コルーチンとの比較
Unity ではコルーチンでも同じことができます。
IEnumerator SampleCoroutine()
{
label1.text = "処理中...";
yield return new WaitForSeconds(5);
label1.text = "処理が完了しました";
}
- コルーチン → Unity独自の仕組み。ゲーム開発でよく使う。
- async/await → C# 標準の非同期構文。外部APIやファイルI/Oとも相性が良い。
どちらを使うかは用途次第ですが、C#の知識を活かしたいなら async/await が便利です。
まとめ
- Thread.Sleep のような同期待機は Unity でも UI を止めてしまう
- async/await を使うと 処理を待ちながらUIを更新できる
- Task.Delay はコルーチンの WaitForSeconds に相当
- TextMeshPro を組み合わせることで見やすいUIを構築可能
- ボタン無効化やキャンセル処理を入れると実用的
訪問数 6 回, 今日の訪問数 6回
ディスカッション
コメント一覧
まだ、コメントがありません