diff --git a/apps/client/src/scenes/game/GameManager.ts b/apps/client/src/scenes/game/GameManager.ts index 9a1b14e..4da0b22 100644 --- a/apps/client/src/scenes/game/GameManager.ts +++ b/apps/client/src/scenes/game/GameManager.ts @@ -10,6 +10,7 @@ import { GameNetworkSync } from "./application/GameNetworkSync"; import { GameLoop } from "./application/GameLoop"; import { BombManager } from "./application/BombManager"; +import type { BombUpsertPayload } from "./application/BombManager"; import type { GamePlayers } from "./application/game.types"; /** ゲームシーンの実行ライフサイクルを管理するマネージャー */ @@ -35,8 +36,17 @@ return this.timer.getRemainingTime(); } - public placeBomb() { - this.bombManager?.placeBomb(); + public placeBomb(): string | null { + if (!this.bombManager) return null; + return this.bombManager.placeBomb(); + } + + public upsertBomb(bombId: string, payload: BombUpsertPayload): void { + this.bombManager?.upsertBomb(bombId, payload); + } + + public removeBomb(bombId: string): void { + this.bombManager?.removeBomb(bombId); } // 入力と状態管理 diff --git a/apps/client/src/scenes/game/application/BombManager.ts b/apps/client/src/scenes/game/application/BombManager.ts index 9ed623a..08a923c 100644 --- a/apps/client/src/scenes/game/application/BombManager.ts +++ b/apps/client/src/scenes/game/application/BombManager.ts @@ -12,6 +12,14 @@ /** 経過時間ミリ秒を返す関数型 */ export type ElapsedMsProvider = () => number; +/** 爆弾の追加更新に使う入力データ型 */ +export type BombUpsertPayload = { + x: number; + y: number; + radiusGrid: number; + explodeAtElapsedMs: number; +}; + type BombManagerOptions = { worldContainer: Container; players: GamePlayers; @@ -25,7 +33,8 @@ private players: GamePlayers; private myId: string; private getElapsedMs: ElapsedMsProvider; - private bombs: BombController[] = []; + private bombs = new Map(); + private nextLocalBombId = 1; private lastBombPlacedElapsedMs = Number.NEGATIVE_INFINITY; constructor({ worldContainer, players, myId, getElapsedMs }: BombManagerOptions) { @@ -35,53 +44,72 @@ this.getElapsedMs = getElapsedMs; } - /** 自プレイヤー位置に爆弾を設置する */ - public placeBomb(): void { + /** 自プレイヤー位置に爆弾を設置し,生成IDを返す */ + public placeBomb(): string | null { const me = this.players[this.myId]; - if (!me || !(me instanceof LocalPlayerController)) return; + if (!me || !(me instanceof LocalPlayerController)) return null; const elapsedMs = this.getElapsedMs(); const { BOMB_COOLDOWN_MS, BOMB_FUSE_MS, BOMB_RADIUS_GRID } = config.GAME_CONFIG; if (elapsedMs - this.lastBombPlacedElapsedMs < BOMB_COOLDOWN_MS) { - return; + return null; } const position = me.getPosition(); - const bomb = new BombController({ + const payload: BombUpsertPayload = { x: position.x, y: position.y, radiusGrid: BOMB_RADIUS_GRID, explodeAtElapsedMs: elapsedMs + BOMB_FUSE_MS, - }); + }; + const bombId = `local-${this.nextLocalBombId}`; + this.nextLocalBombId += 1; - this.bombs.push(bomb); - this.worldContainer.addChild(bomb.getDisplayObject()); + this.upsertBomb(bombId, payload); this.lastBombPlacedElapsedMs = elapsedMs; + return bombId; + } + + /** 指定IDの爆弾を追加または更新する */ + public upsertBomb(bombId: string, payload: BombUpsertPayload): void { + const current = this.bombs.get(bombId); + if (current) { + this.worldContainer.removeChild(current.getDisplayObject()); + current.destroy(); + } + + const bomb = new BombController(payload); + this.bombs.set(bombId, bomb); + this.worldContainer.addChild(bomb.getDisplayObject()); + } + + /** 指定IDの爆弾を削除する */ + public removeBomb(bombId: string): void { + const bomb = this.bombs.get(bombId); + if (!bomb) return; + + this.worldContainer.removeChild(bomb.getDisplayObject()); + bomb.destroy(); + this.bombs.delete(bombId); } /** 爆弾状態を更新し終了済みを破棄する */ public tick(): void { const elapsedMs = this.getElapsedMs(); - const nextBombs: BombController[] = []; - this.bombs.forEach((bomb) => { + this.bombs.forEach((bomb, bombId) => { bomb.tick(elapsedMs); if (bomb.isFinished()) { - this.worldContainer.removeChild(bomb.getDisplayObject()); - bomb.destroy(); + this.removeBomb(bombId); return; } - - nextBombs.push(bomb); }); - - this.bombs = nextBombs; } /** 管理中の爆弾をすべて破棄する */ public destroy(): void { this.bombs.forEach((bomb) => bomb.destroy()); - this.bombs = []; + this.bombs.clear(); } }