60pxの市松模様で10行、10列(縦横600px)の画像があったとします。

これを中心に配置すると以下のようになります。
./src/main.js

import Phaser from "phaser";
import GameScene from "./scenes/GameScene";

const config = {
    type: Phaser.AUTO,
    width: 1200,
    height: 600,
    parent: 'game-container',
    backgroundColor: '#fff',
    scale: {
        mode: Phaser.Scale.NONE,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    dom: {
        createContainer: true
    },
    scene: [
        GameScene
    ]
};

export default new Phaser.Game(config);

./src/scenes/GameScene.js

import { Scene } from 'phaser';

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

    preload() {
        this.load.image("bg", "./assets/bg.png");
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;
        const bg = this.add.image(centerX, centerY, "bg");
        bg.setOrigin(0.5);
    }

    update() {
    }
}

そのうち、左上を基準に、2行、4列(縦120px × 横240px)を表示しようとしてcropを使うと
./src/scenes/GameScene.js

import { Scene } from 'phaser';

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

    preload() {
        this.load.image("bg", "./assets/bg.png");
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;
        const bg = this.add.image(centerX, centerY, "bg");
        bg.setOrigin(0.5);

        const cropX = 0;
        const cropY = 0;
        const cropWidth = 240;
        const cropHeight = 120;
        bg.setCrop(cropX, cropY, cropWidth, cropHeight);
    }

    update() {
    }
}

setOriginはあくまでも全体のサイズにおけるセンターのため、
切り取った部分をセンターにもっていくためには、調整が必要。

./src/scenes/GameScene.js

import { Scene } from 'phaser';

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

    preload() {
        this.load.image("bg", "./assets/bg.png");
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;
        const width = 600;
        const height = 600;

        // 切り取り領域
        const cropX = 0;
        const cropY = 0;
        const cropWidth = 240;
        const cropHeight = 120;

        const bg = this.add.image(centerX + (width - cropWidth) / 2, centerY + (height - cropHeight) / 2, "bg");
        bg.setOrigin(0.5);
        bg.setCrop(cropX, cropY, cropWidth, cropHeight);
    }

    update() {
    }
}

どちらかというと、原点をセンターにするより、左上の位置から調整した方が楽ですね。

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;

        // 切り取り領域
        const cropX = 0;
        const cropY = 0;
        const cropWidth = 240;
        const cropHeight = 120;

        const bg = this.add.image(centerX - cropWidth / 2, centerY - cropHeight / 2, "bg");
        bg.setOrigin(0);
        bg.setCrop(cropX, cropY, cropWidth, cropHeight);
    }

1つの画像に同一サイズの画像をまとめているのであれば、SpriteSheetを使って切り出してつかうことができます。
↓縦横20pxのデータが8つある。

./src/scenes/GameScene.js

import { Scene } from 'phaser';

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

    preload() {
        this.load.spritesheet("charList", "./assets/CharList.png", { frameWidth: 20, frameHeight: 20 });
    }

    create() {
        const charList = [];

        for (let n = 0; n < 8; n++) {
            const row = 20 * Math.trunc(n / 4);
            const col = 20 * (n % 4);
            const char = this.add.image(col, row, "charList", n);
            char.setOrigin(0); // 原点は左上
            charList.push(char);
        }
    }

    update() {
    }
}

↓左上から2行4列で表示

投稿日時: 2024-08-14 15:34:14
更新日時: 2024-08-14 16:17:14

ボタンや、表といったものは、Phaserでは用意していないのでHTMLを追加することになります。
例えば、タイトル画面でゲーム開始ボタンを用意し、ゲーム画面に遷移するとします。

button要素一つ追加する例

DOMを追加する場合、configに dom : { createContainer : true } を追加する必要があります。
./src/main.js

import { AUTO, Scale, Game } from 'phaser';
import GameScene from './scenes/GameScene';
import TitleScene from './scenes/TitleScene';

//  Find out more information about the Game Config at:
//  https://newdocs.phaser.io/docs/3.70.0/Phaser.Types.Core.GameConfig
const config = {
    type: AUTO,
    width: 960,
    height: 540,
    parent: 'game-container',
    backgroundColor: '#FFF',
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [
        TitleScene,
        GameScene
    ],
    dom: {
        createContainer: true
    },
};

export default new Game(config);

./src/scenes/TitleScene.js

import { Scene } from 'phaser';

