背景
Unityで、一定間隔毎に何か処理を実行したいときがあります。
例えば、接続デバイスの監視とか、デバッグログの出力とか。
そういうことがしたいとき、よく下記のようにしていました。
float _time;
void Update()
{
// 1秒ごとに実行
if (_time < Time.unscaledTime) {
_time = Time.unscaledTime + 1;
Debug.Log("kita");
}
}
問題ないのですが、メンバ変数を定義する必要があったりタイピング量が多いです。また、やりたいときに毎回この処理を書かないといけない。本番を想定した処理ではなく、開発中はテスト処理として確実に〇秒ごとではなくてもいいからもっと少ないコード量で書きたい。
ぱっと思いつくコードはあったのですが、まずはChatGPTに聞いてみました。
方法1: InvokeRepeatingを使用する方法
// 開始時に呼び出されるメソッド
void Start()
{
// 2秒ごとにMyMethodを呼び出す
InvokeRepeating("MyMethod", 0f, 2f);
}
void MyMethod()
{
// ここに一定間隔で実行したいコードを書く
Debug.Log("実行されました!");
}
InvokeRepeatingが提案されました。Invokeとか懐かしい…あまり使われないですよね。
この場合、キャンセル処理なども必要ですが提案はされませんでした。
余談ですが、SendMessage系関数やコルーチンも同じく、関数名文字列からコールするというのは特別な状況でない限りあまり利用することはないように思います。
方法2: Coroutineを使用する方法
void Start()
{
// StartCoroutineを使用してCoroutineを実行
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine()
{
while (true)
{
// ここに一定間隔で実行したいコードを書く
Debug.Log("実行されました!");
// 2秒待つ
yield return new WaitForSeconds(2f);
}
}
Coroutineが提案されました。UniTaskで書き始めてからCoroutineアレルギー🐛です。
WaitForSecondsをストアせず、毎回newしてるところが気になります。classを毎フレームnewするのは避けましょう。
しかしChatGPTはすごい!コメントまで入れてくれて優秀だ!
だけどコードが長いので、短くしてとお願いしてみましたが、僕の最初のコードと似たような形が出力され、良い案は得られず。
一番短いのはこれだ!
void Update()
{
if (Time.unscaledTime % 1f < Time.unscaledDeltaTime)
{
Debug.Log("kita");
}
}
くるのかな?と思ってたのですが割と正確にきていました。重い処理の場面では頻繁にすっ飛ぶと思います。記事を書いててもう一つ思い浮かびました。
void Update()
{
if (Time.frameCount % 60 == 0) // 60FPS固定なら、
{
Debug.Log("kita");
}
}
こっちの方が確実そう。フレームカウンタはどんなに重くてもすっ飛ばないはずだから確実にコールされる。だけど可変長フレームレート設定のプロジェクトでは一定間隔とは呼べなくなってしまうかもしれません。が、そもそも確実性を気にしない処理が対象なので問題なし。
以上。