Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@KUMANOPUXTU

Phaser3(TypeScript)を使いたい ②動かしてみる

More than 1 year has passed since last update.

概要

  • Phaser3(TypeScript)を動かしてみる

前回の記事では環境構築まで行ったので、実際にPhaserを動作させてみます。

ディレクトリの用意

package.json のあるディレクトリに

  • scenes
  • assets

というディレクトリを作成してください。

場面ごとに必要なスクリプトファイルは scenes ディレクトリに保存します。
画像や音声などのファイルは assets ディレクトリに保存します。

HTMLの用意

次にHTMLファイルを用意していきます。

package.json のあるディレクトリにindex.html というファイルを作成し、以下のように記載してください。

index.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" integrity="sha256-7VVaJ5GDwFQiLIc+eNksQLUSSY5JNZtqv9o2BI8UGYg=" crossorigin="anonymous" />
    <title>テスト</title>
    <script src="dist/bundle.js"></script>
  </head>
  <body>
      <div id="game"></div>
  </body>
</html>

ポイント

  • dist下にあるbundle.jsを読み込ませる
  • Phaserの画面書き出し先の要素を用意する(<div id="game"></div>
  • リセットCSSを読ませる(好み)

WebpackによりバンドルされたJavaScriptは./dist/bundle.jsに作られます。
この中にPhaserや自分で書いたスクリプトの内容が入ってます。

ブラウザごとに既定のスタイルが用意されていて煩わしい動きをするので、
リセットCSSを読み込ませて既定のスタイルをつぶしています。

エントリポイント(index.ts)の追加

次にWebpackのエントリポイントとして指定していたindex.tsを用意します。
package.json のあるディレクトリにindex.ts というファイルを作成し、以下のように記載してください。

index.ts
import 'phaser';

//あとでコメントアウトを解除する
import Scenes from './scenes/scenes';

//コンフィグ
const config: Phaser.Types.Core.GameConfig = {
  //画面サイズ
  width: 360,
  height: 640,
  type: Phaser.AUTO,
  //ゲーム画面を描画するcanvasを書き出す先
  parent: 'game',
  //ゲーム画面を伸縮して表示させるための設定
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
    parent: 'game',
  },
  //あとでコメントアウトを解除する
  //必要なシーンを読み込む
  scene: Scenes,
};

export class Game extends Phaser.Game {
  constructor(config: Phaser.Types.Core.GameConfig) {
    super(config);
  }
}

//HTMLがロードされた後にインスタンスを生成する
window.addEventListener('load', () => {
  const game = new Game(config);
});


Phaserを実際に読み込み、configを注入してGameインスタンスを作ってます。

画像ファイルを用意する

assets ディレクトリに picture.png という画像ファイルを保存します。
いらすとやの画像でもなんでもいいです。

シーンを作ってみる

Phaserはシーン(Scene)という単位で、オブジェクト(Game Object)の管理をしてます。
「ローディング」や「タイトル」、「ポーズ」など、独立する画面ごとにシーンを切り分けていくようにするとイイ感じなんじゃないでしょうか。

とりあえず

  • ローディング画面
  • タイトル画面
  • ゲーム画面

を簡易に作ってみます。

ローディング画面を作成する

scenes ディレクトリにloading-scene.tsというファイルを作成し、以下のように記載してください。

scenes/loading-scene.ts
export default class LoadingScene extends Phaser.Scene {
  constructor() {
    super({
      key: 'Loading',
    });
  }
  /**アセットを読み込むライフサイクルで呼ばれるメソッド*/
  preload(): void {
    //ロード中の文面を設定する
    const loadingText = (progress: number): string =>
      `Now Loading ... ${Math.round(progress * 100)}%`;

    //テキストオブジェクトを作る
    const currentLoadingText = this.add.text(10, 10, loadingText(0));

    //ファイルのロードをしていく
    this.load.image('acorn', '../assets/picture.png');
    //疑似的に大量のアセットをロードするかのような動きをさせてる
    for (let index = 0; index < 100; index++) {
      this.load.image('acorn' + index, '../assets/picture.png');
    }

    //ロードに進捗があるたびに発生するイベント
    this.load.on('progress', (progress: number) => {
      //テキストの内容を書き換える
      currentLoadingText.text = loadingText(progress);
    });
    //ロードが完了すると発生するイベント
    this.load.on('complete', () => {
      //タイトルシーンへ遷移
      this.scene.start('Title');
    });
  }
}

