Unityで一定時間ごとに実行されるメソッドの実装方法まとめ

Unityでは、プロジェクトの要件に応じて、さまざまな方法で一定時間ごとに処理を実行することが可能です。ここでは、基本的な方法と、より高度な実装手法をすべてまとめています。


1. 基本的なタイマー処理

1.1 InvokeRepeating を使う方法

概要

InvokeRepeating は、指定した遅延後から一定間隔でメソッドを自動的に呼び出します。シンプルなタイマー処理に適しています。

実装例

void Start()
{
    // 2秒後に "MyMethod" を呼び出し、その後は毎秒実行する
    InvokeRepeating("MyMethod", 2f, 1f);
}

void MyMethod()
{
    Debug.Log("InvokeRepeatingで実行されるメソッド");
}

1.2 コルーチンを使う方法

概要

コルーチンを利用することで、WaitForSeconds を用いた待機処理を実装できます。非同期処理や、柔軟なタイミング制御が必要な場合に有効です。

実装例

void Start()
{
    StartCoroutine(ExecuteEverySecond());
}

IEnumerator ExecuteEverySecond()
{
    while (true)
    {
        Debug.Log("コルーチンで実行されるメソッド");
        yield return new WaitForSeconds(1f); // 1秒待機
    }
}

1.3 Time.deltaTime を使った方法

概要

Update メソッド内で Time.deltaTime を累積し、指定した間隔に達した時点で処理を実行する方法です。フレーム単位の経過時間を管理するため、柔軟なタイミング制御が可能です。

実装例

public class TimerExample : MonoBehaviour
{
    // 一定時間(秒)
    public float interval = 1f;
    // 経過時間を保持する変数
    private float elapsedTime = 0f;

    void Update()
    {
        // 毎フレームの経過時間を加算
        elapsedTime += Time.deltaTime;

        // 経過時間が設定した間隔を超えたら処理を実行
        if (elapsedTime >= interval)
        {
            Debug.Log("Time.deltaTimeを利用して一定時間ごとに実行されるメソッド");
            // 経過時間をリセット(超過分を保持する場合は elapsedTime -= interval; とする)
            elapsedTime = 0f;
        }
    }
}

1.4 FixedUpdate の役割

概要

FixedUpdate は物理演算処理向けに一定の間隔で呼び出されるため、物理計算が絡む場合に使用します。一般的なタイマー処理では、上記の手法(InvokeRepeating、コルーチン、Time.deltaTime)を使うほうが柔軟です。


2. 高度なタイマー処理

2.1 Async/Await を使った方法

概要

C# の async/await 機能を利用し、Task.Delay による待機処理を実装する方法です。Unity 2017以降で利用可能ですが、メインスレッドへの復帰に注意が必要です。

実装例

using System.Threading.Tasks;
using UnityEngine;

public class AsyncTimerExample : MonoBehaviour
{
    public float interval = 1f;

    async void Start()
    {
        while (true)
        {
            Debug.Log("async/await で実行されるメソッド");
            await Task.Delay((int)(interval * 1000)); // ミリ秒に変換して待機
        }
    }
}

2.2 UniRx(Reactive Extensions for Unity)を利用する方法

概要

UniRxは、Unity向けのReactive Extensionsライブラリです。オブザーバブルなタイマー処理がシンプルに実装でき、複雑なイベントの統合や非同期処理にも対応できます。※ UniRxの利用にはパッケージのインポートが必要です。

実装例

using UniRx;
using UnityEngine;
using System;

public class UniRxTimerExample : MonoBehaviour
{
    void Start()
    {
        // 1秒ごとにタイマーイベントを発行
        Observable.Interval(TimeSpan.FromSeconds(1))
            .Subscribe(_ => Debug.Log("UniRxで実行されるメソッド"))
            .AddTo(this); // MonoBehaviourのライフサイクルに合わせて購読管理
    }
}

2.3 カスタムタイマー管理クラスの実装

概要

プロジェクトの規模や複雑さに応じて、複数のタイマーを一括で管理するカスタムなタイマーシステムを実装する方法です。タイマーの登録、停止、再開などを一元管理できるため、複数イベントの同時管理や高度な制御が可能です。

実装例(基本的な概念例)

using System;
using System.Collections.Generic;
using UnityEngine;

public class TimerManager : MonoBehaviour
{
    private class Timer
    {
        public float Interval;
        public float Elapsed;
        public Action Callback;
    }

    private List<Timer> timers = new List<Timer>();

    // タイマーを追加するメソッド
    public void AddTimer(float interval, Action callback)
    {
        timers.Add(new Timer { Interval = interval, Callback = callback, Elapsed = 0f });
    }