export default class TitleScene extends Scene {
    constructor() {
        super('TitleScene');
    }

    preload() {
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;

        const btnStartNode = document.createElement("button");
        btnStartNode.className = "btnStart btnStart--royalblue";
        btnStartNode.innerText = "ゲーム開始";
        btnStartNode.addEventListener("click", () => { this.scene.start("GameScene"); });

        const btnStart = this.add.dom(centerX, centerY, btnStartNode);
    }

    update() {
    }
}

./src/scenes/GameScene.js

import { Scene } from 'phaser';

export default class GameScene extends Scene {
    constructor() {
        super('GameScene');
    }

    preload() {
    }

    create() {
    }

    update() {
    }
}

./public/phaser.css


.btnStart {
    border: none;
    border-radius: 5px;
    color: white;
    font-size: 200%;
    padding: 10px 30px;
    text-align: center;
}

.btnStart--royalblue{
    background-color: royalblue;
    border-bottom: 5px solid rgb(48, 66, 133);
}

.btnStart--royalblue:hover {
    background: rgb(85, 125, 245);
    border-bottom: 2px solid rgb(48, 66, 133);
    margin-top: 2px;
}
DOMを追加しているので、イベントは通常のaddEventListenerで追加する。 追加した要素は、画面遷移とともに、消えています。

タイトル画面で、ゲームの種類を選択して画面遷移させたい場合など、複数の同一のボタンを用意したい場合

複数のボタンを追加する例

今度は、ボタンのクラスを作って配置してみます。
./src/main.js

import { Scene } from 'phaser';
import GameTypeButton from '../objects/GameTypeButton'

export default class TitleScene extends Scene {
    constructor() {
        super('TitleScene');
    }

    preload() {
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;

        new GameTypeButton(this, centerX - 90, centerY, "Game1", () => { this.scene.start("GameScene"); });
        new GameTypeButton(this, centerX + 0, centerY, "Game2", () => { this.scene.start("GameScene2"); });
        new GameTypeButton(this, centerX + 90, centerY, "Game3", () => { this.scene.start("GameScene3"); });
    }

    update() {
    }
}

./scenes/TitleScene.js

import { Scene } from 'phaser';
import GameTypeButton from '../objects/GameTypeButton'

export default class TitleScene extends Scene {
    constructor() {
        super('TitleScene');
    }

    preload() {
    }

    create() {
        const centerX = this.scale.width / 2;
        const centerY = this.scale.height / 2;

        new GameTypeButton(this, centerX - 90, centerY, "Game1", () => { this.scene.start("GameScene"); });
        new GameTypeButton(this, centerX + 0, centerY, "Game2", () => { this.scene.start("GameScene2"); });
        new GameTypeButton(this, centerX + 90, centerY, "Game3", () => { this.scene.start("GameScene3"); });
    }

    update() {
    }
}

DOMを追加するクラスは、Phaser.GameObjects.DOMElementを継承します。
ここでは、親クラスには、scene, x, y, HTML要素を渡しています。
./src/objects/GameTypeButton.js

export default class GameTypeButton extends Phaser.GameObjects.DOMElement {
    constructor(scene, x, y, text, callback) {
        // HTML要素を作成
        const element = document.createElement('button');
        element.innerText = text;
        element.className = "btnStart btnStart--royalblue";

        super(scene, x, y, element);

        // シーンに追加
        scene.add.existing(this);

        // ボタンクリック時のコールバックを設定
        this.node.addEventListener('click', callback);
    }
}

./public/phaser.css


.btnStart {
    border: none;
    border-radius: 5px;
    color: white;
    font-size: 100%;
    padding: 5px 15px;
    text-align: center;
}

.btnStart--royalblue{
    background-color: royalblue;
    border-bottom: 5px solid rgb(48, 66, 133);
}

.btnStart--royalblue:hover {
    background: rgb(85, 125, 245);
    border-bottom: 2px solid rgb(48, 66, 133);
    margin-top: 2px;
}

./srcscenes/GameScene.js

import { Scene } from 'phaser';

export default class GameScene extends Scene {
    constructor() {
        super('GameScene');
    }

    preload() {
    }

    create() {
    }

    update() {
    }
}

./srcscenes/GameScene2.js

import { Scene } from 'phaser';

export default class GameScene2 extends Scene {
    constructor() {
        super('GameScene2');
    }

    preload() {
    }

    create() {
    }

    update() {
    }
}

