Help us understand the problem. What is going on with this article?

【Unity】スクリプトの処理の実行タイミングを操作する

More than 1 year has passed since last update.

Unityでゲーム開発をしていると、「ある処理を一定時間後や特定のタイミングで実行したい」といった事がよくあるので、そのあたりのやり方をまとめてみました。

Unityの標準機能のみで書く場合

処理をn秒後に実行したい

Invokeを使う

private void Start()
{
    //DelayMethodを3.5秒後に呼び出す
    Invoke("DelayMethod", 3.5f);
}

void DelayMethod()
{
    Debug.Log("Delay call");
}

多分一番シンプルです。
Invokeを使うことで指定メソッドをn秒後に実行させることができます。
ただしメソッドを文字列指定しなくてはいけなかったり、メソッドに引数を渡すことができないなど使い勝手はそこまで良く無いです。

コルーチンを使う

private void Start()
{
    //3.5秒後に実行する
    StartCoroutine(DelayMethod(3.5f, () =>
    {
        Debug.Log("Delay call");
    }));
}

/// <summary>
/// 渡された処理を指定時間後に実行する
/// </summary>
/// <param name="waitTime">遅延時間[ミリ秒]</param>
/// <param name="action">実行したい処理</param>
/// <returns></returns>
private IEnumerator DelayMethod(float waitTime, Action action)
{
    yield return new WaitForSeconds(waitTime);
    action();
}

コルーチンとWaitForSecondsを組み合わせてあげるパターン。
Invokeと違ってタイプセーフだし、引数も渡せるしとこっちの方が何かと良いかと思います。
MonoBehaviourに拡張メソッドとして生やしておくと便利かも。

nフレーム後に実行したい

コルーチンを使う

private void Start()
{
    //5フレーム後に実行する
    StartCoroutine(DelayMethod(5, () =>
    {
        Debug.Log("Delay call");
    }));
}

/// <summary>
/// 渡された処理を指定時間後に実行する
/// </summary>
/// <param name="delayFrameCount"></param>
/// <param name="action">実行したい処理</param>
/// <returns></returns>
private IEnumerator DelayMethod(int delayFrameCount, Action action)
{
    for (var i = 0; i < delayFrameCount; i++)
    {
        yield return null;
    }
    action();
}

コルーチンでn秒待つ奴とそんなに変わらないです。
これも拡張メソッド化して生やしておくと便利かも。

UniRxを使う場合

n秒後に実行したい

Observable.Timerを使う

//ただ呼び出すパターン
//100ミリ秒後にLogを出す
Observable.Timer(TimeSpan.FromMilliseconds(100))
    .Subscribe(_ => Debug.Log("Delay call"));

//パラメータを渡すパターン
//現在のプレイヤの座標を500ミリ秒後に表示する
var playerPosition = transform.position;
Observable.Timer(TimeSpan.FromMilliseconds(500))
    .Subscribe(_ => Debug.Log("Player Position:" + playerPosition));

Timerを使うパターン。
パラメータを渡そうとするとストリーム外で値の保持が必要になるため、複数同時にタイマ登録すると事故る可能性があります。

Delayを使う

//ただ呼び出すパターン
//100ミリ秒後にLogを出す
Observable.Return(Unit.Default)
    .Delay(TimeSpan.FromMilliseconds(100))
    .Subscribe(_ => Debug.Log("Delay call"));

//パラメータを渡すパターン
//現在のプレイヤの座標を500ミリ秒後に表示する
Observable.Return(transform.position)
    .Delay(TimeSpan.FromMilliseconds(500))
    .Subscribe(p => Debug.Log("Player Position:" + p));

複数パラメータ渡したい場合はUniRx.Tupleを使うといいかも。

nフレーム後に実行したい

Observable.TimerFrameを使う

//次のフレームで実行する
Observable.TimerFrame(1)
    .Subscribe(_ => Debug.Log("Next Update"));

//次のFixedUpdateで実行する
Observable.TimerFrame(1,FrameCountType.FixedUpdate)
    .Subscribe(_ => Debug.Log("Next FixedUpdate"));

Observable.Timerとそれほど変わらないです。

DelayFrameを使う

//次のフレームで実行する
Observable.Return(Unit.Default)
    .DelayFrame(1)
    .Subscribe(_ => Debug.Log("Next Update"));

//次のFixedUpdateで実行する
Observable.Return(Unit.Default)
    .DelayFrame(1, FrameCountType.FixedUpdate)
    .Subscribe(_ => Debug.Log("Next FixedUpdate"));

Delayとそんなに変わらないです。

次のフレームで実行する

次のフレームで実行したいといった場合はNextFrameを使った方がスマート。

NextFrame
//次のフレームで実行する
Observable.NextFrame()
    .Subscribe(_ => Debug.Log("Next Frame"));

まとめ

ただ処理を遅延させたいだけならコルーチンで書いたほうが楽です。
処理を遅延させた後、まだ何か処理を続けるんであればUniRxでストリーム化した方がいろいろやりやすいです。

toRisouP
virtualcast
VRシステム(バーチャルキャスト)の開発、運営、企画
https://virtualcast.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした