頑張らないために頑張る

ゆるく頑張ります

Phaser3でタイマーイベントを使う

Posted at — May 2, 2021

タイマーイベントってなんだっけ

一定の時間経過を条件として発動するイベントのことを、タイマーイベントといいます。タイマーイベントには繰り返し発生するタイプと、1回だけ発動するタイプの2つが存在します。繰り返し発生するタイプは永久に発生し続けるものと、決められた回数のみ発生する2パターンが存在します。

後述しますが、実装時のメソッドが異なるのでそれだけは注意。

これらのタイマーイベントは、Phaser.Time.Clockクラスを利用することで実装が可能です。

サンプルコード

class GameScene extends Phaser.Scene {
    timerRepeat: Phaser.Time.Clock;
    timerLoop: Phaser.Time.Clock;
    timerOneShot: Phaser.Time.Clock;
  
    constructor() {
        super('gameScene');
    }

    preload() {

    }

    create() {
      this.timerRepeat = this.time.addEvent({
        delay: 1000,
        callback: ()=>console.log('hoge'),
        callbackScope: this,
        repeat: 2,
      });

      this.timerLoop = this.time.addEvent({
        delay: 2000,
        callback: ()=>console.log('loop'),
        callbackScope: this,
        loop: true,
      });

      this.timerOneShot = this.time.delayedCall(3000, ()=>console.log('one shot'), this
      );

    }
}

let gameScene = new GameScene();

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#e0e0e0'
};

let game = new Phaser.Game(config);

game.scene.add('gameScene', gameScene);

game.scene.start('gameScene');

addEvent()では、引数にタイマーの設定を記述したオブジェクトを渡します。このときプロパティの設定値によって挙動が変わり、loop:trueにすれば延々とループするし、repeat:nとすればn+1回リピートします。

ちなみに、リピート数は前述のとおりrepeat:nで指定しますが、このとき実行される実際の回数n+1回です。なぜ1回足されるかというと、どうも0回目からスタートするようで、repeat:2と指定した場合は合計で3回コールバック関数が実行されました。repeat:0とした場合は1回のみの実行で終了、つまり単発の実行と同じになります。

単発で処理を実行するイベントを仕込む場合は、delayedCall()で実装することが可能です。ただ、単発イベントの実装だけメソッド名が異なるので注意してください。こちらは、引数にオブジェクトではなく経過時間、コールバック関数、コールバックのスコープなどをそれぞれ指定します。設定した時間が経過すると1度だけコールバック関数が実行され、以降の処理はありません。

サンプルコードその2

const generateEllipse = (scene) => {
  let {width, height} = scene.game.canvas;  
  
  let ellipse = scene.add.ellipse(Phaser.Math.Between(0, width), Phaser.Math.Between(0, height), 100, 100, 0x12a797);
      ellipse.setOrigin(0, 0);
      ellipse.setInteractive();
      ellipse.on('pointerdown', ()=>{
        ellipse.input.enabled = false;
        ellipse.destroy();
      });
  
  return ellipse;
};

const generateMoveText = (scene, text,) => {
  let {width, height} = scene.game.canvas;
  
  let textObj = scene.add.text(Phaser.Math.Between(0, width / 2), Phaser.Math.Between(0, height), text, {
    fontSize: Phaser.Math.Between(15, 40),
    color: '#a83839',
  });
  
  let tween = scene.tweens.add({
        targets: textObj,
        props: {
            x: { value: width, duration: 4000, ease: 'Linear' },
            y: { value: height / 2, duration: 1000, ease: 'Bounce.easeInOut', yoyo: true, delay: 1000 },
          alpha: { value: 0, duration: 2000, ease: 'Linear', delay: 2000}
        }
    });
  
  let onetimeTimer = scene.time.delayedCall(4000, ()=>{
    textObj.destroy();
  }, scene);
  
  return textObj;
};

class GameScene extends Phaser.Scene {
    timerRepeat: Phaser.Time.Clock;
    timerLoop: Phaser.Time.Clock;
    timerOneShot: Phaser.Time.Clock;
  
    constructor() {
        super('gameScene');
    }

    preload() {

    }

    create() {
      this.timerRepeat = this.time.addEvent({
        delay: 1000,
        callback: ()=>console.log('hoge'),
        callbackScope: this,
        repeat: 3,
      });

      this.timerLoop = this.time.addEvent({
        delay: 2000,
        callback: ()=>{
          generateEllipse(this);
          generateMoveText(this, 'hoge');
          console.log('loop')
        },
        callbackScope: this,
        loop: true,
      });

      this.timerOneShot = this.time.delayedCall(3000, ()=>console.log('one shot'), this
      );

    }
}

let gameScene = new GameScene();

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#e0e0e0'
};

let game = new Phaser.Game(config);

game.scene.add('gameScene', gameScene);

game.scene.start('gameScene');

上記のサンプルに、円と文字を表示する関数をそれぞれタイマー実行するコードを追加しました。文字自体にも、一定時間経過後自分自身をdestroy()するタイマーイベントを仕込んであります。tweenで実装できないような処理を仕込みたい場合に使えそうですね。

See the Pen Timer with Phaser3 by ysko909 (@ysko909) on CodePen.

Codepenでも実装してみました。

まとめ

アクションゲームだったり、RPGでも時限式イベントなどでは必須のタイマーイベント。たったこれだけの記述量で処理を仕込めるのは、Phaser3のいいところですね。有効に使いたいものです。

参考

  1. Phaser.Time. Clock
  2. Timer
comments powered by Disqus