[Phaser3]updateの中で指定時間ごとに処理を行うには

2022-3-1

目次

今回の題

Phaserのシーンの中で指定時間毎に処理を走らせるには以下のように、Phaser.Time.Clockを使います。

例:1.5秒毎に走る処理

this.time.addEvent({
  delay: 1500,
  callback: () => {
    console.log('1500ms経過');
  },
  loop: true,
});

大抵の場合はこれでいいと思います。
ただタイルマップにアニメーションをつける処理などを書いていると、delayの値をタイル毎に頻繁に切り替えたりする必要が出てきたりと、この方法では難しくなります。
ここで紹介するのは、そんなときに役立つ方法です。

updateの中で指定時間ごとに処理を行う

以下のようなコードになります。

update(time: number, delta: number): void {
  this.elapsedTime += delta;
  if (this.elapsedTime >= 3000) {
    console.log('3000ms経過');
    this.elapsedTime %= 3000;
  }
}

まず、注目すべきはupdate()の第2引数deltaです。
deltaには、前回update()が呼ばれてから今回のupdate()が呼ばれるまでの経過時間がミリ秒単位で入っています。60FPSでループが回っているなら大体16msをdeltaは持っています。
このコードでは、deltaの値をelapsedTimeというプロパティに加算していき、その値が指定した秒数の値以上になった所で、処理を実行しています。
ここまではシンプルな実装だと思います。

次に注目したいのが、以下の部分です。

this.elapsedTime %= 3000;

指定秒数ごとの処理が行われたら次の処理に移る為、経過時間をリセットしてあげる必要があります。
その為に、ここでは剰余代入という方法を用いてそれを実現しています。

剰余代入は、変数を右辺で除算して余りをその変数に代入してくれる式です。
どのような動きをするのかは、文章で説明するよりも以下のコードを見てもらった方が早いと思います。

// 指定時間
const delay = 100;

// パターン1:経過時間が指定秒数と同じ場合
let elapsedTime1 = 100;
elapsedTime1 %= delay;
console.log(elapsedTime1); // 結果:0 

// パターン2:経過時間が指定秒数を超えている場合
let elapsedTime2 = 101;
elapsedTime2 %= delay;
console.log(elapsedTime2); // 結果:1

// パターン3:経過時間が指定秒数を超えていない場合
let elapsedTime3 = 99;
elapsedTime3 %= delay;
console.log(elapsedTime3); // 結果:99

つまり、

  • 経過時間が指定秒数と同じ場合、0が返る
  • 経過時間が指定秒数を超えている場合、余りの数値が返る
  • 経過時間が指定秒数を超えていない場合、経過時間がそのまま返る

となっています。
これらの動きによって、経過時間のリセットを実現しています。

特に、経過時間が指定秒数を超えている場合に余りの数値が返る、というのが肝になっています。
仮に、余りを無視して0を代入する事でリセットをした場合、その余りの分だけ徐々に経過時間がずれていってしまいます。