./srcscenes/GameScene3.js

import { Scene } from 'phaser';

export default class GameScene3 extends Scene {
    constructor() {
        super('GameScene3');
    }

    preload() {
    }

    create() {
    }

    update() {
    }
}
それぞれクリックすると、画面遷移します。

大した、Styleじゃないので、CSSファイルにわけるのではなく、ソースとStyle一か所でまとめて管理したいというのであれば・・・

親クラスにStyleも渡す場合

cssに記載していた内容をクラス内にまとめるとすると・・・
./src/objects/GameTypeButton.js

export default class GameTypeButton extends Phaser.GameObjects.DOMElement {
    constructor(scene, x, y, text, callback) {

        const style = {
            backgroundColor: "royalblue",
            border: "none",
            borderBottom: "5px solid rgb(48, 66, 133)",
            borderRadius: "5px",
            color: "white",
            fontSize: "100%",
            marginTop: "0px",
            padding: "5px 15px",
            textAlign: "center",
        };

        super(scene, x, y, "button", style, text);

        this.setOrigin(0.5);
        scene.add.existing(this);

        // ボタンクリック時のコールバックを設定
        this.node.addEventListener('click', callback);

        // ホバー設定(over/outで代用)
        this.node.addEventListener('mouseover', () => {
            this.node.style.background = "rgb(85, 125, 245)";
            this.node.style.borderBottom = "2px solid rgb(48, 66, 133)";
            this.node.style.marginTop = "2px";
        });
        this.node.addEventListener('mouseout', () => {
            this.node.style.background = style.backgroundColor
            this.node.style.borderBottom = style.borderBottom;
            this.node.style.marginTop = style.marginTop;
        });
    }
}

ランキングのようなものとかなら、templateタグで用意しておいてゲーム画面外の要素として表示とかでよい気がする。

投稿日時: 2024-08-12 15:05:12
更新日時: 2024-08-13 06:13:13

phaserで、オブジェクトを生成し、クリックイベントに関数を指定しておき
その関数から、インスタンス変数にアクセスしようとした場合

export class xxxxxx {
    constructor(scene, rnd) {
        this.scene = scene;
        this.data = [];
    }

    init(){
        // オブジェクト生成
       this.#createObject();

        // データ生成(略)
        this.createData(); // ここでthis.dataにデータを追加する
    }

    #createObject(){
        // オブジェクトを生成(実際はもっとちゃんといろいろ設定している)
        const obj = this.scene.add.rectangle(100, 100, 100, 100, 0x000000, 0); //透明なクリック検知プレート
        obj.setInteractive();
        obj.on("pointerdown", this.#clickAreaClick);
    }

    #clickAreaClick(pointer, localX, localY){
        console.log(this.data); // undefined
    }
}

#clickAreaClickメソッドがイベントハンドラとして登録されると、
そのメソッド内でのthisは、initインスタンスを参照せず、
イベントのターゲット(この場合はclickArea)を参照します。
そのため、this.tileDataがundefinedになります。

解決策(アロー関数を使用)

obj.on("pointerdown", (pointer, localX, localY) => {
    this.#clickAreaClick(pointer, localX, localY); 
});

解決策(bindメソッドを使用)

