頑張らないために頑張る

ゆるく頑張ります

Phaser3を使ってボタン用のクラスを作る

Posted at — May 10, 2021

Phaser3を使ってボタンを作ろう

任意の文字列と押されたときの挙動を記述したコールバック関数などを引数として受け取って、画面にボタンを配置するクラスを作ってみました。

メニュー画面やRPGの戦闘シーンなどで、コマンドなどを一覧描画したりする際に利用できます。また、ボタンとしての機能を持たせるため、カーソルオーバーなどのイベントに何かしらの反応を示す要素が記述されています。

ソース

// 設定用オブジェクト
type Props = {
  width: number;
  height: number;
  onClick: Function;
  align: string;
  fontSize: number;
  color: string;
}

class OriginalButtonClass extends Phaser.GameObjects.Container{
  
  text: Phaser.GameObjects.Text;
  container: Phaser.GameObjects.Rectangle;
  
  constructor (scene: Phaser.Scene, x:number, y:number, text:string, props: Props){
    super(scene, x, y);
    
    // 入力されたオブジェクトから各要素を取り出す
    const{
      width = 90,
      height = 40, 
      onClick,
      align = 'center', 
      fontSize = 30, 
      color = 'black'
    } = props;
    
    // シーンにボタンを追加
    this.scene = scene;
    this.scene.add.existing(this);
    
    this.setSize(width, height);
    this.setInteractive({useHandCursor: true});
    
    const alignLeft = align === 'left';
    
    // 左寄せの場合は位置を調整
    this.text = scene.add.text(alignLeft ? -width / 2 + 0 : 0, -1, text, {align, fontSize, color}).setOrigin(alignLeft ? 0:0.5, 0.5).setPadding(0, 2, 0, 0);
    this.text.setColor(color);
    
    // ボタンの枠を作成
    this.container = scene.add.rectangle(0, 0, width, height);
    this.container.setStrokeStyle(1, 0xffffff).setOrigin(alignLeft ? 0 : 0.5, 0.5);
    
    this.add([this.container, this.text])
    this.on('pointerover', () => {
      this.updateButton('pointer over', 'red');
    });
    
    this.on('pointerout', () => {
      this.updateButton('pointer out', color);
    });
    
    this.on('pointerdown', ()=>{
      this.updateButton('pointer down', 'blue');
      this.scene.tweens.add({
        targets: this,
        scaleX: 1.1,
        scaleY: 1.1,
        duration: 100,
        yoyo: true,
        repeat: 2,
        ease: 'Sine.easeInOut',
      });
    });
    
    this.on('pointerup', () => {
      this.updateButton('pointer up','yellow');
      onClick();
    });
    
  }
  
  updateButton =(message: string, color: string)=>{
    console.log(message);
    this.text.setColor(color);
  }

}

class GameScene extends Phaser.Scene {
    constructor() {
        super('gameScene');
    }

    preload() {

    }

    create() {
      this.button = new OriginalButtonClass(this, 200, 200, 'hoge', {
        onClick: ()=>{
          console.log('clicked.');
        }
      });

    }
}

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');

クリックしたときのTweenも設定してみました。

ボタンを押したときの機能はコールバック関数として引数で渡すので、ボタンのクラス内には特段の機能は記述していません。必要があれば追記するか、このクラスを継承して新しいクラスとして作成すれば問題ありません。

ちょっと詳細

オブジェクトから要素を取り出す

// 入力されたオブジェクトから各要素を取り出す
const{
  width = 90,
  height = 40, 
  onClick,
  align = 'center', 
  fontSize = 30, 
  color = 'black'
} = props;

ボタンとして画面配置するとき、そのボタンの仕様を決定する必要があります。ボタンの高さや幅、クリックされたときの挙動などがそれに当たりますが、これらをクラスのコンストラクタで利用します。入力された引数のpropsオブジェクトの内容を分割代入して、それぞれをボタンの仕様として使うわけです。

なお、ここではすべての項目について初期値を設定していますが、実際にこのクラスを利用するときに「このプロパティについては必ず指定するから初期値いらないな・・・」となれば、上記のコード部分を適当な初期値に設定したり削除してやればOKです。

左寄せあるいはセンタリング

const alignLeft = align === 'left';

// 左寄せの場合は位置を調整
this.text = scene.add.text(alignLeft ? -width / 2 + 0 : 0, -1, text, {align, fontSize, color}).setOrigin(alignLeft ? 0:0.5, 0.5).setPadding(0, 2, 0, 0);
this.text.setColor(color);

入力された指定が左寄せか否かを判定し、テキスト表示位置の調整を行う部分です。こちらのコードを参考にしました。

ボタンの枠を作成

// ボタンの枠を作成
this.container = scene.add.rectangle(0, 0, width, height);
this.container.setStrokeStyle(1, 0xffffff).setOrigin(alignLeft ? 0 : 0.5, 0.5);

ボタンの枠や線について任意の色を指定したい場合は、上記の箇所を変更します。また、線の太さなども上記部分で変更可能です。

イベント発生時の処理を付与

this.on('pointerover', () => {
  this.updateButton('pointer over', 'red');
});

this.on('pointerout', () => {
  this.updateButton('pointer out', color);
});
...以下省略

ボタンに対し、何らかのカーソルによるアクションがあったときの処理を上記では記述しています。たとえば、ボタンにマウスカーソルが乗った(pointeroverイベントが発生)とき、updateButton()という関数が実行されて内容が更新されます。updateButton()関数は指定された引数に基づいて、ボタンのテキスト色を変更するだけの単純な関数です。他にも処理を追加したければ、イベントごとに任意の処理を追加すればOKです。

またクリックされたとき(正確にはマウスのボタンを上げたとき)に、事前に引数で指定しておいた処理をここで実行します。今回、ここで実行しているのはコンソールに文字列を出力するだけの処理ですが。

参考

  1. Buttons In Phaser 3
  2. Phaser3でボタンクラスを作る
comments powered by Disqus