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-EZ にバニラJS版サンプルを追加しました - フレームワーク選択の自由度について

Last updated at Posted at 2025-07-05

以前作った Phaser-EZ ライブラリに、Vue版に加えてバニラJS版のサンプルを追加しました。これは業務案件での必要性から生まれたものですが、結果的に「フレームワークを使わずに Phaser-EZ を使いたい」という声にも応えられるようになりました。

背景:実務で感じた課題

実は、バニラJS版を作ったのは外部からの要望対応ではありません。実際の業務案件で Phaser-EZ を使う必要があり、その過程である問題に気づいたからです。

最初のサンプルは Vue との連携にフォーカスしていましたが、業務では Vue を使わないプロジェクトもありました。そこでバニラJS での使用を試してみると...

柔軟性のジレンマ

業務でゲーム開発をしていると、プロジェクトごとに要求が全然違います:

  • 「アセットの読み込み方法を変えたい」
  • 「独自のシーン管理システムと組み合わせたい」
  • 「特定のフレームワークでラップしたい」
  • 「メモリ管理を細かく制御したい」

そこで、これらの要望に応えるために、たくさんの設定オプションを用意しました。しかし、その結果...

初期設定がものすごく複雑になってしまいました。

そこで、全く同じゲームロジックを持つバニラJS版サンプルを作成しました。

比較:Vue版 vs バニラJS版

プロジェクト構成の違い

Vue版

examples/vue/
├── src/
│   ├── components/     # Vue コンポーネント
│   ├── stores/         # Pinia ストア
│   ├── game/           # ゲーム関連
│   └── App.vue         # メインアプリ
├── package.json        # Vue, Pinia, SSG関連の依存関係
└── vite.config.mjs     # Vue プラグイン設定

バニラJS版

examples/vanilla/
├── src/
│   ├── scenes/         # ゲームシーン
│   ├── assets/         # ゲームアセット
│   ├── libs/           # ユーティリティ
│   └── main.js         # エントリーポイント
├── package.json        # 最小限の依存関係
└── vite.config.js      # シンプルな設定

依存関係の比較

Vue版の dependencies

{
  "phaser": "^3.87.0",
  "phaser-ez": "^0.0.218",
  "pinia": "^2.3.0",
  "vue": "^3.5.13"
}

バニラJS版の dependencies

{
  "phaser": "^3.87.0",
  "phaser-ez": "^0.0.218"
}

必要最小限の依存関係で済みます。

設定の複雑さを比較してみる

現在の初期化コードの現実

実際に両方のサンプルを見ると、初期設定がかなり複雑になっているのがわかります:

ゲーム初期化コード

Vue版(PhaserGame.vue)

// Vue コンポーネント内
const startGame = async () => {
  const config = {
    parent: gameContainerId,
    type: Phaser.CANVAS,
    width: 1024,
    height: 768,
    // ...
  }
  
  // アセットコンテキストの設定(複雑!)
  DefaultScene.soundsContext = import.meta.glob('@/assets/sounds/**/*', {
    eager: true
  })
  DefaultScene.imagesContext = import.meta.glob('@/assets/images/**/*', {
    eager: true
  })
  
  // プリローダーの詳細設定(これも複雑!)
  Preloader.imagesCommonContext = import.meta.glob('@/assets/common/images/Preloader/*', {
    eager: true
  })
  Preloader.nextSceneKey = 'MainMenu'
  Preloader.config.autoStart = false
  
  // Vue のリアクティブな状態との連携
  const appStore = useAppStore()
  EventBus.on('scene-start', (scene) => {
    selectedScene.value = scene.sceneKey
  })
}

バニラJS版(main.js)

// 純粋なJavaScript
const startGame = async () => {
  const config = {
    parent: 'game-container',
    type: Phaser.CANVAS,
    width: 1024,
    height: 768,
    // ...
  }
  
  // 同じく複雑なアセットコンテキスト設定
  DefaultScene.soundsContext = import.meta.glob('./assets/sounds/**/*', {
    eager: true
  })
  DefaultScene.imagesContext = import.meta.glob('./assets/images/**/*', {
    eager: true
  })
  
  // 同じくプリローダー設定
  Preloader.imagesCommonContext = import.meta.glob('./assets/common/images/Preloader/*', {
    eager: true
  })
  Preloader.nextSceneKey = 'MainMenu'
  Preloader.config.autoStart = false
  
  // シンプルなコンソールログ
  EventBus.on('scene-start', (scene) => {
    console.log(`Scene ${scene.sceneKey} started`)
  })
}

