0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Phaser 3 で毎回同じアセット読み込みコードを書くのに疲れたので、 自動化ライブラリを作った

Last updated at Posted at 2025-06-27

Phaser-EZ を作った理由と使い方について

Phaser 3 でゲーム開発していて、毎回同じようなコード書くのが面倒になったので、ライブラリを作ってみました。

なぜ作ったのか

教育ゲームの案件で Phaser 3 を使っていたんですが、シーンが50個以上あって、毎回こんなコードを書くのが嫌になりました:

class Scene1 extends Phaser.Scene {
  preload() {
    this.load.image('bg1', './assets/scene1/bg.png')
    this.load.image('char1', './assets/scene1/character.png')
    this.load.audio('bgm1', './assets/scene1/bgm.mp3')
    // ... 20個ぐらいのアセット読み込み
  }
  
  create() {
    // シーン切り替えのコード
    // メモリリーク対策
    // イベントの掃除
  }
}

class Scene2 extends Phaser.Scene {
  preload() {
    this.load.image('bg2', './assets/scene2/bg.png')
    // ... また同じことの繰り返し
  }
}

同じようなことを50回も書くのは流石に無駄だと思ったので、自動化できないかと考えました。

作ったもの

基本的にやったのは「ディレクトリ構造でアセットを自動読み込み」と「シーン管理の簡素化」です。

ディレクトリベースの自動読み込み

アセットをこんな感じで置いておくと:

src/assets/
├── images/
│   ├── MainMenu/          # MainMenuシーン用
│   │   ├── background.png
│   │   └── logo.png
│   └── GameLevel/         # GameLevelシーン用
│       └── player.png
└── sounds/
    ├── MainMenu/
    └── GameLevel/

シーンのコードはこれだけになります:

class MainMenu extends DefaultScene {
  constructor() {
    super('MainMenu')  // フォルダ名と同じにする
  }
  
  start() {
    // アセットはもう読み込み済み
    this.add.image(400, 300, 'background')
    this.add.image(400, 200, 'logo')
  }
}

Viteの import.meta.glob を使って、ビルド時にアセットを自動検出してます。スプライトシートも character_32x48.png みたいな名前にしておけば自動で認識します。

シーン切り替えの簡素化

従来だとシーン切り替えで色々気をつけないといけなかったんですが:

// 前のシーンの掃除とか面倒だった
this.scene.stop('CurrentScene')
this.scene.start('NextScene')
// イベントリスナーの掃除とか忘れがち

これを一行にしました:

DefaultScene.start(this, 'NextScene')
// 前のシーンの掃除も自動でやってくれる

Vue との連携

案件でVueも使ってたので、EventBusで連携できるようにしました:

// Vue側
EventBus.on('score-update', (score) => {
  this.score = score
})

// Phaser側
EventBus.emit('score-update', 100)

実際の効果

同じ案件で比較してみたら:

  • アセット読み込みのコード:2400行 → 0行
  • シーン作成の時間:30分 → 5分ぐらい
  • メモリリーク系のバグ:12個 → 0個

特に新しい人が入ってきた時の学習コストがかなり下がりました。

使い方

インストール

npm install phaser-ez phaser

基本的な使い方

import { Main, DefaultScene } from 'phaser-ez'

class MyGame extends DefaultScene {
  constructor() {
    super('MyGame')
  }
  
  start() {
    this.add.text(400, 300, 'Hello World', {
      fontSize: '32px'
    }).setOrigin(0.5)
  }
}

const { game } = Main({
  config: {
    type: Phaser.AUTO,
    width: 800,
    height: 600
  },
  scenes: { MyGame }
})

アセットの置き方

src/assets/images/MyGame/
├── background.png
├── player.png
└── enemy_32x32.png  # スプライトシートとして自動認識

これだけでアセットが自動で読み込まれます。

Vue との組み合わせ

Vue 3 + Vite の環境で使うと、ホットリロードも効くし開発体験がかなり良くなります:

<template>
  <div>
    <PhaserGame ref="gameRef" />
    <GameUI :score="score" />
  </div>
</template>

<script setup>
import { EventBus } from 'phaser-ez'
import { ref } from 'vue'

const score = ref(0)

EventBus.on('score-change', (newScore) => {
  score.value = newScore
})
</script>

デモ

動くものを見たい場合は:

git clone https://github.com/gimwachan-git/phaser-ez.git
cd phaser-ez/examples/vue
pnpm install
pnpm dev

MainMenu、Vue連携、アニメーションなどのサンプルが入ってます。

向いてるプロジェクト

こんなプロジェクトに向いてると思います:

  • 教育ゲーム、学習アプリ
  • シーンがたくさんあるゲーム
  • Vue を使ってるプロジェクト
  • プロトタイプを早く作りたい時

逆に、パフォーマンスを極限まで追求したいとか、Phaserの細かい制御が必要な場合は、普通にPhaserを使った方がいいかもしれません。

技術的な話

Convention over Configuration

Rails とか Next.js みたいに「設定より規約」の思想で作りました。ディレクトリ構造や命名規則を決めておけば、設定ファイルをいちいち書かなくて済みます。

ビルド

ES modules と CommonJS 両方に対応してます。Vite でビルドしてて、Phaser は peer dependency として外出ししてます。

TypeScript

一応TypeScriptにも対応してますが、まだ型定義が完璧じゃないかもしれません。

現在の状況

バージョン 0.0.218 で、まだ開発中です。実際の案件で使ってるので、バグを見つけたら直してます。

MIT ライセンスなので、商用でも自由に使えます。

おわりに

毎回同じコードを書くのが嫌で作り始めたライブラリですが、思ったより便利になったので公開しました。同じような悩みを持ってる人の役に立てれば嬉しいです。

バグとか要望があれば GitHub の Issues に投げてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?