ChatGPTにコルーチンで書かれたスクリプトを渡して、UniTaskに書き換えてもらいました。
ChatGPT
はじめは async/await に書き直すだけの指示をしました。
以下のスクリプトをasync/awaitを使って書き直してください。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FadeImageTest : MonoBehaviour
{
[SerializeField] Text text;
[SerializeField] Image image;
[SerializeField] float fadeSpeed = 0.001f;
private void Start()
{
State = VisibilityState.Visible;
}
enum VisibilityState
{
Visible,
FadingOut,
Invisible,
FadingIn
}
VisibilityState state;
VisibilityState State { get => state;
set
{
state = value;
text.text = state + "";
}
}
public void StartFadeInOrOut()
{
StopAllCoroutines();
switch(State)
{
default:
case VisibilityState.Visible:
case VisibilityState.FadingIn:
StartCoroutine("FadeOut");
break;
case VisibilityState.FadingOut:
case VisibilityState.Invisible:
StartCoroutine("FadeIn");
break;
}
}
IEnumerator FadeOut()
{
State = VisibilityState.FadingOut;
var color = image.color;
while(color.a >= 0f)
{
yield return null;
color.a -= fadeSpeed;
image.color = color;
}
color.a = 0f;
image.color = color;
State = VisibilityState.Invisible;
}
IEnumerator FadeIn()
{
State = VisibilityState.FadingIn;
var color = image.color;
while (color.a <= 1f)
{
yield return null;
color.a += fadeSpeed;
image.color = color;
}
color.a = 1f;
image.color = color;
State = VisibilityState.Visible;
}
}
すると、UniTaskも使うように書き換えてくれました。
C#でasync/awaitを使うことは、非同期処理を行う時に特に便利ですが、Unityの主な非同期パターンはコルーチンを用いたものです。これはUnityが特にゲームループとフレーム更新に基づく動作を行い、その中で非同期操作を行うためです。そのため、C#の一般的なasync/awaitの書き方がUnityのコンテキストで直接使えない場合があります。
ただし、非公式ながらも一部のライブラリではasync/awaitをUnityで使えるようにするための機能が提供されています。その一つがUniTaskライブラリです。このライブラリを使用することで、Unityでasync/awaitを用いた非同期処理を行うことが可能になります。
以下に示すコードは、上記のコードをUniTaskを使用してasync/awaitで書き直したものです。ただし、このコードを動作させるには、UniTaskライブラリをプロジェクトにインポートする必要があります。
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Threading;
public class FadeImageTest : MonoBehaviour
{
[SerializeField] Text text;
[SerializeField] Image image;
[SerializeField] float fadeSpeed = 0.001f;
private CancellationTokenSource cancellationTokenSource;
private void Start()
{
State = VisibilityState.Visible;
}
enum VisibilityState
{
Visible,
FadingOut,
Invisible,
FadingIn
}
VisibilityState state;
VisibilityState State
{
get => state;
set
{
state = value;
text.text = state + "";
}
}
public void StartFadeInOrOutWrapper()
{
// Cancel the previous task if it was running
cancellationTokenSource?.Cancel();
cancellationTokenSource = new CancellationTokenSource();
_ = StartFadeInOrOut(cancellationTokenSource.Token);
}
public async UniTask StartFadeInOrOut(CancellationToken token)
{
switch (State)
{
default:
case VisibilityState.Visible:
case VisibilityState.FadingIn:
await FadeOut(token);
break;
case VisibilityState.FadingOut:
case VisibilityState.Invisible:
await FadeIn(token);
break;
}
}
async UniTask FadeOut(CancellationToken token)
{
State = VisibilityState.FadingOut;
var color = image.color;
while (color.a >= 0f)
{
await UniTask.Yield();
token.ThrowIfCancellationRequested();
color.a -= fadeSpeed;
image.color = color;
}
color.a = 0f;
image.color = color;
State = VisibilityState.Invisible;
}
async UniTask FadeIn(CancellationToken token)
{
State = VisibilityState.FadingIn;
var color = image.color;
while (color.a <= 1f)
{
await UniTask.Yield();
token.ThrowIfCancellationRequested();
color.a += fadeSpeed;
image.color = color;
}
color.a = 1f;
image.color = color;
State = VisibilityState.Visible;
}
}
ボタンクリックでの実行や、非同期処理のキャンセル等ができるように修正指示をしてうまく書き換わりました。
使い方
シーンにCanvasとテキスト、Image、ボタンを追加します。
Canvasに上記スクリプトを付け、テキストとImageオブジェクトをアタッチしています。
ボタンのOnClickにスクリプトのStartFadeInOrOutWrapperメソッドを設定します。
スクリプト詳細
using Cysharp.Threading.Tasks;
UniTaskを使用するためのライブラリをインポートします。
using UnityEngine;
Unityの基本的なクラスを使用するためにUnityエンジンの名前空間をインポートします。
using UnityEngine.UI;
UI要素(ここではTextとImage)を使用するための名前空間をインポートします。
using System;
.NETの基本的なクラスを使用するための名前空間をインポートします。
using System.Threading;
CancellationTokenを使用するための名前空間をインポートします。
public class FadeImageTest : MonoBehaviour
MonoBehaviourを継承した新しいクラス、FadeImageTestを定義します。MonoBehaviourはUnityエンジンが提供する基本的なクラスで、ゲームオブジェクトにアタッチして使用するスクリプトの基底クラスです。
[SerializeField] Text text;
[SerializeField] Image image;
[SerializeField] float fadeSpeed = 0.001f;
スクリプトが操作する対象のUI要素とフェード速度を設定します。SerializeFieldはUnityエディタから値を設定できるようにするアノテーションです。デフォルトのフェード速度は0.001です。
private CancellationTokenSource cancellationTokenSource;
非同期タスクをキャンセルするためのCancellationTokenSourceを定義します。新しいフェード操作が始まるたびにこれを更新し、前の操作をキャンセルします。
private void Start()
Unityのライフサイクルメソッドの一つで、ゲームオブジェクトがアクティブになったときに一度だけ実行されます。
State = VisibilityState.Visible;
ゲームオブジェクトが開始時には見える状態であることを表します。これは初期状態を設定するためです。
enum VisibilityState
VisibilityStateという新しい列挙型を定義します。これは画像の可視状態を表します。4つの値(Visible、FadingOut、Invisible、FadingIn)を持つことができます。
VisibilityState state;
現在の可視状態を保持するプライベートフィールドを定義します。デフォルトの状態はVisibilityState.Visibleです。
VisibilityState State
可視状態を操作するためのプロパティを定義します。このプロパティのsetアクセサーでは、状態を更新するたびにその状態をテキストフィールドに表示します。
public void StartFadeInOrOutWrapper()
外部から非同期のフェード操作を開始するための公開メソッドを定義します。
cancellationTokenSource?.Cancel();
cancellationTokenSource = new CancellationTokenSource();
もし既に進行中の非同期操作がある場合はそれをキャンセルし、新しいCancellationTokenSourceを作成します。
_ = StartFadeInOrOut(cancellationTokenSource.Token);
作成したCancellationTokenを使用して非同期のフェード操作を開始します。ここでは戻り値を無視しています(_ =)。
public async UniTask StartFadeInOrOut(CancellationToken token)
非同期のフェード操作を実行するメソッドを定義します。現在の状態に応じてフェードインまたはフェードアウトの操作を選択します。キャンセルトークンを受け取り、これを各フェード操作に渡します。
async UniTask FadeOut(CancellationToken token)
フェードアウト操作を定義します。状態をFadingOutに設定し、透明度が0になるまで徐々に減らします。キャンセルが要求された場合は即座に操作を中断します。
async UniTask FadeIn(CancellationToken token)
フェードイン操作を定義します。状態をFadingInに設定し、透明度が1になるまで徐々に増やします。キャンセルが要求された場合は即座に操作を中断します。
このスクリプトでは、フェードインとフェードアウトの操作を非同期に実行し、その操作が途中でキャンセルされる可能性を考慮しています。これにより、複数のフェード操作が同時に起きた場合でも、古い操作が新しい操作によって正しくキャンセルされ、画像のフェード状態が正確に管理されます。