😴 Unityで遅延処理をする方法色々
Unityは遅延処理を実現する方法がたくさんあってどれにしようか迷う事が多いのでメモメモ。
Invokeを使う方法
一番簡単に実装できる。けど引数を渡す事ができないのが難点。
void Start()
{
Invoke("DelayMethod", 1.0f);
}
private void DelayMethod()
{
Debug.Log("Invoke");
}
StartCoroutineを使う方法
StartCoroutine
はコルーチンの中で一定時間中断する処理を実行する。
呼び出される関数の方は内部でyield return
を実行して IEnumerator
のインスタンスを返す必要がある。
StartCoroutine
に渡すメソッドには遅延時間を引数として渡せるようにしておくと便利。
void Start()
{
Coroutine coroutine = StartCoroutine("DelayMethod", 1.0f);
}
private IEnumerator DelayMethod(float waitTime)
{
yield return new WaitForSeconds(waitTime);
Debug.Log("StartCoroutine");
}
キャンセルしたい場合には Coroutine coroutine = StartCoroutine()
で返ってくるコルーチンに StopCoroutine (coroutine);
を実行する事で止める事ができる。
また、下記のように仲介するメソッドを一つ作成しておけばアロー関数で書くことができるようになるのでさらに便利。
void Start()
{
Coroutine coroutine = StartCoroutine(DelayMethod(1.0f, () => {
Debug.Log("StartCoroutine");
}));
}
private IEnumerator DelayMethod(float waitTime, Action action)
{
yield return new WaitForSeconds(waitTime);
action();
}
さらにIEnumerator
のメソッドの方に引数を渡す処理を書けば int
や string
などの引数を渡すことができるようになるのでもっと便利。
void Start()
{
Coroutine coroutine = StartCoroutine(DelayMethod(1.0f, (int id) => {
Debug.Log("StartCoroutine: "+id);
}, 0));
}
private IEnumerator DelayMethod<T>(float waitTime, Action<T> action, T t)
{
yield return new WaitForSeconds(waitTime);
action(t);
}
Taskを使う方法
Task
は非同期で処理を実行してくれる。
使うにはまず System.Threading.Tasks
を読み込む必要がある。
using System.Threading.Tasks;
await
を使用して待機させるには、実行されるメソッドに async
が付与されている必要がある。
単純に1秒待たせたいだけならこんな感じで書ける。
private async void DelayMethod()
{
await Task.Delay(1000);
Debug.Log("DelayMethod");
}
自分でメソッドを作りたい場合にはこんな感じで書く。
async void Start()
{
await DelayMethod();
}
private async Task DelayMethod()
{
await Task.Delay(1000);
Debug.Log("DelayMethod");
}
引数を渡したり返したりもできる。
async void Start()
{
int id = await DelayMethod(1);
}
private async Task<int> DelayMethod(int id)
{
await Task.Delay(1000);
Debug.Log("DelayMethod: " + id);
return id;
}
Task.Run
とアロー関数を利用して無名関数で非同期処理を利用する事も可能。
この場合はasyncではないメソッドから呼び出す事が可能。
Task.Run(async () => {
await Task.Delay(1000);
print("Task.Run");
});
ラッパークラスを使う方法
また、小規模なプロジェクトで毎回色々処理を書くのが面倒な時などには、前述のコルーチンの処理を使用した自分用のオレオレラッパークラスを作成する方法もある。
ラッパークラスを使用すると下記のように簡単に記載できるようになるのでコードの可読性も上がるし、カスタマイズすれば自分好みの使用方法で遅延処理を実行する事ができるようになる。
Coroutine coroutine = DelayUtil.Delay (1.0f, (int id) => {
Debug.Log ("DelayUtil.Delay: "+id);
}, 10);
この例ではラッパークラスの中でGameObject
を作成し、その中でコルーチン処理を行っているので、キャンセルを実行したい場合には同じくラッパークラスのキャンセル用の関数DelayUtil.Stop(coroutine);
を呼び出す必要がある。
MonoBehaviourを拡張する方法
また、拡張メソッドをモリモリ使っているようなプロジェクトの場合、MonoBehaviour
を拡張する事でさらに簡単に書くこともできるようになる。
MonoBehaviorExtentsion.cs
の中ではMonoBehaviour
を拡張し、Delay
というメソッドを追加して、内部で前述の例と同様に作成したDelayMethod
を呼び出すようにしている。
Coroutine coroutine = this.Delay(1.0f, (int id) => {
print("Delay: "+id);
}, 0);
DOTweenを使う方法
DOTweenを入れているプロジェクトの場合には、ラッパークラスや拡張を行わなくてもDOTweenで用意されている関数を利用して遅延処理を行う事ができる。
DOVirtual.DelayedCall (1.0f, () => {
print ("DOVirtual.DelayedCall");
});
UniRxを使う方法
またUniRxを入れているプロジェクトの場合にも同様にUniRxに用意されている関数を利用して遅延処理を行う事ができる。
Timer
かTimerFrame
を使用して遅延させSubscribe
で実行する方法と
Timerを使用する方法:
Observable.Timer(TimeSpan.FromSeconds(1.0f))
.Subscribe(_ => {
print("UniRx Observable.Timer");
});
TimerFrameを使用する方法:
Observable.TimerFrame(1)
.Subscribe(_ => {
print("UniRx Observable.TimerFrame");
});
Delay
を使用する方法がある。
Delayを使用する方法:
Observable.Return(Unit.Default)
.Delay(TimeSpan.FromSeconds(1.0f))
.Subscribe(_ => {
print("UniRx Observable.Delay");
});
Delayを使用する方法(引数を渡したい時):
Observable.Return(0)
.Delay(TimeSpan.FromSeconds(1.0f))
.Subscribe((int id) => {
print("UniRx Observable.Delay: "+id);
});
- 2018-09-04 追記: UniRxの記述を追加しました。
- 2021-06-15 追記: 非同期処理の記述を追加しました。