diff --git a/apps/client/src/scenes/game/input/GameInputOverlay.tsx b/apps/client/src/scenes/game/input/GameInputOverlay.tsx index e8e2db8..c3e9c26 100644 --- a/apps/client/src/scenes/game/input/GameInputOverlay.tsx +++ b/apps/client/src/scenes/game/input/GameInputOverlay.tsx @@ -5,8 +5,8 @@ */ import { config } from "@client/config"; import { JoystickInputPresenter } from "./joystick/presentation/JoystickInputPresenter"; -import { BombButton } from "./bomb/BombButton"; -import { useCooldownClock } from "./hooks/useCooldownClock"; +import { BombButton } from "./bomb/presentation/BombButton"; +import { useBombCooldownClock } from "./bomb/hooks/useBombCooldownClock"; /** 入力UIレイヤーの入力プロパティ */ type GameInputOverlayProps = { @@ -29,7 +29,7 @@ onPlaceBomb, }: GameInputOverlayProps) => { const bombCooldownMs = config.GAME_CONFIG.BOMB_COOLDOWN_MS; - const { cooldownState, markTriggered } = useCooldownClock(bombCooldownMs); + const { cooldownState, markTriggered } = useBombCooldownClock(bombCooldownMs); const handlePressBomb = () => { if (!isInputEnabled || !cooldownState.isReady) { diff --git a/apps/client/src/scenes/game/input/bomb/BombButton.tsx b/apps/client/src/scenes/game/input/bomb/BombButton.tsx index 9117a8c..9ba5abe 100644 --- a/apps/client/src/scenes/game/input/bomb/BombButton.tsx +++ b/apps/client/src/scenes/game/input/bomb/BombButton.tsx @@ -1,129 +1,11 @@ /** * BombButton - * 爆弾設置ボタンの見た目とクリック入力を担う - * 画面右下固定の操作ボタンを提供する + * presentation配下のBombButtonを段階移行のため再公開する + * 既存import互換を維持して段階的な参照置換を可能にする */ -/** 爆弾設置ボタンの入力プロパティ */ -type BombButtonProps = { - onPress: () => void; - cooldownProgress: number; - isReady: boolean; - remainingSecText: string | null; -}; +/** presentation配下の型を互換再エクスポートする */ +export type { BombButtonProps } from "./presentation/BombButton"; -const BOMB_BUTTON_FRAME_STYLE: React.CSSProperties = { - width: "108px", - height: "108px", - borderRadius: "50%", - display: "flex", - alignItems: "center", - justifyContent: "center", - pointerEvents: "none", -}; - -const BOMB_BUTTON_HIT_AREA_STYLE: React.CSSProperties = { - position: "fixed", - right: "24px", - bottom: "28px", - width: "120px", - height: "120px", - borderRadius: "50%", - display: "flex", - alignItems: "center", - justifyContent: "center", - zIndex: 9999, - touchAction: "manipulation", -}; - -const BOMB_BUTTON_STYLE: React.CSSProperties = { - width: "96px", - height: "96px", - borderRadius: "50%", - border: "2px solid rgba(255,255,255,0.75)", - background: "rgba(220, 60, 60, 0.85)", - color: "white", - fontSize: "18px", - fontWeight: "bold", - pointerEvents: "auto", - touchAction: "manipulation", - display: "flex", - alignItems: "center", - justifyContent: "center", -}; - -/** 画面右下の爆弾設置ボタンを描画する */ -export const BombButton = ({ - onPress, - cooldownProgress, - isReady, - remainingSecText, -}: BombButtonProps) => { - const progressDeg = Math.max(0, Math.min(1, cooldownProgress)) * 360; - const frameStyle: React.CSSProperties = { - ...BOMB_BUTTON_FRAME_STYLE, - background: `conic-gradient(rgba(255,255,255,0.95) ${progressDeg}deg, rgba(255,255,255,0.2) ${progressDeg}deg 360deg)`, - }; - - const buttonStyle: React.CSSProperties = { - ...BOMB_BUTTON_STYLE, - background: isReady ? "rgba(220, 60, 60, 0.85)" : "rgba(110, 40, 40, 0.85)", - opacity: isReady ? 1 : 0.88, - cursor: isReady ? "pointer" : "not-allowed", - }; - - const hitAreaStyle: React.CSSProperties = { - ...BOMB_BUTTON_HIT_AREA_STYLE, - cursor: isReady ? "pointer" : "not-allowed", - }; - - const handleActivate = () => { - if (!isReady) { - return; - } - - onPress(); - }; - - const handlePointerDown = (event: React.PointerEvent) => { - event.preventDefault(); - handleActivate(); - }; - - const handleTouchStart = (event: React.TouchEvent) => { - event.preventDefault(); - handleActivate(); - }; - - const handleMouseDown = (event: React.MouseEvent) => { - event.preventDefault(); - handleActivate(); - }; - - return ( -
-
- -
-
- ); -}; +/** presentation配下のコンポーネントを互換再エクスポートする */ +export { BombButton } from "./presentation/BombButton"; diff --git a/apps/client/src/scenes/game/input/bomb/hooks/useBombCooldownClock.ts b/apps/client/src/scenes/game/input/bomb/hooks/useBombCooldownClock.ts new file mode 100644 index 0000000..08218a6 --- /dev/null +++ b/apps/client/src/scenes/game/input/bomb/hooks/useBombCooldownClock.ts @@ -0,0 +1,17 @@ +/** + * useBombCooldownClock + * 爆弾ボタン専用のクールダウン状態を提供する + * 汎用クールダウンフックを利用して爆弾入力の責務を明確化する + */ +import { + useCooldownClock, + type UseCooldownClockOptions, +} from "@client/scenes/game/input/hooks/useCooldownClock"; + +/** 爆弾クールダウン状態を取得するフック */ +export const useBombCooldownClock = ( + cooldownMs: number, + options?: UseCooldownClockOptions, +) => { + return useCooldownClock(cooldownMs, options); +}; diff --git a/apps/client/src/scenes/game/input/bomb/presentation/BombButton.tsx b/apps/client/src/scenes/game/input/bomb/presentation/BombButton.tsx new file mode 100644 index 0000000..26725d0 --- /dev/null +++ b/apps/client/src/scenes/game/input/bomb/presentation/BombButton.tsx @@ -0,0 +1,129 @@ +/** + * BombButton + * 爆弾設置ボタンの見た目とクリック入力を担う + * 画面右下固定の操作ボタンを提供する + */ + +/** 爆弾設置ボタンの入力プロパティ */ +export type BombButtonProps = { + onPress: () => void; + cooldownProgress: number; + isReady: boolean; + remainingSecText: string | null; +}; + +const BOMB_BUTTON_FRAME_STYLE: React.CSSProperties = { + width: "108px", + height: "108px", + borderRadius: "50%", + display: "flex", + alignItems: "center", + justifyContent: "center", + pointerEvents: "none", +}; + +const BOMB_BUTTON_HIT_AREA_STYLE: React.CSSProperties = { + position: "fixed", + right: "24px", + bottom: "28px", + width: "120px", + height: "120px", + borderRadius: "50%", + display: "flex", + alignItems: "center", + justifyContent: "center", + zIndex: 9999, + touchAction: "manipulation", +}; + +const BOMB_BUTTON_STYLE: React.CSSProperties = { + width: "96px", + height: "96px", + borderRadius: "50%", + border: "2px solid rgba(255,255,255,0.75)", + background: "rgba(220, 60, 60, 0.85)", + color: "white", + fontSize: "18px", + fontWeight: "bold", + pointerEvents: "auto", + touchAction: "manipulation", + display: "flex", + alignItems: "center", + justifyContent: "center", +}; + +/** 画面右下の爆弾設置ボタンを描画する */ +export const BombButton = ({ + onPress, + cooldownProgress, + isReady, + remainingSecText, +}: BombButtonProps) => { + const progressDeg = Math.max(0, Math.min(1, cooldownProgress)) * 360; + const frameStyle: React.CSSProperties = { + ...BOMB_BUTTON_FRAME_STYLE, + background: `conic-gradient(rgba(255,255,255,0.95) ${progressDeg}deg, rgba(255,255,255,0.2) ${progressDeg}deg 360deg)`, + }; + + const buttonStyle: React.CSSProperties = { + ...BOMB_BUTTON_STYLE, + background: isReady ? "rgba(220, 60, 60, 0.85)" : "rgba(110, 40, 40, 0.85)", + opacity: isReady ? 1 : 0.88, + cursor: isReady ? "pointer" : "not-allowed", + }; + + const hitAreaStyle: React.CSSProperties = { + ...BOMB_BUTTON_HIT_AREA_STYLE, + cursor: isReady ? "pointer" : "not-allowed", + }; + + const handleActivate = () => { + if (!isReady) { + return; + } + + onPress(); + }; + + const handlePointerDown = (event: React.PointerEvent) => { + event.preventDefault(); + handleActivate(); + }; + + const handleTouchStart = (event: React.TouchEvent) => { + event.preventDefault(); + handleActivate(); + }; + + const handleMouseDown = (event: React.MouseEvent) => { + event.preventDefault(); + handleActivate(); + }; + + return ( +
+
+ +
+
+ ); +};