場面の実装

ゲームロジック自体は全く同じですが、バニラJS版では Vue特有の部分を削除しています:

Vue版のシーン

// Vue コンポーネントとの連携を想定
EventBus.emit('scene-log', 'User clicked - transitioning to Vue scene')
DefaultScene.start(this, 'Vue')

バニラJS版のシーン

// 純粋なJavaScript版
EventBus.emit('scene-log', 'User clicked - transitioning to Vanilla scene')
DefaultScene.start(this, 'Vanilla')

実際の使用感

Vue版のメリット

  • フレームワークとの連携: Vue のリアクティブシステムとの連携が簡単
  • コンポーネント分割: UI部分を Vue コンポーネントで管理
  • 状態管理: Pinia によるグローバル状態管理
  • 開発体験: Vue Devtools, ホットリロード

バニラJS版のメリット

  • 軽量: 最小限の依存関係
  • シンプル: フレームワークの学習コストなし
  • 高速: 余分な抽象化レイヤーなし
  • 自由度: どんなプロジェクトにも組み込みやすい

具体的な使い方

バニラJS版の始め方

# サンプルをクローン
git clone https://github.com/gimwachan-git/phaser-ez.git
cd phaser-ez/examples/vanilla

# 依存関係をインストール
pnpm install

# 開発サーバー起動
pnpm run dev

新しいプロジェクトで使う場合

# 新しいプロジェクトを作成
mkdir my-game
cd my-game
pnpm init -y

# 必要な依存関係をインストール
pnpm install phaser phaser-ez vite

# シンプルなゲームを作成
mkdir -p src/assets/images/MyScene
echo 'console.log("Hello Phaser-EZ!")' > src/main.js

プロジェクトの柔軟性を実感

今回バニラJS版を作ってみて、Phaser-EZ の設計思想が正しかったと確信しました:

1. フレームワーク非依存の設計

  • 内部的に Phaser と軽量なユーティリティのみ使用
  • Vue, React, Angular など、どのフレームワークとも組み合わせ可能
  • もちろんフレームワークなしでも使用可能

2. 段階的な導入

  • 既存のプロジェクトに徐々に導入可能
  • 最小限の変更で Phaser-EZ の恩恵を受けられる
  • 必要に応じて機能を追加していける

3. 実装の自由度

  • UI部分は好きな技術で実装
  • ゲームロジックは Phaser-EZ で統一
  • 状態管理も自由に選択

使い分けの指針

Vue版を選ぶべき場合

  • Vue.js を使った Web アプリケーション内にゲームを組み込みたい
  • UI とゲームの状態を密に連携させたい
  • SSG(Static Site Generation)で配信したい
  • Vue の開発体験を活用したい

バニラJS版を選ぶべき場合

  • 軽量なゲームを作りたい
  • 既存のプロジェクトに組み込みたい
  • フレームワークの学習コストを避けたい
  • 最大限の自由度を求める

技術的な工夫

共通コードの維持

両方のサンプルで同じアセットとアニメーションライブラリを使用することで、コードの重複を避けました:

// 共通のアニメーションライブラリ
import { createFallAnimation } from '../libs/Phaser/animations/index.js'

// Vue版でもバニラJS版でも同じように使用
createFallAnimation(this, this.logo)

ビルド設定の最適化

それぞれの用途に最適化したビルド設定を用意:

Vue版: SSG対応、コンポーネント分割、開発ツール統合
バニラJS版: 最小限の設定、高速ビルド、シンプルな構成

課題:設定が複雑すぎる問題

正直に言うと、現在の Phaser-EZ は "OOTB"(out-of-the-box)ではありません。

上記のコードを見ると分かる通り、Vue版もバニラJS版も、初期設定で大量のボイラープレートコードが必要です:

  • アセットコンテキストの設定(6行)
  • プリローダーの詳細設定(4行)
  • EventBusリスナーの設定(複数行)

