Newer
Older
PixelPaintWar / apps / client / src / scenes / game / application / combat / CombatLifecycleFacade.ts
/**
 * CombatLifecycleFacade
 * 被弾判定から硬直,演出,報告送信までの戦闘ライフサイクルを管理する
 * ゲームマネージャーから被弾関連の責務を分離する
 */
import { config } from "@client/config";
import type { PlayerDeadPayload } from "@repo/shared";
import type { BombExplodedPayload } from "@client/scenes/game/entities/bomb/BombManager";
import { BombHitOrchestrator } from "@client/scenes/game/application/BombHitOrchestrator";
import { PlayerDeathPolicy } from "@client/scenes/game/application/PlayerDeathPolicy";
import { PlayerHitEffectOrchestrator } from "@client/scenes/game/application/PlayerHitEffectOrchestrator";
import type { GamePlayers } from "@client/scenes/game/application/game.types";

/** CombatLifecycleFacade の初期化入力 */
export type CombatLifecycleFacadeOptions = {
  players: GamePlayers;
  myId: string;
  acquireInputLock: () => () => void;
  onSendBombHitReport: (bombId: string) => void;
};

/** 被弾関連ライフサイクルの制御を担当する */
export class CombatLifecycleFacade {
  private readonly myId: string;
  private readonly onSendBombHitReport: (
    bombId: string,
  ) => void;
  private readonly bombHitOrchestrator: BombHitOrchestrator;
  private readonly playerDeathPolicy: PlayerDeathPolicy;
  private readonly playerHitEffectOrchestrator: PlayerHitEffectOrchestrator;

  constructor({
    players,
    myId,
    acquireInputLock,
    onSendBombHitReport,
  }: CombatLifecycleFacadeOptions) {
    this.myId = myId;
    this.onSendBombHitReport = onSendBombHitReport;
    this.bombHitOrchestrator = new BombHitOrchestrator({
      players,
      myId,
    });
    this.playerDeathPolicy = new PlayerDeathPolicy({
      myId,
      hitStunMs: config.GAME_CONFIG.PLAYER_HIT_STUN_MS,
      acquireInputLock,
    });
    this.playerHitEffectOrchestrator = new PlayerHitEffectOrchestrator({
      players,
      blinkDurationMs: config.GAME_CONFIG.PLAYER_HIT_EFFECT.BLINK_DURATION_MS,
      dedupWindowMs: config.GAME_CONFIG.PLAYER_HIT_EFFECT.DEDUP_WINDOW_MS,
    });
  }

  /** 爆弾爆発時の判定と後続処理を実行する */
  public handleBombExploded(payload: BombExplodedPayload): void {
    const hitPlayerId = this.bombHitOrchestrator.evaluateHit(payload);
    if (!hitPlayerId) return;

    this.playerDeathPolicy.applyLocalHitStun();
    this.playerHitEffectOrchestrator.handleLocalBombHit(this.myId);
    this.onSendBombHitReport(payload.bombId);
  }

  /** ネットワーク被弾通知を適用する */
  public handleNetworkPlayerDead(payload: PlayerDeadPayload): void {
    this.playerDeathPolicy.applyPlayerDeadEvent(payload);
    this.playerHitEffectOrchestrator.handleNetworkPlayerDead(payload.playerId, this.myId);
  }

  /** 管理中リソースを破棄する */
  public dispose(): void {
    this.bombHitOrchestrator.clear();
    this.playerDeathPolicy.dispose();
  }
}