シーンはPhaser.Sceneを継承して実装していきます。
必要な画像データをロードする処理は、preload()の中に実装していくようにしてください。
ここでロードしたデータは、別のシーンでも使えます。

コンストラクタ内にシーン固有のコンフィグを設定していってください。

タイトル画面を作成する

scenes ディレクトリにtitle-scene.tsというファイルを作成し、以下のように記載してください。

scenes/title-scene.ts
export default class TitleScene extends Phaser.Scene {
  constructor() {
    super({
      key: 'Title',
    });
  }

  /**ロードが終わったあとのライフサイクルで呼ばれるメソッド */
  create(): void {
    const text = this.add.text(10, 10, 'おしたらStart');

    //setInteractiveを呼ぶと動的なオブジェクトになる
    //入力系のイベントなどが有効化される
    text.setInteractive();

    text.on('pointerdown', () => {
      this.scene.start('Main');
    });
  }
}

必要な画像データがロードされたあと、シーンの開始時点で必要な処理は、create()の中に実装していくようにしてください。

ゲーム画面を作成する

scenes ディレクトリにmain-scene.tsというファイルを作成し、以下のように記載してください。

scenes/main-scene.ts
export default class MainScene extends Phaser.Scene {
  private acorn: Phaser.Physics.Arcade.Image;
  constructor() {
    super({
      key: 'Main',
      physics: { arcade: { debug: true } },
    });
  }

  create(): void {
    this.physics.world.gravity.y = 100;
    this.acorn = this.physics.add
      .sprite(30, 30, 'acorn') //loading画面で設定したkeyで画像を読める
      .setScale(0.1)
      .setOrigin(0, 0)
      .setInteractive()
      .setVelocityX(100)
      .setCollideWorldBounds(true, 1, 1);
    this.acorn.on('pointerdown', () => {
      this.acorn.setVelocityX(-this.acorn.body.velocity.x);
    });
  }
  update(): void {
    console.log(this.acorn.x, this.acorn.y);
  }
}

シーンが開始されて毎フレーム必要な処理は、update()の中に実装していくようにしてください。
acornに対してsetしている内容は大体読めばわかる通りです。
数値をいじるといろいろ変化がおきるので試してください。

このシーン固有のコンフィグとして、物理演算を有効化しています。

各シーンをフレームワークのConfigに設定する

index.ts の中で設定しているconfigに設定を適用します。

scenes ディレクトリにscenes.tsというファイルを作成し、以下のように記載してください。

scenes/scenes.ts
import Main from './main-scene';
import Loading from './loading-scene';
import Title from './title-scene';

export default [Loading, Main, Title];
export { Main, Loading, Title };

シーン増えるとわけわかんなくなってくるので、ここでシーンを全部束ねておきます。

最後に index.ts のコメントアウトを解除します。

index.ts
import 'phaser';

//ここのコメントアウトを解除する
import Scenes from './scenes/scenes';

//コンフィグ
const config: Phaser.Types.Core.GameConfig = {
  //画面サイズ
  width: 360,
  height: 640,
  type: Phaser.AUTO,
  //ゲーム画面を描画するcanvasを書き出す先
  parent: 'game',
  //ゲーム画面を伸縮して表示させるための設定
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
    parent: 'game',
  },
  //ここのコメントアウトを解除する
  //必要なシーンを読み込む
  scene: Scenes,
};

export class Game extends Phaser.Game {
  constructor(config: Phaser.Types.Core.GameConfig) {
    super(config);
  }
}

//HTMLがロードされた後にインスタンスを生成する
window.addEventListener('load', () => {
  const game = new Game(config);
});

これで作成したシーンの内容がPhaserに反映されるようになります。

開発用サーバを起動する

yarn dev

を実行してください。
Webpackがindex.tsを起点に必要なモジュールをバンドルして、 dist/bundle.js を生成しつつ、開発用のWebサーバを立ち上げてくれます。
TypeScriptファイルの更新を検知し、なんらか更新されたら自動的に再読み込みが行われます。

超簡素ですが、とりあえず動作する状態になりました。

image.png

最後に

次回はTiledと連携してレベルを作ったりするところをやってみます。

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
KUMANOPUXTU
vtuber好き

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
4
Help us understand the problem. What is going on with this article?