Phaser3 ゲームオブジェクトの拡張①: runChildUpdateを使う

今回はゲームオブジェクトの拡張について勉強します。

ゲームオブジェクトの拡張

gpnotes.hatenablog.jp

以前の記事中リンクで紹介しましたが、ゲームオブジェクトに子要素を追加するにはコンテナを用いるかゲームオブジェクトを拡張する方法が紹介されていました。
今回からはゲームオブジェクトを拡張してダイヤル電話のアニメーションを作ってみたいと思います。
コンテナを拡張したMyContainerを用意します。

export class MyContainer extends Phaser.GameObjects.Container {
    constructor(scene: Phaser.Scene, x?: number, y?: number, children?: Phaser.GameObjects.GameObject[]) {
        super(scene, x, y, children);
    }
}

MyContainerにはまだ独自の機能が何もありません。

add.existingでシーンへの追加を行う

次にcreateでMyContainerを初期化します。

拡張したオブジェクトはscene.add.existing()でシーンへの追加を忘れないようにします。
拡張オブジェクトのコンストラクタ内でシーンへの追加を行う方法もあります。
Phaser.Actions.PlaceOnCircleの第三引数、第四引数でオブジェクト配置の始点角度と終点角度を指定することができます。
この角度はラジアンで渡す必要があるので、 Phaser.Math.DEG_TO_RAD でラジアンを出しています。

    export class MyScene1 extends Phaser.Scene {
        //グラフィックオブジェクトを用意
        public graphics: Phaser.GameObjects.Graphics;

        public baseContainer: MyContainer;

        constructor() {
            super({ key: 'MyScene1', active: false });
        }

        preload() {

            this.load.image("block", "assets/images/block1.png")
            //背景を白に
            this.cameras.main.setBackgroundColor("#ffffff");
           
        }

        create() {

            this.baseContainer = new MyContainer(this);

            //グラフィックスオブジェクトを追加
            this.graphics = this.add.graphics();

            this.graphics.fillStyle(0xff00ff);

            //コンテナを宣言
            this.baseContainer.add(this.graphics);

            //ベースの円を作成
            this.graphics.fillStyle(0x1a1a1a);
            this.graphics.fillCircle(0, 0, 110);

            //※拡張で作成したオブジェクトはexistingでシーンへの追加を忘れないようにする
            this.add.existing(this.baseContainer);

            //文字の作成
            let texts: Phaser.GameObjects.Text[] = [];
            
            for (let i = 10; i > 0; i--) {
                let t = this.add.text(0, 0, i.toString());
                texts.push(t);
                t.setColor("#ffffff")
                t.setOrigin(0.5);
            }

            texts[0].text = "0";

            let circle = new Phaser.Geom.Circle(0, 0, 80);
            //円周上に配置
            Phaser.Actions.PlaceOnCircle(texts, circle, Phaser.Math.DEG_TO_RAD * 90, Phaser.Math.DEG_TO_RAD * 320);

            this.baseContainer.add(texts);

            this.baseContainer.x = this.sys.canvas.width / 2;
            this.baseContainer.y = this.sys.canvas.height / 2;

        }

        update() {

        }

    }

以上で電話の文字盤ができました。 f:id:Phaser_3:20181210162320p:plain

runChildUpdateでオブジェクトにupdateを実行させる

上の文字盤を回転させてみたいと思います。
まずはMyContainerクラスにupdateを追加します。

MyContainer(){
~~
    update() {
        //円盤を回転させる
        this.angle += 1;

        //テキストの角度を補正する
        for (let obj of this.list) {
            if (obj instanceof Phaser.GameObjects.Text) {
                (obj as Phaser.GameObjects.Text).angle = -this.angle;
            }
        }
    }
~~
}

次にMyScene1のcreateに以下を追加します。
groupの作成時にrunChildUpdate: trueのオプションを追加しておくとgroup内のオブジェクトに記述されているupdateを実行することができます。

let group = this.add.group(this.baseContainer, { runChildUpdate: true });

上記の実行結果がこちらです。 f:id:Phaser_3:20181210164518g:plain

今回のソースがこちらです。
MyScene1ではupdateが空なのが確認できます。

namespace MyGame {


export class MyContainer extends Phaser.GameObjects.Container {
    constructor(scene: Phaser.Scene, x?: number, y?: number, children?: Phaser.GameObjects.GameObject[]) {
        super(scene, x, y, children);
    }

    update() {
        //円盤を回転させる
        this.angle += 1;

        //テキストの角度を補正する
        for (let obj of this.list) {
            if (obj instanceof Phaser.GameObjects.Text) {
                (obj as Phaser.GameObjects.Text).angle = -this.angle;
            }
        }

    }

}



    export class MyScene1 extends Phaser.Scene {
        //グラフィックオブジェクトを用意
        public graphics: Phaser.GameObjects.Graphics;

        public baseContainer: MyContainer;
        public dialContainer: MyContainer;

        constructor() {
            super({ key: 'MyScene1', active: false });
        }

        preload() {

            this.load.image("block", "assets/images/block1.png")
            //背景を白に
            this.cameras.main.setBackgroundColor("#ffffff");
           
        }

        create() {

            this.baseContainer = new MyContainer(this);

            //グラフィックスオブジェクトを追加
            this.graphics = this.add.graphics();

            this.graphics.fillStyle(0xff00ff);

            //コンテナを宣言
            this.baseContainer.add(this.graphics);

            //ベースの円を作成
            this.graphics.fillStyle(0x1a1a1a);
            this.graphics.fillCircle(0, 0, 110);

            //※拡張で作成したオブジェクトはexistingでシーンへの追加を忘れないようにする
            this.add.existing(this.baseContainer);

            //文字の作成
            let texts: Phaser.GameObjects.Text[] = [];
            
            for (let i = 10; i > 0; i--) {
                let t = this.add.text(0, 0, i.toString());
                texts.push(t);
                t.setColor("#ffffff")
                t.setOrigin(0.5);
            }

            texts[0].text = "0";

            let circle = new Phaser.Geom.Circle(0, 0, 80);
            //円周上に配置
            Phaser.Actions.PlaceOnCircle(texts, circle, Phaser.Math.DEG_TO_RAD * 90, Phaser.Math.DEG_TO_RAD * 320);

            this.baseContainer.add(texts);

            this.baseContainer.x = this.sys.canvas.width / 2;
            this.baseContainer.y = this.sys.canvas.height / 2;

            let group = this.add.group(this.baseContainer, { runChildUpdate: true });
        }

        update() {

        }

    }


}