配列を使った複数のモグラを管理する、より高度なモグラたたきゲームを作成します
この発展編では配列や複数オブジェクトの管理など、やや高度な概念を扱います。 まずは基本編で1匹のモグラを使ったシンプルなゲームを完成させてから挑戦することをおすすめします。
まず、ゲームで使用する画像ファイルを準備します。src/assets
フォルダに以下の画像を配置してください。
💡 画像について:
画像は自分で用意するか、フリー素材サイトからダウンロードしてください。 シンプルな図形でも構いません。重要なのはPhaserJSの使い方を学ぶことです!
src/scenes
フォルダにGameScene.ts
を作成します。
// src/scenes/GameScene.ts import * as Phaser from 'phaser'; export class GameScene extends Phaser.Scene { // モグラの穴の位置を定義 private holes: { x: number, y: number }[] = [ { x: 200, y: 200 }, { x: 400, y: 200 }, { x: 600, y: 200 }, { x: 200, y: 350 }, { x: 400, y: 350 }, { x: 600, y: 350 }, ]; // 穴のスプライトを格納する配列 private holeSprites: Phaser.GameObjects.Image[] = []; // 現在表示中のモグラを格納する配列 private moles: Phaser.GameObjects.Image[] = []; constructor() { super({ key: 'GameScene' }); } // ゲーム開始前にアセットを読み込む preload(): void { // 画像ファイルを読み込み this.load.image('hole', 'assets/hole.png'); this.load.image('mole', 'assets/mole.png'); this.load.image('mole_hit', 'assets/mole_hit.png'); } // シーンが開始されたときに実行 create(): void { // 背景色を設定 this.cameras.main.setBackgroundColor('#4ade80'); // 穴を配置 this.holes.forEach(holePos => { const hole = this.add.image(holePos.x, holePos.y, 'hole'); this.holeSprites.push(hole); }); // 2秒ごとにモグラを出現させる this.time.addEvent({ delay: 2000, // 2000ミリ秒 = 2秒 callback: this.spawnMole, callbackScope: this, loop: true // 繰り返し実行 }); } }
プログラミングでは変数を使ってデータを保存します。箱に名前を付けて、その中に値を入れるイメージです。
💡 変数名は分かりやすい名前にすることが重要です!holes
なら「穴」、moles
なら「モグラ」とすぐ分かりますね。
配列は、複数のデータをまとめて管理できる便利な入れ物です。ロッカーのように番号付きの箱がたくさん並んでいるイメージです。
fruits = ["りんご", "バナナ", "みかん"]
fruits[0]
で「りんご」を取得
fruits[1]
で「バナナ」を取得
push()
-
配列の最後に新しい要素を追加
length
-
配列の要素数を取得
forEach()
-
配列の全要素に対して処理を実行
find()
-
条件に合う要素を検索
GameScene.tsに以下のメソッドを追加します。
// GameScene.tsのcreate()メソッドの後に追加 // ランダムな穴からモグラを出現させる private spawnMole(): void { // ランダムな穴を選択 const randomIndex = Phaser.Math.Between(0, this.holes.length - 1); const holePos = this.holes[randomIndex]; // すでにその穴にモグラがいるかチェック const existingMole = this.moles.find(mole => mole.x === holePos.x && mole.y === holePos.y ); // すでにモグラがいる場合は何もしない if (existingMole) { return; } // モグラを作成 const mole = this.add.image(holePos.x, holePos.y, 'mole'); // モグラをクリック可能にする mole.setInteractive(); // クリックされたときの処理 mole.on('pointerdown', () => { this.hitMole(mole); }); // モグラを配列に追加 this.moles.push(mole); // 3秒後にモグラを自動で消す this.time.delayedCall(3000, () => { this.removeMole(mole); }); } // モグラがクリックされたときの処理 private hitMole(mole: Phaser.GameObjects.Image): void { // 画像をやられた状態に変更 mole.setTexture('mole_hit'); // クリックを無効にする mole.disableInteractive(); // 0.5秒後にモグラを消す this.time.delayedCall(500, () => { this.removeMole(mole); }); } // モグラを画面から削除 private removeMole(mole: Phaser.GameObjects.Image): void { // 配列からモグラを削除 const index = this.moles.indexOf(mole); if (index > -1) { this.moles.splice(index, 1); } // 画面からモグラを削除 mole.destroy(); }
src/main.ts
を以下のように更新します。
// src/main.ts import './style.css'; import * as Phaser from 'phaser'; import { GameScene } from './scenes/GameScene'; // ゲーム設定 const config: Phaser.Types.Core.GameConfig = { type: Phaser.AUTO, width: 800, height: 600, parent: 'app', backgroundColor: '#4ade80', scene: [GameScene] }; // ゲームを開始 new Phaser.Game(config);
すべてのコードを保存したら、ターミナルで開発サーバーを起動します。
🐛 うまく動かない場合:
ブラウザのデベロッパーツール(F12)でエラーメッセージを確認してください。 よくある問題は画像ファイルのパスが間違っていることです。
タイマーイベントの代わりに、変数とdeltaTimeを使ってモグラの表示時間を管理する方法を学びましょう。 この方法はより細かい制御が可能で、フレームレートに依存しない安定した動作を実現できます。
// より柔軟なGameScene.tsの実装 export class GameScene extends Phaser.Scene { // モグラの穴の位置を定義 private holes: { x: number, y: number }[] = [ { x: 200, y: 200 }, { x: 400, y: 200 }, { x: 600, y: 200 }, { x: 200, y: 350 }, { x: 400, y: 350 }, { x: 600, y: 350 }, ]; // 穴のスプライトを格納する配列 private holeSprites: Phaser.GameObjects.Image[] = []; // モグラの情報を格納するオブジェクト private moles: { sprite: Phaser.GameObjects.Image; timeAlive: number; // 生存時間(ミリ秒) maxLifeTime: number; // 最大生存時間 isHit: boolean; // クリックされたかどうか hitTime: number; // クリックされた時間 }[] = []; // 時間管理用の変数 private lastSpawnTime: number = 0; // 最後にモグラを出現させた時間 private spawnInterval: number = 2000; // モグラ出現間隔(ミリ秒) private moleLifeTime: number = 3000; // モグラの生存時間(ミリ秒) private hitDisplayTime: number = 500; // やられた状態の表示時間 create(): void { // 背景色を設定 this.cameras.main.setBackgroundColor('#4ade80'); // 穴を配置 this.holes.forEach(holePos => { const hole = this.add.image(holePos.x, holePos.y, 'hole'); this.holeSprites.push(hole); }); // 初回のモグラ出現時間を設定 this.lastSpawnTime = this.time.now; } // 毎フレーム実行される更新処理 update(time: number, delta: number): void { // モグラの出現チェック if (time - this.lastSpawnTime >= this.spawnInterval) { this.spawnMole(); this.lastSpawnTime = time; } // 各モグラの生存時間を更新 this.moles.forEach((moleData, index) => { moleData.timeAlive += delta; // クリックされていない場合 if (!moleData.isHit) { // 生存時間が超過した場合、モグラを削除 if (moleData.timeAlive >= moleData.maxLifeTime) { this.removeMoleAt(index); return; // 配列が変更されるので処理を中断 } } else { // クリックされた場合、一定時間後に削除 if (time - moleData.hitTime >= this.hitDisplayTime) { this.removeMoleAt(index); return; } } }); } // ランダムな穴からモグラを出現させる private spawnMole(): void { // ランダムな穴を選択 const randomIndex = Phaser.Math.Between(0, this.holes.length - 1); const holePos = this.holes[randomIndex]; // すでにその穴にモグラがいるかチェック const existingMole = this.moles.find(moleData => moleData.sprite.x === holePos.x && moleData.sprite.y === holePos.y ); if (existingMole) { return; } // モグラを作成 const mole = this.add.image(holePos.x, holePos.y, 'mole'); mole.setInteractive(); // モグラデータを作成 const moleData = { sprite: mole, timeAlive: 0, maxLifeTime: this.moleLifeTime, isHit: false, hitTime: 0 }; // クリックイベント mole.on('pointerdown', () => { this.hitMole(moleData); }); this.moles.push(moleData); } // モグラがクリックされたときの処理 private hitMole(moleData: any): void { moleData.sprite.setTexture('mole_hit'); moleData.sprite.disableInteractive(); moleData.isHit = true; moleData.hitTime = this.time.now; } // 指定したインデックスのモグラを削除 private removeMoleAt(index: number): void { const moleData = this.moles[index]; moleData.sprite.destroy(); this.moles.splice(index, 1); } }
この発展編では、配列を使った複数オブジェクト管理やDeltaTimeによる高度な時間制御など、 より実践的なゲーム開発テクニックを学習しました。基本編で学んだ概念を発展させ、 本格的なゲーム開発に必要なスキルを身につけることができたはずです。