diff --git a/apps/client/src/app.tsx b/apps/client/src/app.tsx index da5687c..63f5e75 100644 --- a/apps/client/src/app.tsx +++ b/apps/client/src/app.tsx @@ -45,8 +45,8 @@ - socketManager.lobby.startGame(targetPlayerCount) + onStart={(payload) => + socketManager.lobby.startGame(payload) } onBackToTitle={() => returnToTitle({ leaveRoom: true })} /> diff --git a/apps/client/src/network/handlers/LobbyHandler.ts b/apps/client/src/network/handlers/LobbyHandler.ts index 1b1d70e..00c037b 100644 --- a/apps/client/src/network/handlers/LobbyHandler.ts +++ b/apps/client/src/network/handlers/LobbyHandler.ts @@ -5,7 +5,7 @@ */ import type { Socket } from "socket.io-client"; import { contracts as protocol } from "@repo/shared"; -import type { ServerToClientPayloadOf } from "@repo/shared"; +import type { ServerToClientPayloadOf, StartGameRequestPayload } from "@repo/shared"; import { createClientSocketEventBridge } from "./socketEventBridge"; /** ロビー画面で利用する通信操作の契約 */ @@ -25,7 +25,7 @@ room: ServerToClientPayloadOf, ) => void, ) => void; - startGame: (targetPlayerCount?: number) => void; + startGame: (payload?: StartGameRequestPayload) => void; }; /** ロビー画面向けのソケットハンドラを生成する */ @@ -43,10 +43,8 @@ offRoomUpdate: (callback) => { offEvent(protocol.SocketEvents.ROOM_UPDATE, callback); }, - startGame: (targetPlayerCount) => { - emitEvent(protocol.SocketEvents.START_GAME, { - targetPlayerCount, - }); + startGame: (payload) => { + emitEvent(protocol.SocketEvents.START_GAME, payload ?? {}); }, }; }; diff --git a/apps/client/src/scenes/lobby/LobbyScene.tsx b/apps/client/src/scenes/lobby/LobbyScene.tsx index af8cc78..ae26629 100644 --- a/apps/client/src/scenes/lobby/LobbyScene.tsx +++ b/apps/client/src/scenes/lobby/LobbyScene.tsx @@ -1,12 +1,14 @@ import { useEffect, useMemo, useState } from "react"; import { domain } from "@repo/shared"; +import type { FieldSizePreset, StartGameRequestPayload } from "@repo/shared"; +import { config } from "@client/config"; import { OVERLAY_BUTTON_STYLE } from "@client/scenes/shared/styles/overlayStyles"; import { LobbyRuleModal } from "./components/LobbyRuleModal"; type Props = { room: domain.room.Room | null; myId: string | null; - onStart: (targetPlayerCount: number) => void; + onStart: (payload: StartGameRequestPayload) => void; onBackToTitle: () => void; }; @@ -46,6 +48,13 @@ const [selectedStartPlayerCount, setSelectedStartPlayerCount] = useState( minimumStartPlayerCount, ); + const fieldPresetOptions = useMemo(() => { + return Object.keys( + config.GAME_CONFIG.FIELD_PRESETS, + ) as FieldSizePreset[]; + }, []); + const [selectedFieldSizePreset, setSelectedFieldSizePreset] = + useState(config.GAME_CONFIG.DEFAULT_FIELD_PRESET); const [isRuleModalOpen, setIsRuleModalOpen] = useState(false); useEffect(() => { @@ -63,7 +72,24 @@ }, [minimumStartPlayerCount, maxStartPlayerCount]); const handleStart = () => { - onStart(selectedStartPlayerCount); + onStart({ + targetPlayerCount: selectedStartPlayerCount, + fieldSizePreset: selectedFieldSizePreset, + }); + }; + + const toFieldPresetLabel = (preset: FieldSizePreset): string => { + const range = config.GAME_CONFIG.FIELD_PRESETS[preset].recommendedPlayers; + const baseLabel = + preset === "SMALL" + ? "小" + : preset === "MEDIUM" + ? "中" + : preset === "LARGE" + ? "大" + : "極大"; + + return `${baseLabel} (${range.min}-${range.max}人目安)`; }; return ( @@ -226,6 +252,40 @@ ))} + + +