    void Update()
    {
        // 各タイマーの経過時間を更新し、実行判定を行う
        for (int i = timers.Count - 1; i >= 0; i--)
        {
            Timer timer = timers[i];
            timer.Elapsed += Time.deltaTime;
            if (timer.Elapsed >= timer.Interval)
            {
                timer.Callback?.Invoke();
                // 一度実行したタイマーを削除(リピートの場合はここを調整)
                timers.RemoveAt(i);
            }
        }
    }
}

このコードは、Unityで複数のタイマー(一定時間経過後に一度だけまたは繰り返し実行される処理)を管理するためのカスタムなタイマーシステムの例です。以下、各部分について詳しく説明します。


1. TimerManager クラス

  • MonoBehaviour の継承
    TimerManagerMonoBehaviour を継承しているため、Unityのゲームオブジェクトにアタッチして利用できます。これにより、UpdateメソッドなどのUnityライフサイクルイベントを活用できます。

2. Timer クラス

  • 内部クラスとして定義
    TimerTimerManager 内に定義されたプライベートな内部クラスです。外部から直接アクセスできないため、タイマーの実装を隠蔽しています。
  • プロパティ
  • public float Interval;
    タイマーが動作するまでの待機時間(秒単位)を指定します。
  • public float Elapsed;
    タイマーが開始されてから経過した時間を管理するための変数です。
  • public Action Callback;
    指定した時間が経過した際に呼び出すメソッド(コールバック関数)を保持します。

3. タイマーリストの管理

  • List timers
    TimerManager クラス内で、複数のタイマーを保持するために List<Timer> を使用しています。新しいタイマーはこのリストに追加され、Updateメソッドで逐次更新されます。

4. AddTimer メソッド

  • タイマーの登録
    public void AddTimer(float interval, Action callback) メソッドは、タイマーをリストに追加するためのメソッドです。
  • interval:待機する秒数。
  • callback:待機時間が経過したときに実行される処理。
  • 初期化
    タイマーは Elapsed0f に初期化し、指定された intervalcallback を設定してリストに追加されます。

5. Update メソッド

  • 毎フレーム実行
    Update メソッドはUnityのフレーム毎の更新処理です。ここで各タイマーの経過時間を更新し、実行判定を行います。
  • 逆順ループ
    タイマーリストを逆順(後ろから)にループする理由は、リストから要素を削除する場合にインデックスのズレが起こらないようにするためです。
  • タイマーの更新と実行判定
    • timer.Elapsed += Time.deltaTime;
      各フレームで経過時間を Time.deltaTime (前フレームからの経過時間)だけ増加させます。
    • if (timer.Elapsed >= timer.Interval)
      経過時間が設定した間隔以上になったら、
      • timer.Callback?.Invoke(); でコールバックを実行します。
      • timers.RemoveAt(i); でタイマーをリストから削除します。
        ※ この実装では、一度実行したタイマーは削除されるため、繰り返し実行されるタイマーを実装する場合は、削除処理の部分を調整する必要があります。

6. 応用例と注意点

  • 繰り返しタイマーの実装
    上記のコードは一度実行されるタイマーとして実装されています。もし繰り返し実行したい場合は、タイマーの Elapsed をリセットするか、タイマーの削除条件を変更する必要があります。
  • 拡張性
    このカスタムタイマー管理システムは、プロジェクトの要件に合わせてタイマーの追加、停止、再開などの高度な管理機能に拡張することが可能です。

このように、このコードはシンプルながら柔軟なタイマー管理システムの基本的な実装例となっており、複数のタイマーを同時に管理する必要がある場合に役立ちます。


3. まとめ

  • 基本的な手法
    • InvokeRepeating: シンプルな実装で、決まった間隔でメソッドを呼び出すのに適している。
    • コルーチン: 柔軟な待機処理が可能で、非同期処理や複雑なタイミング制御が実現できる。
    • Time.deltaTime: Update内でのフレーム単位の時間管理により、細かいタイミング制御が可能。
    • FixedUpdate: 主に物理演算向け。一般的なタイマー処理には他の手法が推奨される。
  • 高度な手法
    • Async/Await: C#の非同期処理機能を活用。シンプルな待機処理が可能だが、メインスレッドとの調整に注意。
    • UniRx: Reactive Extensionsを利用して、オブザーバブルなタイマー処理が実装でき、複数イベントの統合に強みがある。
    • カスタムタイマー管理: 複数のタイマーを柔軟に管理するための仕組み。大規模・複雑なプロジェクト向け。

各手法にはメリットと留意点があり、用途やプロジェクトの規模、求める柔軟性に応じて最適な方法を選択してください。

Unity

Posted by hidepon