これは「簡単に使えるライブラリ」とは言えません。

原因:柔軟性を追求しすぎた

業務でのカスタマイズ要求に応えるため、たくさんの設定オプションを用意した結果:

// 現在:設定項目が多すぎる
DefaultScene.soundsContext = ...
DefaultScene.imagesContext = ...
DefaultScene.videosContext = ...
DefaultScene.persistentSounds = ...
Preloader.imagesCommonContext = ...
Preloader.soundsCommonContext = ...
Preloader.nextSceneKey = ...
Preloader.config.autoStart = ...
Preloader.imagesCommonFilenames = ...
// まだまだ続く...

理想:こうなってほしい

// vite.config.js
import { defineConfig } from 'vite'
import { phaserEZ } from 'vite-plugin-phaser-ez'

export default defineConfig({
  plugins: [
    phaserEZ({
      scenes: './src/scenes/*.js',
      assets: './src/assets',
      autoStart: true
    })
  ]
})
// main.js - シンプルに
import { createGame } from 'phaser-ez'

const game = createGame()  // Viteプラグインが全部やってくれる

解決策:Viteプラグインを検討中

現在、この問題を解決するために Viteプラグイン の開発を検討しています。みんなが Vite を使っている今の流れに合わせて、より自然な開発体験を提供したいと思います。

Viteプラグインの構想

// vite.config.js
import { defineConfig } from 'vite'
import { phaserEZ } from 'vite-plugin-phaser-ez'

export default defineConfig({
  plugins: [
    phaserEZ({
      // 基本設定
      scenes: './src/scenes/*.js',
      assets: './src/assets',
      
      // オプション設定
      autoStart: true,
      sceneTransitions: true,
      memoryManagement: 'auto',
      
      // フレームワーク統合
      framework: 'vue', // 'vue' | 'react' | 'none'
    })
  ]
})
// main.js - 驚くほどシンプル
import { createGame } from 'phaser-ez'

// Viteプラグインが build time に全部解析してくれる
const game = createGame()

Viteプラグインの利点

  1. ビルド時最適化: シーンとアセットをビルド時に自動解析
  2. HMR対応: 開発中のホットリロードが効く
  3. 型安全性: TypeScriptでアセットの型も自動生成
  4. エコシステム統合: 他のViteプラグインとの組み合わせが自然
  5. 設定の一元化: vite.config.js ですべて完結

段階的な機能提供

// レベル1:最小構成
export default defineConfig({
  plugins: [phaserEZ()]  // デフォルト設定で即座に動く
})
// レベル2:カスタマイズ
export default defineConfig({
  plugins: [
    phaserEZ({
      scenes: './src/scenes/*.js',
      assets: './src/assets'
    })
  ]
})
// レベル3:フル機能
export default defineConfig({
  plugins: [
    phaserEZ({
      scenes: './src/scenes/*.js',
      assets: './src/assets',
      framework: 'vue',
      preloader: {
        autoStart: false,
        customLoader: './src/CustomLoader.vue'
      },
      performance: {
        memoryManagement: true,
        assetOptimization: true
      }
    })
  ]
})

まとめ

Phaser-EZ の魅力は「必要な機能だけを使って、好きな技術と組み合わせられる」ことです。しかし、現在は初期設定が複雑になってしまい、本来の魅力を活かしきれていません。

現在の状況:

  • Vue を使いたい人: Vue版サンプルを参考に(ただし設定が複雑)
  • フレームワークを使いたくない人: バニラJS版サンプルを参考に(同じく複雑)
  • React を使いたい人: バニラJS版をベースに React と組み合わせ(やはり複雑)

理想の未来:

  • 簡単に始めたい人: 基本プラグインで即座にスタート
  • カスタマイズしたい人: 専用プラグインで柔軟に拡張
  • 上級者: 独自プラグインで完全カスタマイズ

プラグインシステムが実現すれば、真に「使いやすくて柔軟なライブラリ」になると確信しています。

次回予告

プラグインシステムの設計と実装について、詳しく記事にする予定です。また、React 版のサンプルも作る予定ですが、その時にはプラグインベースの新しいアーキテクチャで実装したいと思います。


リンク

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?