diff --git a/apps/client/src/scenes/game/GameManager.ts b/apps/client/src/scenes/game/GameManager.ts index 1f419a2..2251d3b 100644 --- a/apps/client/src/scenes/game/GameManager.ts +++ b/apps/client/src/scenes/game/GameManager.ts @@ -120,14 +120,6 @@ }); this.networkSync.bind(); - this.gameLoop = new GameLoop({ - app: this.app, - worldContainer: this.worldContainer, - players: this.players, - myId: this.myId, - getJoystickInput: () => this.joystickInput, - }); - const bombHitContextProvider = new BombHitContextProvider({ players: this.players, myId: this.myId, @@ -147,6 +139,15 @@ }, }); + this.gameLoop = new GameLoop({ + app: this.app, + worldContainer: this.worldContainer, + players: this.players, + myId: this.myId, + getJoystickInput: () => this.joystickInput, + bombManager: this.bombManager, + }); + // サーバーへゲーム準備完了を通知 socketManager.game.readyForGame(); @@ -168,7 +169,6 @@ */ private tick = (ticker: Ticker) => { this.gameLoop?.tick(ticker); - this.bombManager?.tick(); }; /** diff --git a/apps/client/src/scenes/game/application/BombHitOrchestrator.ts b/apps/client/src/scenes/game/application/BombHitOrchestrator.ts index 1ff843d..0def7b5 100644 --- a/apps/client/src/scenes/game/application/BombHitOrchestrator.ts +++ b/apps/client/src/scenes/game/application/BombHitOrchestrator.ts @@ -1,7 +1,7 @@ /** * BombHitOrchestrator * 爆弾爆発イベントとローカルプレイヤー情報を橋渡しして当たり判定を実行する - * 同一爆弾の重複判定を抑止し,ヒット時のみデバッグログを出力する + * 同一爆弾の重複判定を抑止して当たり判定を実行する */ import { checkBombHit } from "@client/scenes/game/entities/bomb/BombHitDetector"; import type { BombExplodedPayload } from "@client/scenes/game/entities/bomb/BombManager"; @@ -47,13 +47,6 @@ return; } - console.log("[BombHitDebug] hit", { - bombId: payload.bombId, - distanceSquared: result.distanceSquared, - thresholdSquared: result.thresholdSquared, - bombTeamId: payload.teamId, - playerTeamId: localPlayer.teamId, - }); } /** 判定済み状態を初期化する */ diff --git a/apps/client/src/scenes/game/application/GameLoop.ts b/apps/client/src/scenes/game/application/GameLoop.ts index d4976ef..723411a 100644 --- a/apps/client/src/scenes/game/application/GameLoop.ts +++ b/apps/client/src/scenes/game/application/GameLoop.ts @@ -5,10 +5,12 @@ */ import { Application, Container, Ticker } from "pixi.js"; import { LocalPlayerController } from "@client/scenes/game/entities/player/PlayerController"; +import { BombManager } from "@client/scenes/game/entities/bomb/BombManager"; import type { GamePlayers } from "./game.types"; import { InputStep } from "./loopSteps/InputStep"; import { SimulationStep } from "./loopSteps/SimulationStep"; import { CameraStep } from "./loopSteps/CameraStep"; +import { BombStep } from "./loopSteps/BombStep"; type GameLoopOptions = { app: Application; @@ -16,6 +18,7 @@ players: GamePlayers; myId: string; getJoystickInput: () => { x: number; y: number }; + bombManager: BombManager; }; /** ゲームのフレーム更新順序を管理するループ制御クラス */ @@ -26,15 +29,17 @@ private myId: string; private inputStep: InputStep; private simulationStep: SimulationStep; + private bombStep: BombStep; private cameraStep: CameraStep; - constructor({ app, worldContainer, players, myId, getJoystickInput }: GameLoopOptions) { + constructor({ app, worldContainer, players, myId, getJoystickInput, bombManager }: GameLoopOptions) { this.app = app; this.worldContainer = worldContainer; this.players = players; this.myId = myId; this.inputStep = new InputStep({ getJoystickInput }); this.simulationStep = new SimulationStep(); + this.bombStep = new BombStep({ bombManager }); this.cameraStep = new CameraStep(); } @@ -52,6 +57,8 @@ isMoving, }); + this.bombStep.run(); + this.cameraStep.run({ app: this.app, worldContainer: this.worldContainer, diff --git a/apps/client/src/scenes/game/application/loopSteps/BombStep.ts b/apps/client/src/scenes/game/application/loopSteps/BombStep.ts new file mode 100644 index 0000000..326c39d --- /dev/null +++ b/apps/client/src/scenes/game/application/loopSteps/BombStep.ts @@ -0,0 +1,25 @@ +/** + * BombStep + * ゲームループの爆弾更新段を担う + * 爆弾エンティティの時間更新と状態遷移を実行する + */ +import { BombManager } from "@client/scenes/game/entities/bomb/BombManager"; + +/** BombStep の初期化入力 */ +type BombStepOptions = { + bombManager: BombManager; +}; + +/** 爆弾更新処理を担うステップ */ +export class BombStep { + private bombManager: BombManager; + + constructor({ bombManager }: BombStepOptions) { + this.bombManager = bombManager; + } + + /** 爆弾更新を実行する */ + public run(): void { + this.bombManager.tick(); + } +} diff --git a/apps/client/src/scenes/game/entities/bomb/BombView.ts b/apps/client/src/scenes/game/entities/bomb/BombView.ts index 12fe1c4..7c8dba1 100644 --- a/apps/client/src/scenes/game/entities/bomb/BombView.ts +++ b/apps/client/src/scenes/game/entities/bomb/BombView.ts @@ -8,8 +8,6 @@ import { config } from "@client/config"; import type { BombState } from "./BombModel"; -const ENABLE_DEBUG_LOG = import.meta.env.DEV; - /** 爆弾の描画表現を管理するビュー */ export class BombView { public readonly displayObject: Container; @@ -21,6 +19,7 @@ private lastRenderedRadiusGrid: number | null = null; private lastRenderedColor: number | null = null; private isBombTextureReady = false; + private isDestroyed = false; constructor() { this.displayObject = new Container(); @@ -44,13 +43,17 @@ try { const texture = await Assets.load(imageUrl); + if (this.isDestroyed || this.bombSprite.destroyed) { + return; + } + this.bombSprite.texture = texture; this.isBombTextureReady = true; - - if (ENABLE_DEBUG_LOG) { - console.log(`[BombView] Bomb.svg 読み込み成功: ${imageUrl}`); - } } catch (error) { + if (this.isDestroyed) { + return; + } + this.isBombTextureReady = false; console.error(`[BombView] Bomb.svg 読み込み失敗: ${imageUrl}`, error); } @@ -112,6 +115,7 @@ } public destroy(): void { + this.isDestroyed = true; this.displayObject.destroy({ children: true }); } }