obj.on("pointerdown", this.#clickAreaClick.bind(this));
投稿日時: 2024-08-04 10:42:04

./src/main.js

import Phaser from "phaser";
import GameScene from "./scenes/GameScene";

const config = {
    type: Phaser.AUTO,
    width: 400,
    height: 300,
    parent: 'game-container',
    backgroundColor: '#ffffff',
    scale: {
        mode: Phaser.Scale.NONE,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [
        GameScene
    ]
};

export default new Phaser.Game(config);

./src/scenes/GameScene.js

import { Scene } from 'phaser';
import Rect from '../objects/Rect'

export default class GameScene extends Phaser.Scene {

    constructor() {
        super('GameScene');
    }

    create() {
        const rect = new Rect(this, 100, 200);
    }
}

./src/objects/Rect.js

export default class Rect {
    constructor(scene, x, y) {
        const centerX = scene.scale.width / 2;
        const centerY = scene.scale.height / 2;
        const width = 200;
        const height = 200;

        const clickArea = scene.add.rectangle(centerX, centerY, width, height, 0x000000, 0); // 透明な矩形
        clickArea.setDepth(30);

        clickArea.setInteractive();
        clickArea.on("pointerdown", this.handleClick);
        scene.add.existing(clickArea);
    }

    handleClick(pointer, localX, localY) {
        console.log(`ClickX=${pointer.x}, Clicky=${pointer.y}\t画像内X=${localX}, 画像内Y=${localY}`);
    }
}
投稿日時: 2024-08-04 06:51:04

10要素中7要素1を設定し残り0を設定。

const data = Array.from({ length: 10 }, (_, i) => i < 7 ? 1 : 0);

console.log(data); //Array(10) [ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]



Array.from() Array.from() 静的メソッドは、反復可能オブジェクトや配列風オブジェクトからシャローコピーされた、新しい Array インスタンスを生成します。 mdn web docs

console.log(Array.from('foo'));
// Expected output: Array ["f", "o", "o"]

console.log(Array.from([1, 2, 3], (x) => x + x));
// Expected output: Array [2, 4, 6]

console.log(Array.from({length: 5}));
// Expected output: Array [undefined, undefined, undefined, undefined, undefined]
投稿日時: 2024-07-28 05:43:28
更新日時: 2024-07-28 07:27:28

Phaserでつかえる乱数の調査
結構いろいろ用意されている感じ。

        // ■整数
        // 1から5までの整数を生成する。(お互い含む)
        console.log(Phaser.Math.RND.integerInRange(1, 5));

        // integerInRangeのエリアス
        // 1から5までの整数を生成する。(お互い含む)
        console.log(Phaser.Math.RND.between(1, 5));

        // 0から2の32乗までの整数を生成する。
        console.log(Phaser.Math.RND.integer());


        // ■小数点数
        // 0から1までの小数点数を生成する。
        console.log(Phaser.Math.RND.frac());

        // -1から1までの小数点数を生成する。
        console.log(Phaser.Math.RND.normal());


        // ■角度
        // degree(-180から180)までの整数を生成する。(-180, 180を含む)
        console.log(Phaser.Math.RND.angle());

        // radian(-πからπ)までの小数点数を生成する。
        console.log(Phaser.Math.RND.rotation());

        // ■他
        // 配列のデータを一つ選ぶ
        const data = ["black", "bule", "red", "green"];
        console.log(Phaser.Math.RND.pick(data));

        // 配列の順番をシャッフルする
        Phaser.Math.RND.shuffle(data);
        console.log(data);

シードを設定してみる。

文字列か、配列の文字列ということになっていますが・・・
文字列だと、何を指定しても同じ配列になってしまうので、配列に文字列指定をしています。

        // ■seed
        for (let i = 0; i < 3; i++) {
            let data = [];
            let r = new Phaser.Math.RandomDataGenerator(["a"]);

            for (let j = 0; j < 10; j++) {
                const value = r.between(1, 1000);
                data.push(value);
            }

            console.log(data.join(", ")); // 425, 388, 604, 466, 913, 310, 533, 890, 602, 435
        }

        // 別のシードで実行
        for (let i = 0; i < 3; i++) {
            let data = [];
            let r = new Phaser.Math.RandomDataGenerator(["b"]);

            for (let j = 0; j < 10; j++) {
                const value = r.between(1, 1000);
                data.push(value);
            }

            console.log(data.join(", ")); // 574, 647, 255, 508, 245, 406, 748, 436, 768, 239
        }

shuffleなども再現することを確認。

        const r = new Phaser.Math.RandomDataGenerator(["a"]);
        let data = [];
        for (let i = 0; i < 10; i++) {
            let val = r.integerInRange(1, 1000);
            data.push(val);
        }

        r.shuffle(data);
        console.log(data); //[ 533, 435, 388, 425, 310, 604, 890, 913, 602, 466 ]
投稿日時: 2024-07-27 15:46:27
更新日時: 2024-08-03 11:43:03

Phaserについて調査中。
マウス操作、タッチ操作でスコアは差がでるので、検知だったり制限する方法が知りたかったので調べた結果のメモ。


create() {
  if (this.sys.game.device.input.mouse) {
    // マウス入力のみを有効化
    this.input.mouse.enabled = true;
    this.input.touch.enabled = false;
  } else if (this.sys.game.device.input.touch) {
    // タッチ入力のみを有効化
    this.input.mouse.enabled = false;
    this.input.touch.enabled = true;
  }
}
投稿日時: 2024-07-27 02:54:27
更新日時: 2024-07-28 02:37:28

Phaser.GameObjects.Imageを継承し、クリック(タップ)のイベントを取得してみたけども他のイベントを利用するにはどう記載するのか調べてみたのでメモ。

  • pointerdown: オブジェクトがクリック/タップされた時
  • pointerup: オブジェクト上でマウスボタン/タッチが離された時
  • pointermove: オブジェクト上でポインターが移動した時
  • pointerover: ポインターがオブジェクトに入った時
  • pointerout: ポインターがオブジェクトから出た時
  • dragstart: ドラッグが開始された時
  • drag: ドラッグ中
  • dragend: ドラッグが終了した時
  • dragenter: ドラッグ中にオブジェクトに入った時
  • dragleave: ドラッグ中にオブジェクトから出た時
  • drop: ドラッグしたアイテムがオブジェクト上でドロップされた時
投稿日時: 2024-07-27 02:53:27

システムフォントに依存しないようwebフォントの利用をしてみる。

main.js

import Phaser from "phaser";
import GameScene from "./scenes/GameScene";

const config = {
    type: Phaser.AUTO,
    width: 400,
    height: 300,
    parent: 'game-container',
    backgroundColor: '#ffffff',
    scale: {
        mode: Phaser.Scale.NONE,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [
        GameScene
    ]
};

export default new Phaser.Game(config);

GameScene.js

import { Scene } from 'phaser';

export default class GameScene extends Phaser.Scene {

    constructor() {
        super('game');
    }

    preload() {
        // webフォントをロード
        WebFont.load({
            google: {
                families: ['Hachi Maru Pop']
            }
        });
    }

    create() {
        const txtOriginX = this.scale.width / 2;
        const txtOriginY = this.scale.height / 2;
        this.add.text(txtOriginX, txtOriginY, "あいうえお", { fontFamily: "Hachi Maru Pop", fontSize: "32px", fill: "#000" }).setOrigin(0.5);
    }
 }

index.htmlに https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js を追加
fontはGoogle fontから適当に選択(ここでは設定できているのが確認しやすいフォントを選びました)

Hachi Maru Popはこんな感じ

ゲーム実行したらこんな感じ

投稿日時: 2024-07-26 13:53:26

■画像を表示する

main.js

import Phaser from "phaser";
import GameScene from "./scenes/GameScene";

const config = {
    type: Phaser.AUTO,
    width: 600,
    height: 300,
    parent: 'game-container',
    backgroundColor: '#ffffff',
    scale: {
        mode: Phaser.Scale.NONE,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [
        GameScene
    ]
};

export default new Phaser.Game(config);

./src/objects/Block.js

export default class Block extends Phaser.GameObjects.Image {
    constructor(scene, x, y) {
        super(scene, x, y, 'black_block');
        this.setOrigin(0.5);            // 原点を中心にする
        this.scene.add.existing(this);  // シーンに追加する。
    }
}

./src/scenes/GameScene.js

import { Scene } from 'phaser';
import Block from '../objects/Block.js'

export default class GameScene extends Phaser.Scene {

    constructor() {
        super('game');
    }

    preload() {
        // 画像を読み込む
        this.load.image("black_block", './assets/black.png');
    }

    create() {
        // 画面中心に配置
        var centerX = this.scale.width / 2;
        var centerY = this.scale.height / 2;
        var block = new Block(this, centerX, centerY);
    }

    update() {
    }
}

■クリックイベント処理を追加

./src/objects/Block.js

export default class Block extends Phaser.GameObjects.Image {
    constructor(scene, x, y) {
        super(scene, x, y, 'black_block');
        this.setOrigin(0.5);            // 原点を中心にする
        this.setInteractive();          // クリックやタッチを受け付ける
        this.scene.add.existing(this);  // シーンに追加する。

        // クリックイベントの設定
        this.on("pointerdown", this.handleClick, this);
    }

    handleClick(pointer, localX, localY, event) {
        // 現在の位置をconsole.logに出力
        console.log(`ClickX=${pointer.x}, Clicky=${pointer.y}\t画像内X=${localX}, 画像内Y=${localY}`);
    }
}

■クリックイベント範囲を円型にする

./src/objects/Block.js

export default class Block extends Phaser.GameObjects.Image {
    constructor(scene, x, y) {
        super(scene, x, y, 'black_block');
        this.setOrigin(0.5); // 原点を中心にする

        // クリックやタッチを受け付ける
        this.setInteractive(
            new Phaser.Geom.Circle(this.width / 2, this.height / 2, this.width / 4),
            Phaser.Geom.Circle.Contains
        );

        console.log(`画像の幅:${this.width} / 高さ:${this.height} 半径:${this.width / 4}`);
        console.log(`配置位置X:${x} / Y:${y}`);
        console.log(`範囲X:${x - this.width / 4} ~ ${x + this.width / 4}`);

        this.scene.add.existing(this); // シーンに追加する

        // クリックイベントの設定
        this.on("pointerdown", this.handleClick, this);
    }

    handleClick(pointer, localX, localY, event) {
        // 現在の位置をconsole.logに出力
        console.log(`ClickX=${pointer.x}, Clicky=${pointer.y}\t画像内X=${localX}, 画像内Y=${localY}`);
    }
}

■クリックイベントで自身を削除

export default class Block extends Phaser.GameObjects.Image {
    constructor(scene, x, y) {
        super(scene, x, y, 'black_block');
        this.setOrigin(0.5);            // 原点を中心にする
        this.setInteractive();          // クリックやタッチを受け付ける
        this.scene.add.existing(this);  // シーンに追加する

        // クリックイベントの設定
        this.on("pointerdown", this.handleClick, this);
    }

    handleClick() {
        // 削除
        this.destroy();
    }
}
投稿日時: 2024-07-24 14:15:24
更新日時: 2024-07-24 15:08:24

テンプレートを使って作成するとmain.jsは以下のようになっている。

import { Game as MainGame } from './scenes/Game';
import { AUTO, Scale,Game } from 'phaser';

//  Find out more information about the Game Config at:
//  https://newdocs.phaser.io/docs/3.70.0/Phaser.Types.Core.GameConfig
const config = {
    type: AUTO,
    width: 1024,
    height: 768,
    parent: 'game-container',
    backgroundColor: '#028af8',
    scale: {
        mode: Scale.FIT,
        autoCenter: Scale.CENTER_BOTH
    },
    scene: [
        MainGame
    ]
};

export default new Game(config);

import { AUTO, Scale,Game } from 'phaser'; を記載しない場合は、
AUTO、Scale、Gameに Phaser. をつける。

import { Game as MainGame } from './scenes/Game';
//import { AUTO, Scale, Game } from 'phaser';

//  Find out more information about the Game Config at:
//  https://newdocs.phaser.io/docs/3.70.0/Phaser.Types.Core.GameConfig
const config = {
    type: Phaser.AUTO,
    width: 1024,
    height: 768,
    parent: 'game-container',
    backgroundColor: '#028af8',
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [
        MainGame
    ]
};

export default new Phaser.Game(config);
投稿日時: 2024-07-20 02:09:20

設定はこちら

import { Game as MainGame } from './scenes/Game';
import { AUTO, Scale, Game } from 'phaser';

const config = {
    type: AUTO,
    width: 300,
    height: 300,
    parent: 'game-container',
    backgroundColor: '#028af8',
    scale: {
        mode: Scale.NONE, //
        autoCenter: Scale.CENTER_BOTH
    },
    scene: [
        MainGame
    ]
};

export default new Game(config);

画像の読み込みと配置

100x100のblockを、(0,0)の座標に配置してみる。

Game.js

import { Scene } from 'phaser';

export class Game extends Scene {
    constructor() {
        super('Game');
    }

    preload() {
        this.load.image('block', 'assets/Block.png');
    }

    create() {
        this.add.image(0, 0, 'block');
    }
}

画像をロードするためには、
this.load.image(キー名, パス); を指定します。
パスは、publicフォルダからの相対パスです。

ロードで読み込んだ画像を配置するためには、以下のように記載します。
this.add.iamge(x座標, y座標, キー名);

配置した結果は、以下のとおりです。

この結果から、0,0 の原点は左上であることと、画像は右下しかみえていないことから、画像中心が指定座標に配置されていることがわかります。

100x100のサイズの画像を画面内の納めるのであれば、以下のように 50, 50 の座標に配置することになります。

    create() {
        this.add.image(50, 50, 'block');
    }

複数の画像をロードして配置

今度は、別の画像(60x60)を左上から少しずつオーバーラップして配置してみます。

    preload() {
        this.load.image('black', 'assets/Black.png');
        this.load.image('blue', 'assets/Blue.png');
        this.load.image('green', 'assets/Green.png');
    }

    create() {
        this.add.image(30, 30, 'black');
        this.add.image(80, 30, 'blue');
        this.add.image(130, 30, 'green');
    }

奥行方向は、配置した順になります。
逆の重なりにしたいのであれば、setDepthで奥行を指定します

    create() {
        this.add.image(30, 30, 'black').setDepth(30);
        this.add.image(80, 30, 'blue').setDepth(20);
        this.add.image(130, 30, 'green').setDepth(10);
    }

ロードする際に、assetsを何度も書くのは冗長なので、複数のデータを取り込むのであれば

    preload() {
        this.load.setPath('assets');
        this.load.image('black', 'Black.png');
        this.load.image('blue', 'Blue.png');
        this.load.image('green', 'Green.png');
    }

this.load.setPathに assets を指定すれば
それ以降は、省略して記載できます。

画像のスケール

X方向に2倍にしたい場合、setScaleを使います。

    create() {
        this.add.image(30, 30, 'black');
        this.add.image(60, 90, 'black').setScale(2, 1);
    }

60x60が 120x60になるので、配置の位置も60にずらしています。
x方向が2倍、 y方向は1倍のままです。

両方等倍するのであれば、 2引数ではなく1引数で指定できます。

    create() {
        this.add.image(30, 30, 'black');
        this.add.image(60, 120, 'black').setScale(2);
    }
投稿日時: 2024-07-15 15:47:15

設定についてみていきます。

まずは、テンプレでMinimalとして作成した際のmain.jsをみてみます。

yarn create @phaserjs/game
import { Game as MainGame } from './scenes/Game';

//  Find out more information about the Game Config at:
//  https://newdocs.phaser.io/docs/3.70.0/Phaser.Types.Core.GameConfig
const config = {
    type: Phaser.AUTO,
    width: 1024,
    height: 768,
    parent: 'game-container',
    backgroundColor: '#028af8',
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Scale.CENTER_BOTH
    },
    scene: [
        MainGame
    ]
};

export default new Phaser.Game(config);

■type

AUTO: ブラウザがWebGLをサポートできるかどうかを自動検出する。対応している場合はWebGLレンダラーを使用する。対応していない場合は、Canvasレンダラーを使用する。
WEBGL: 強制的にWebGLレンダラーを使用する。
CANVAS: 強制的にCanvasレンダラーを使用する。

参考:
APIドキュメントをみるといろいろ説明でてくるので参考にしてみるとよいと思います
https://newdocs.phaser.io/docs/3.80.0/focus/Phaser.AUTO


■width, height

初期状態のキャンバスの幅と高さをピクセル単位で指定


■parent

レンダラーによって作成されたキャンバスが描画される親要素(ID)名を指定する
index.htmlには、以下のように id=game-containerを持つ要素がありそこに描画される

<body>
    <div id="app">
        <div id="game-container"></div>
    </div>
    <!-- <script type="module" src="src/main.js"></script> -->
</body>

■backgroundColor

背景色を設定


■scaleのmode

FITとNONEあたりかな

長いので折り畳み・・

Scale.FIT: 縦横比を維持したまま自動的に幅、高さを変更する。
Scale.NONE: サイズ変更なし。
Scale.ENVELOP: 縦横比を保ったまま、対象エリア全体をカバーするサイズになるよう、幅と高さを自動的に調整とのこと。
Scale.RESIZE: 縦横比に関係なく、利用可能なすべての親スペースに合わせてリサイズする。

それぞれのモードの違いを以下で実験。
width: 1024
height: 768
backgroundColor: '#DDFFDD' 薄緑色 ブラウザの縮尺を30%にした状態で比較

FIT:

縦横比は維持したまま画面のサイズに合わせて変更

NONE:

NONEはサイズ変更なし

ENVELOP:

RESIZE:

公式の説明とちょっと一致している感じがしないのですが・・
縦横比関係なくリサイズするといっているけど、左上基準でサイズ固定されていて、たりないところはBackGroundColorで埋めている感じでしょうか…


■scaleのautoCenter

Scale.CENTER_BOTH: 垂直、水平方向ともにセンタリングされる。
Scale.CENTER_HORIZONTALLY: 水平方向のみセンタリングされる。
Scale.CENTER_VERTICALLY: 垂直方向のみセンタリングされる。
Scale.NO_CENTER: センタリングしない。


投稿日時: 2024-07-15 08:23:15
更新日時: 2024-07-19 16:02:19
yarn create @phaserjs/game

今度は、 Project名を Dewmo001とでもして、
Demo Game (Matching Pairs, Clicker, Shmup) を選択

一番上のDemoを選ぶ。
作成されたら、フォルダに移動して、 yarn install でモジュールのインストール
yarn run dev で起動します。

20秒間、敵が上下繰り返すのでマウスクリックで玉をうちこみ、当てたら 敵も玉をうってくるので、それを上下に移動してかわしながらどれくらい得点をのばせるかというゲームのようです。

どうように次のDemoを作成してみます。
次のゲームは、コインクリッカーというゲームで、上からふってきて、地面にぶつかったら跳ね返る動きをするのでクリックして、コインをとっていくゲームですね。

どうように最後のDemoを作成してみます。
記憶するゲームのようですね。

12枚のカードで、2枚選び絵が一致したら、カードをとりのぞいていき、全部なくしたら終了。
また、ミスすするとハートがへっていくので、ハートを多く残してクリアするってゲームのようですね。

ここらへんのサンプルも含めて、解析していろいろ調べていくか・・

投稿日時: 2024-07-14 11:57:14

ひな形を使ってプロジェクトをつくっていく。

作成

実行すると、プロジェクト名を聞かれるので適当に入力します。

次に、Demo Game(3つ選べる)か Client Framework か Web Bundler の選択画面になります。

大規模なJS書いたことないんで、フレームワークさわっていないので、
Frameworkは軽くスルーして・・・

Web Bundlerを選択。
ひとまず、webpackを選択。

今度は、最小限の設定か、一通り設定された完成されたプロジェクトかを選べるので、
いろいろ込々のComplete Projectを選択

最後に TypeScriptか JavaScriptか聞かれます。おすきなほうを…

? We anonymously record which template was selected to help guide development.
If you don't agree, press N to Quit. Otherwise, press Y. » (Y/n)
どのテンプレート選んだのか、匿名で情報を蓄積するけどいいよね? と言われるので、どうぞどうぞの Y で。

そうするとこんな感じのひな形が作られます

プロジェクト作成に成功したら次のステップとして3つ書かれています。
フォルダに移動して、モジュールをインストールして、実行してみるってことですね。

指示どおり、フォルダに移動し、yarn installでインストールを行い
yarn run devで実行

バンドルして開発用サーバーが起動し、ページを開いてくれます。

最初のひな型は、MainMenuシーン(クリック) → Gameシーン(クリック) → GameOverシーン(クリック) → MainMenuシーン
と設定されているようです。

しばらくこれを使って、使い方を探っていきます。

投稿日時: 2024-07-14 11:33:14

wikipediaをみてみると…

(Google翻訳) Phaserは、デスクトップおよびモバイル向けのHTML5ゲームを作成するために使用される2Dゲームフレームワークです。Photon Stormによって開発されたフリーソフトウェアです。

Phaser は内部的に Canvas と WebGL レンダラーの両方を使用し、ブラウザのサポートに基づいてそれらを自動的に切り替えることができます。これにより、デスクトップとモバイル間での高速レンダリングが可能になります。レンダリングには Pixi.js ライブラリを使用します。

ゲームはApache Cordovaやphonegapなどのサードパーティツールを介してiOS、Android、ネイティブデスクトップアプリにデプロイできます。
Phaser (game framework)

とりあえず、phaser.min.jsをダウンロード https://phaser.io/download/stable

公式のサイト内をあちこち見てみる。

■チュートリアル

まずはここらへんからみてみるか。
https://phaser.io/news/category/tutorial

■Phaser by Example Book

https://phaser.io/news/2024/04/phaser-by-example-book
phaserについて書かれた本(500ページ越えの17章にも及ぶもの)が、Phaserのサイトのアカウントがあると無料でダウンロードできるとのこと。

サイトのアカウントについては、メールアドレスを登録するか、Google or GitHub アカウントが使えるとのこと

アカウントのダウンロードページからdownloadできます。
https://phaser.io/account/downloads

■サンプル

githubにサンプルがあるとのこと。
https://github.com/phaserjs/phaser-by-example

■動画

公式内に動画があるんで、そっちも参考にしてみるか・・・
https://phaser.io/news/category/video

サイト内いろいろみるだけでも学べそうね。

投稿日時: 2024-07-05 23:08:05
更新日時: 2024-07-06 11:48:06

最近の投稿

最近のコメント

タグ

アーカイブ

その他