diff --git a/apps/client/src/app.tsx b/apps/client/src/app.tsx index 4608c72..e87e372 100644 --- a/apps/client/src/app.tsx +++ b/apps/client/src/app.tsx @@ -6,13 +6,13 @@ import { LobbyScene } from "./scenes/LobbyScene"; import { GameScene } from "./scenes/GameScene"; -import { GameState, type Room } from "@repo/shared"; +import { roomTypes } from "@repo/shared"; export default function App() { // 現在シーン状態 - const [gameState, setGameState] = useState(GameState.TITLE); + const [gameState, setGameState] = useState(roomTypes.GameState.TITLE); // 参加中ルーム情報 - const [room, setRoom] = useState(null); + const [room, setRoom] = useState(null); // 自身ソケットID const [myId, setMyId] = useState(null); @@ -21,18 +21,18 @@ socketClient.onConnect((id) => setMyId(id)); socketClient.onRoomUpdate((updatedRoom) => { setRoom(updatedRoom); - setGameState(GameState.LOBBY); + setGameState(roomTypes.GameState.LOBBY); }); - socketClient.onGameStart(() => setGameState(GameState.PLAYING)); + socketClient.onGameStart(() => setGameState(roomTypes.GameState.PLAYING)); }, []); // タイトル画面分岐 - if (gameState === GameState.TITLE) { + if (gameState === roomTypes.GameState.TITLE) { return socketClient.joinRoom(payload.roomId, payload.playerName)} />; } // ロビー画面分岐 - if (gameState === GameState.LOBBY) { + if (gameState === roomTypes.GameState.LOBBY) { return socketClient.startGame()} />; } diff --git a/apps/client/src/entities/GameMap.ts b/apps/client/src/entities/GameMap.ts index 7dd272f..d464910 100644 --- a/apps/client/src/entities/GameMap.ts +++ b/apps/client/src/entities/GameMap.ts @@ -1,7 +1,7 @@ // apps/client/src/game/map/GameMap.ts (パスは適宜読み替えてください) import { Container, Graphics } from "pixi.js"; -import { GAME_CONFIG } from "@repo/shared"; -import type { MapState, CellUpdate } from "@repo/shared"; +import { config } from "@repo/shared"; +import type { gridMapTypes } from "@repo/shared"; // 親クラスを Graphics から Container に変更し、レイヤー管理を可能にする export class GameMap extends Container { @@ -30,7 +30,7 @@ // 設定値に基づき、空のマス目(Graphics)を400個生成して配列に格納する private initCells() { - const { GRID_COLS, GRID_ROWS, GRID_CELL_SIZE } = GAME_CONFIG; + const { GRID_COLS, GRID_ROWS, GRID_CELL_SIZE } = config.GAME_CONFIG; const totalCells = GRID_COLS * GRID_ROWS; for (let i = 0; i < totalCells; i++) { @@ -52,7 +52,7 @@ const { MAP_WIDTH, MAP_HEIGHT, GRID_CELL_SIZE, MAP_BG_COLOR, MAP_GRID_COLOR, MAP_BORDER_COLOR - } = GAME_CONFIG; + } = config.GAME_CONFIG; // マップ全域背景レイヤー this.bgGraphics.rect(0, 0, MAP_WIDTH, MAP_HEIGHT).fill(MAP_BG_COLOR); @@ -73,8 +73,8 @@ /** * サーバー(またはテストロジック)から受け取った最新のマップ状態で色を更新する */ - public updateMapState(state: MapState) { - const { GRID_CELL_SIZE, TEAM_COLORS } = GAME_CONFIG; + public updateMapState(state: gridMapTypes.MapState) { + const { GRID_CELL_SIZE, TEAM_COLORS } = config.GAME_CONFIG; for (let i = 0; i < state.gridColors.length; i++) { const teamId = state.gridColors[i]; @@ -98,8 +98,8 @@ /** * 差分データを受け取って指定のマスだけ色を更新する */ - public updateCells(updates: CellUpdate[]) { - const { GRID_CELL_SIZE, TEAM_COLORS } = GAME_CONFIG; + public updateCells(updates: gridMapTypes.CellUpdate[]) { + const { GRID_CELL_SIZE, TEAM_COLORS } = config.GAME_CONFIG; updates.forEach(({ index, teamId }) => { const cell = this.cells[index]; diff --git a/apps/client/src/entities/Player.ts b/apps/client/src/entities/Player.ts index c16cef1..60465fe 100644 --- a/apps/client/src/entities/Player.ts +++ b/apps/client/src/entities/Player.ts @@ -1,6 +1,6 @@ import { Graphics } from 'pixi.js'; -import { GAME_CONFIG } from "@repo/shared"; -import type { PlayerData } from "@repo/shared"; +import { config } from "@repo/shared"; +import type { playerTypes } from "@repo/shared"; /** * プレイヤーの共通基底クラス(描画と基本データの保持) @@ -9,7 +9,7 @@ public id: string; public teamId: number; - constructor(data: PlayerData, isLocal: boolean = false) { + constructor(data: playerTypes.PlayerData, isLocal: boolean = false) { super(); this.id = data.id; this.teamId = data.teamId; @@ -25,7 +25,7 @@ PLAYER_LOCAL_STROKE_WIDTH, PLAYER_REMOTE_STROKE_COLOR, PLAYER_REMOTE_STROKE_WIDTH - } = GAME_CONFIG; + } = config.GAME_CONFIG; // チームIDに対応する色をHEX文字列('#RRGGBB')で取得し、PixiJS用の数値(0xRRGGBB)に変換 const colorString = TEAM_COLORS[this.teamId] || '#FFFFFF'; @@ -49,7 +49,7 @@ * 自プレイヤー(キー・ジョイスティック入力で移動・送信する) */ export class LocalPlayer extends BasePlayer { - constructor(data: PlayerData) { + constructor(data: playerTypes.PlayerData) { super(data, true); } @@ -57,7 +57,7 @@ * 入力ベクトルと経過時間基準の座標更新処理 */ public move(vx: number, vy: number, deltaTime: number) { - const { PLAYER_SPEED, MAP_WIDTH, MAP_HEIGHT, PLAYER_RADIUS } = GAME_CONFIG; + const { PLAYER_SPEED, MAP_WIDTH, MAP_HEIGHT, PLAYER_RADIUS } = config.GAME_CONFIG; const speed = PLAYER_SPEED * deltaTime; this.x += vx * speed; @@ -80,7 +80,7 @@ private targetX: number; private targetY: number; - constructor(data: PlayerData) { + constructor(data: playerTypes.PlayerData) { super(data, false); this.targetX = data.x; this.targetY = data.y; @@ -98,7 +98,7 @@ * 毎フレームの更新処理(目標座標へのLerp補間) */ public update(deltaTime: number): void { - const { PLAYER_LERP_SNAP_THRESHOLD, PLAYER_LERP_SMOOTHNESS } = GAME_CONFIG; + const { PLAYER_LERP_SNAP_THRESHOLD, PLAYER_LERP_SMOOTHNESS } = config.GAME_CONFIG; const diffX = this.targetX - this.x; const diffY = this.targetY - this.y; diff --git a/apps/client/src/managers/GameManager.ts b/apps/client/src/managers/GameManager.ts index c1cb4dd..e6024e4 100644 --- a/apps/client/src/managers/GameManager.ts +++ b/apps/client/src/managers/GameManager.ts @@ -1,7 +1,7 @@ import { Application, Container, Ticker } from "pixi.js"; import { socketClient } from "../network/SocketClient"; -import { GAME_CONFIG } from "@repo/shared"; -import type { PlayerData } from "@repo/shared"; +import { config } from "@repo/shared"; +import type { playerTypes } from "@repo/shared"; import { BasePlayer, LocalPlayer, RemotePlayer } from "../entities/Player"; import { GameMap } from "../entities/GameMap"; import { MAX_DIST } from "../input/VirtualJoystick"; @@ -22,11 +22,11 @@ // 現在の残り秒数を取得する public getRemainingTime(): number { - if (!this.gameStartTime) return GAME_CONFIG.GAME_DURATION_SEC; + if (!this.gameStartTime) return config.GAME_CONFIG.GAME_DURATION_SEC; // 現在のサーバー時刻を推定 (Date.now() + サーバーとの誤差補正が理想ですが、まずは簡易版で) const elapsedMs = Date.now() - this.gameStartTime; - const remainingSec = GAME_CONFIG.GAME_DURATION_SEC - (elapsedMs / 1000); + const remainingSec = config.GAME_CONFIG.GAME_DURATION_SEC - (elapsedMs / 1000); return Math.max(0, remainingSec); } @@ -88,8 +88,8 @@ * ソケットイベントの登録 */ private setupSocketListeners() { - socketClient.onCurrentPlayers((serverPlayers: PlayerData[] | Record) => { - const playersArray = (Array.isArray(serverPlayers) ? serverPlayers : Object.values(serverPlayers)) as PlayerData[]; + socketClient.onCurrentPlayers((serverPlayers: playerTypes.PlayerData[] | Record) => { + const playersArray = (Array.isArray(serverPlayers) ? serverPlayers : Object.values(serverPlayers)) as playerTypes.PlayerData[]; playersArray.forEach((p) => { const playerSprite = p.id === this.myId ? new LocalPlayer(p) : new RemotePlayer(p); this.worldContainer.addChild(playerSprite); @@ -97,7 +97,7 @@ }); }); - socketClient.onNewPlayer((p: PlayerData) => { + socketClient.onNewPlayer((p: playerTypes.PlayerData) => { const playerSprite = new RemotePlayer(p); this.worldContainer.addChild(playerSprite); this.players[p.id] = playerSprite; @@ -111,7 +111,7 @@ } }); - socketClient.onUpdatePlayer((data: Partial & { id: string }) => { + socketClient.onUpdatePlayer((data: Partial & { id: string }) => { if (data.id === this.myId) return; const target = this.players[data.id]; if (target && target instanceof RemotePlayer) { @@ -148,7 +148,7 @@ me.move(dx / MAX_DIST, dy / MAX_DIST, ticker.deltaTime); const now = performance.now(); - if (now - this.lastPositionSentTime >= GAME_CONFIG.PLAYER_POSITION_UPDATE_MS) { + if (now - this.lastPositionSentTime >= config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS) { socketClient.sendMove(me.x, me.y); this.lastPositionSentTime = now; } diff --git a/apps/client/src/network/SocketClient.ts b/apps/client/src/network/SocketClient.ts index a87374f..e5dd3ae 100644 --- a/apps/client/src/network/SocketClient.ts +++ b/apps/client/src/network/SocketClient.ts @@ -1,8 +1,6 @@ import { io, Socket } from "socket.io-client"; -import { SocketEvents } from "@repo/shared"; -import type { MovePayload, PlayerData } from "@repo/shared"; -import type { CellUpdate } from "@repo/shared"; -import type { Room, JoinRoomPayload } from "@repo/shared"; +import { protocol } from "@repo/shared"; +import type { playerTypes, gridMapTypes, roomTypes } from "@repo/shared"; /** * サーバー WebSocket 通信管理クラス @@ -13,7 +11,7 @@ constructor() { // サーバー(バックエンド)のURLを直接指定する // 本番環境(Render)のURLを指定することで、プロキシなしで直接通信させます - const SERVER_URL = "https://skillsemiwebgame.onrender.com"; + const SERVER_URL = "localhost:3000"; // 開発環境用URL this.socket = io(SERVER_URL, { transports: ["websocket", "polling"], // 接続の安定性を高める @@ -32,7 +30,7 @@ } // 初回接続・再接続イベント購読 - this.socket.on(SocketEvents.CONNECT, () => { + this.socket.on(protocol.SocketEvents.CONNECT, () => { callback(this.socket.id || ""); }); } @@ -40,29 +38,29 @@ /** * 初期プレイヤー一覧受信イベント購読 */ - onCurrentPlayers(callback: (players: PlayerData[] | Record) => void) { - this.socket.on(SocketEvents.CURRENT_PLAYERS, callback); + onCurrentPlayers(callback: (players: playerTypes.PlayerData[] | Record) => void) { + this.socket.on(protocol.SocketEvents.CURRENT_PLAYERS, callback); } /** * 新規プレイヤー参加イベント購読 */ - onNewPlayer(callback: (player: PlayerData) => void) { - this.socket.on(SocketEvents.NEW_PLAYER, callback); + onNewPlayer(callback: (player: playerTypes.PlayerData) => void) { + this.socket.on(protocol.SocketEvents.NEW_PLAYER, callback); } /** * 他プレイヤー状態更新イベント購読 */ - onUpdatePlayer(callback: (data: Partial & { id: string }) => void) { - this.socket.on(SocketEvents.UPDATE_PLAYER, callback); + onUpdatePlayer(callback: (data: Partial & { id: string }) => void) { + this.socket.on(protocol.SocketEvents.UPDATE_PLAYER, callback); } /** * プレイヤー退出イベント購読 */ onRemovePlayer(callback: (id: string) => void) { - this.socket.on(SocketEvents.REMOVE_PLAYER, callback); + this.socket.on(protocol.SocketEvents.REMOVE_PLAYER, callback); } /** @@ -71,15 +69,15 @@ * @param y 現在のY座標 */ sendMove(x: number, y: number) { - const payload: MovePayload = { x, y }; - this.socket.emit(SocketEvents.MOVE, payload); + const payload: playerTypes.MovePayload = { x, y }; + this.socket.emit(protocol.SocketEvents.MOVE, payload); } /** * マス目の差分更新イベント購読 */ - onUpdateMapCells(callback: (updates: CellUpdate[]) => void) { - this.socket.on(SocketEvents.UPDATE_MAP_CELLS, callback); + onUpdateMapCells(callback: (updates: gridMapTypes.CellUpdate[]) => void) { + this.socket.on(protocol.SocketEvents.UPDATE_MAP_CELLS, callback); } /** @@ -88,47 +86,47 @@ * @param playerName 表示名 */ joinRoom(roomId: string, playerName: string) { - const payload: JoinRoomPayload = { roomId, playerName }; - this.socket.emit(SocketEvents.JOIN_ROOM, payload); + const payload: roomTypes.JoinRoomPayload = { roomId, playerName }; + this.socket.emit(protocol.SocketEvents.JOIN_ROOM, payload); } /** * ルーム情報更新イベント購読 */ - onRoomUpdate(callback: (room: Room) => void) { - this.socket.on(SocketEvents.ROOM_UPDATE, callback); + onRoomUpdate(callback: (room: roomTypes.Room) => void) { + this.socket.on(protocol.SocketEvents.ROOM_UPDATE, callback); } /** * ゲーム開始通知イベント購読 */ onGameStart(callback: (data: { startTime: number }) => void) { - this.socket.on(SocketEvents.GAME_START, callback); + this.socket.on(protocol.SocketEvents.GAME_START, callback); } /** * ゲーム開始リクエスト送信 */ startGame() { - this.socket.emit(SocketEvents.START_GAME); + this.socket.emit(protocol.SocketEvents.START_GAME); } /** * ゲーム画面準備完了通知 */ readyForGame() { - this.socket.emit(SocketEvents.READY_FOR_GAME); + this.socket.emit(protocol.SocketEvents.READY_FOR_GAME); } /** * 全てのゲームプレイ関連イベントを解除(一括解除用) */ removeAllListeners() { - this.socket.off(SocketEvents.CURRENT_PLAYERS); - this.socket.off(SocketEvents.NEW_PLAYER); - this.socket.off(SocketEvents.UPDATE_PLAYER); - this.socket.off(SocketEvents.REMOVE_PLAYER); - this.socket.off(SocketEvents.UPDATE_MAP_CELLS); + this.socket.off(protocol.SocketEvents.CURRENT_PLAYERS); + this.socket.off(protocol.SocketEvents.NEW_PLAYER); + this.socket.off(protocol.SocketEvents.UPDATE_PLAYER); + this.socket.off(protocol.SocketEvents.REMOVE_PLAYER); + this.socket.off(protocol.SocketEvents.UPDATE_MAP_CELLS); } } diff --git a/apps/client/src/scenes/GameScene.tsx b/apps/client/src/scenes/GameScene.tsx index 31963a8..c4bca7f 100644 --- a/apps/client/src/scenes/GameScene.tsx +++ b/apps/client/src/scenes/GameScene.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { VirtualJoystick } from "../input/VirtualJoystick"; import { GameManager } from "../managers/GameManager"; -import { GAME_CONFIG } from "@repo/shared"; +import { config } from "@repo/shared"; interface GameSceneProps { myId: string | null; @@ -17,7 +17,7 @@ // gameConfig から初期表示時間文字列を生成する関数 const getInitialTimeDisplay = () => { - const totalSec = GAME_CONFIG.GAME_DURATION_SEC; + const totalSec = config.GAME_CONFIG.GAME_DURATION_SEC; const mins = Math.floor(totalSec / 60); const secs = Math.floor(totalSec % 60); return `${mins}:${secs.toString().padStart(2, '0')}`; diff --git a/apps/client/src/scenes/LobbyScene.tsx b/apps/client/src/scenes/LobbyScene.tsx index ab55c22..6653788 100644 --- a/apps/client/src/scenes/LobbyScene.tsx +++ b/apps/client/src/scenes/LobbyScene.tsx @@ -1,7 +1,7 @@ -import type { Room, RoomMember } from "@repo/shared"; +import type { roomTypes } from "@repo/shared"; type Props = { - room: Room | null; + room: roomTypes.Room | null; myId: string | null; onStart: () => void; }; @@ -24,7 +24,7 @@
    {/* 参加プレイヤー一覧描画 */} - {room.players.map((p: RoomMember) => ( + {room.players.map((p: roomTypes.RoomMember) => (
  • {p.id === myId ? "🟢" : "⚪"} {p.name} diff --git a/apps/client/src/scenes/TitleScene.tsx b/apps/client/src/scenes/TitleScene.tsx index c042d22..d475c08 100644 --- a/apps/client/src/scenes/TitleScene.tsx +++ b/apps/client/src/scenes/TitleScene.tsx @@ -1,10 +1,10 @@ import { useState } from "react"; // ルーム参加時送信ペイロード型 -import type { JoinRoomPayload } from "@repo/shared"; +import type { roomTypes } from "@repo/shared"; type Props = { // 入室実行時呼び出しコールバック - onJoin: (payload: JoinRoomPayload) => void; + onJoin: (payload: roomTypes.JoinRoomPayload) => void; }; export const TitleScene = ({ onJoin }: Props) => { diff --git a/apps/server/src/domains/game/GameHandler.ts b/apps/server/src/domains/game/GameHandler.ts index 9bcbec0..df6fa26 100644 --- a/apps/server/src/domains/game/GameHandler.ts +++ b/apps/server/src/domains/game/GameHandler.ts @@ -1,23 +1,22 @@ import { Server, Socket } from "socket.io"; import { GameManager } from "./GameManager"; import { RoomManager } from "../room/RoomManager"; -import { SocketEvents } from "@repo/shared"; -import { RoomStatus } from "@repo/shared"; -import type { MovePayload } from "@repo/shared"; +import { protocol, roomTypes } from "@repo/shared"; +import type { playerTypes } from "@repo/shared"; export const registerGameHandlers = (io: Server, socket: Socket, gameManager: GameManager, roomManager: RoomManager) => { // クライアントから送られてきた時刻をそのまま返しつつ、サーバーの現在時刻も添える - socket.on(SocketEvents.PING, (clientTime: number) => { - socket.emit(SocketEvents.PONG, { clientTime, serverTime: Date.now() }); + socket.on(protocol.SocketEvents.PING, (clientTime: number) => { + socket.emit(protocol.SocketEvents.PONG, { clientTime, serverTime: Date.now() }); }); // ゲーム開始要求処理 - socket.on(SocketEvents.START_GAME, () => { + socket.on(protocol.SocketEvents.START_GAME, () => { const room = roomManager.getRoomByOwnerId(socket.id); if (room) { - room.status = RoomStatus.PLAYING; + room.status = roomTypes.RoomStatus.PLAYING; const playerIds = room.players.map((p: { id: string }) => p.id); @@ -33,33 +32,33 @@ (tickData) => { // 1. 各プレイヤーの最新座標をクライアントに送信 tickData.players.forEach((playerData) => { - io.to(room.roomId).emit(SocketEvents.UPDATE_PLAYER, playerData); + io.to(room.roomId).emit(protocol.SocketEvents.UPDATE_PLAYER, playerData); }); // 2. 差分があれば、ルーム内の全員に一斉送信 if (tickData.cellUpdates.length > 0) { - io.to(room.roomId).emit(SocketEvents.UPDATE_MAP_CELLS, tickData.cellUpdates); + io.to(room.roomId).emit(protocol.SocketEvents.UPDATE_MAP_CELLS, tickData.cellUpdates); } }, () => { // 3分経過時に GameLoop から呼ばれる処理 console.log(`[GameHandler] ルーム ${room.roomId} のゲームが終了しました (3分経過)`); - io.to(room.roomId).emit(SocketEvents.GAME_END); // クライアントへ終了通知 - room.status = RoomStatus.WAITING; // ルーム状態を待機に戻す + io.to(room.roomId).emit(protocol.SocketEvents.GAME_END); // クライアントへ終了通知 + room.status = roomTypes.RoomStatus.WAITING; // ルーム状態を待機に戻す } ); // GameManagerから開始時刻を取得し、GAME_STARTイベントにデータを乗せて送る const startTime = gameManager.getRoomStartTime(room.roomId) || Date.now(); - io.to(room.roomId).emit(SocketEvents.GAME_START, { startTime }); + io.to(room.roomId).emit(protocol.SocketEvents.GAME_START, { startTime }); } }); // 画面準備完了通知受信時初期データ返却 - socket.on(SocketEvents.READY_FOR_GAME, () => { + socket.on(protocol.SocketEvents.READY_FOR_GAME, () => { const allPlayers = gameManager.getAllPlayers(); - socket.emit(SocketEvents.CURRENT_PLAYERS, allPlayers); + socket.emit(protocol.SocketEvents.CURRENT_PLAYERS, allPlayers); // 準備が完了したクライアントに対して、改めて開始時刻を個別に教える // Socket.ioの仕様上、socket.roomsには自身のIDと参加中のルームIDが含まれるため、そこからルームIDを特定する @@ -68,13 +67,13 @@ const startTime = gameManager.getRoomStartTime(roomId); if (startTime) { // io.to() による全員への一斉送信ではなく、socket.emit() でこの本人にだけ送る - socket.emit(SocketEvents.GAME_START, { startTime }); + socket.emit(protocol.SocketEvents.GAME_START, { startTime }); } } }); // ゲームプレイ中イベント群 - socket.on(SocketEvents.MOVE, (data: MovePayload) => { + socket.on(protocol.SocketEvents.MOVE, (data: playerTypes.MovePayload) => { gameManager.movePlayer(socket.id, data.x, data.y); }); @@ -87,5 +86,5 @@ // ゲームからの除外処理 gameManager.removePlayer(playerId); // 全体にプレイヤー削除を通知 - io.emit(SocketEvents.REMOVE_PLAYER, playerId); + io.emit(protocol.SocketEvents.REMOVE_PLAYER, playerId); }; \ No newline at end of file diff --git a/apps/server/src/domains/game/GameLoop.ts b/apps/server/src/domains/game/GameLoop.ts index 54a165f..65a7e69 100644 --- a/apps/server/src/domains/game/GameLoop.ts +++ b/apps/server/src/domains/game/GameLoop.ts @@ -1,8 +1,7 @@ import { Player } from "./entities/Player.js"; import { MapStore } from "./states/MapStore"; -import { getGridIndexFromPosition } from "@repo/shared"; -import type { CellUpdate } from "@repo/shared"; -import { GAME_CONFIG } from "@repo/shared"; +import { gridMapLogic, config } from "@repo/shared"; +import type { gridMapTypes } from "@repo/shared"; // コールバックで渡すデータの型定義 export interface TickData { @@ -12,7 +11,7 @@ y: number; teamId: number; }[]; - cellUpdates: CellUpdate[]; + cellUpdates: gridMapTypes.CellUpdate[]; } export class GameLoop { @@ -38,7 +37,7 @@ this.loopId = setInterval(() => { // 時間経過のチェック const elapsedTimeMs = Date.now() - this.startTime; - if (elapsedTimeMs >= GAME_CONFIG.GAME_DURATION_SEC * 1000) { + if (elapsedTimeMs >= config.GAME_CONFIG.GAME_DURATION_SEC * 1000) { // ゲーム終了時にループを止めて終了処理へ this.stop(); this.onGameEnd(); @@ -52,7 +51,7 @@ const player = this.players.get(id); if (!player) return; - const gridIndex = getGridIndexFromPosition(player.x, player.y); + const gridIndex = gridMapLogic.getGridIndexFromPosition(player.x, player.y); if (gridIndex !== null) { this.mapStore.paintCell(gridIndex, player.teamId); } diff --git a/apps/server/src/domains/game/GameManager.ts b/apps/server/src/domains/game/GameManager.ts index 1eddd5d..4e762af 100644 --- a/apps/server/src/domains/game/GameManager.ts +++ b/apps/server/src/domains/game/GameManager.ts @@ -1,8 +1,8 @@ import { Player } from "./entities/Player.js"; -import { GAME_CONFIG } from "@repo/shared"; +import { config } from "@repo/shared"; import { MapStore } from "./states/MapStore"; -import { getGridIndexFromPosition } from "@repo/shared"; -import type { CellUpdate } from "@repo/shared"; +import { gridMapLogic } from "@repo/shared"; +import type { gridMapTypes } from "@repo/shared"; import { GameLoop, type TickData } from "./GameLoop"; // プレイヤー集合の生成・更新・参照管理クラス @@ -27,8 +27,8 @@ // 新規プレイヤー登録と初期位置設定処理 addPlayer(id: string): Player { const player = new Player(id); - player.x = GAME_CONFIG.MAP_WIDTH / 2; - player.y = GAME_CONFIG.MAP_HEIGHT / 2; + player.x = config.GAME_CONFIG.MAP_WIDTH / 2; + player.y = config.GAME_CONFIG.MAP_HEIGHT / 2; this.players.set(id, player); return player; } @@ -71,7 +71,7 @@ ) { if (this.gameLoops.has(roomId)) return; - const tickRate = GAME_CONFIG.PLAYER_POSITION_UPDATE_MS; + const tickRate = config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS; // ループ開始時に、このルームの開始時刻を記憶する this.roomStartTimes.set(roomId, Date.now()); @@ -114,11 +114,11 @@ } // 【一時的】移動したプレイヤーの足元を塗り、差分を返すメソッド - public paintAndGetUpdates(playerId: string): CellUpdate[] { + public paintAndGetUpdates(playerId: string): gridMapTypes.CellUpdate[] { const player = this.players.get(playerId); if (!player) return []; - const gridIndex = getGridIndexFromPosition(player.x, player.y); + const gridIndex = gridMapLogic.getGridIndexFromPosition(player.x, player.y); if (gridIndex !== null) { this.mapStore.paintCell(gridIndex, player.teamId); } diff --git a/apps/server/src/domains/game/entities/Player.ts b/apps/server/src/domains/game/entities/Player.ts index e2fe48a..6e16617 100644 --- a/apps/server/src/domains/game/entities/Player.ts +++ b/apps/server/src/domains/game/entities/Player.ts @@ -1,8 +1,8 @@ -import type { PlayerData } from "@repo/shared"; -import { GAME_CONFIG } from "@repo/shared"; +import type { playerTypes } from "@repo/shared"; +import { config } from "@repo/shared"; // サーバー側保持プレイヤー状態モデル -export class Player implements PlayerData { +export class Player implements playerTypes.PlayerData { public id: string; public x: number = 0; public y: number = 0; @@ -12,7 +12,7 @@ this.id = id; // GAME_CONFIGからチーム数を動的に取得して割り当て - const teamCount = GAME_CONFIG.TEAM_COLORS.length; + const teamCount = config.GAME_CONFIG.TEAM_COLORS.length; this.teamId = Math.floor(Math.random() * teamCount); } } \ No newline at end of file diff --git a/apps/server/src/domains/game/states/MapStore.ts b/apps/server/src/domains/game/states/MapStore.ts index 5112529..108308a 100644 --- a/apps/server/src/domains/game/states/MapStore.ts +++ b/apps/server/src/domains/game/states/MapStore.ts @@ -1,16 +1,16 @@ // apps/server/src/states/MapStore.ts -import type { CellUpdate } from "@repo/shared"; -import { GAME_CONFIG } from "@repo/shared"; +import type { gridMapTypes } from "@repo/shared"; +import { config } from "@repo/shared"; export class MapStore { // 全マスの現在の色(teamId)を保持 private gridColors: number[]; // 次回の送信ループで送る差分リスト - private pendingUpdates: CellUpdate[]; + private pendingUpdates: gridMapTypes.CellUpdate[]; constructor() { // 初期状態は -1 (無色) などで初期化 - const totalCells = GAME_CONFIG.GRID_COLS * GAME_CONFIG.GRID_ROWS; + const totalCells = config.GAME_CONFIG.GRID_COLS * config.GAME_CONFIG.GRID_ROWS; this.gridColors = new Array(totalCells).fill(-1); this.pendingUpdates = []; } @@ -28,7 +28,7 @@ /** * 溜まっている差分を取得し、キューをクリアする(ループ送信時に使用) */ - public getAndClearUpdates(): CellUpdate[] { + public getAndClearUpdates(): gridMapTypes.CellUpdate[] { const updates = [...this.pendingUpdates]; this.pendingUpdates = []; return updates; diff --git a/apps/server/src/domains/room/RoomHandler.ts b/apps/server/src/domains/room/RoomHandler.ts index 778c147..089ac9c 100644 --- a/apps/server/src/domains/room/RoomHandler.ts +++ b/apps/server/src/domains/room/RoomHandler.ts @@ -1,11 +1,11 @@ import { Server, Socket } from "socket.io"; import { RoomManager } from "./RoomManager"; -import { SocketEvents } from "@repo/shared"; -import type { JoinRoomPayload } from "@repo/shared"; +import { protocol } from "@repo/shared"; +import type { roomTypes } from "@repo/shared"; export const registerRoomHandlers = (io: Server, socket: Socket, roomManager: RoomManager) => { - socket.on(SocketEvents.JOIN_ROOM, (data: JoinRoomPayload) => { + socket.on(protocol.SocketEvents.JOIN_ROOM, (data: roomTypes.JoinRoomPayload) => { const { roomId, playerName } = data; socket.join(roomId); @@ -14,7 +14,7 @@ const room = roomManager.addPlayerToRoom(roomId, socket.id, playerName); // ルーム内全員向け最新状態配信 - io.to(roomId).emit(SocketEvents.ROOM_UPDATE, room); + io.to(roomId).emit(protocol.SocketEvents.ROOM_UPDATE, room); }); }; @@ -28,6 +28,6 @@ // 更新があったルーム(オーナー変更など)にのみ通知を飛ばす updatedRooms.forEach(room => { - io.to(room.roomId).emit(SocketEvents.ROOM_UPDATE, room); + io.to(room.roomId).emit(protocol.SocketEvents.ROOM_UPDATE, room); }); }; \ No newline at end of file diff --git a/apps/server/src/domains/room/RoomManager.ts b/apps/server/src/domains/room/RoomManager.ts index ef6ae4f..7bc61c6 100644 --- a/apps/server/src/domains/room/RoomManager.ts +++ b/apps/server/src/domains/room/RoomManager.ts @@ -1,24 +1,23 @@ -import { Room, RoomStatus, RoomMember } from "@repo/shared"; -import { GAME_CONFIG } from "@repo/shared"; +import { roomTypes, config } from "@repo/shared"; export class RoomManager { - private rooms: Map = new Map(); + private rooms: Map = new Map(); // ルームにプレイヤーを追加(なければ作成) - public addPlayerToRoom(roomId: string, socketId: string, playerName: string): Room { + public addPlayerToRoom(roomId: string, socketId: string, playerName: string): roomTypes.Room { let room = this.rooms.get(roomId); if (!room) { room = { roomId: roomId, ownerId: socketId, players: [], - status: RoomStatus.WAITING, - maxPlayers: GAME_CONFIG.MAX_PLAYERS_PER_ROOM + status: roomTypes.RoomStatus.WAITING, + maxPlayers: config.GAME_CONFIG.MAX_PLAYERS_PER_ROOM }; this.rooms.set(roomId, room); } - const newPlayer: RoomMember = { + const newPlayer: roomTypes.RoomMember = { id: socketId, name: playerName, isOwner: room.ownerId === socketId, @@ -30,8 +29,8 @@ } // プレイヤーをルームから削除し、更新があったルームの配列を返す - public removePlayer(socketId: string): Room[] { - const updatedRooms: Room[] = []; + public removePlayer(socketId: string): roomTypes.Room[] { + const updatedRooms: roomTypes.Room[] = []; for (const [roomId, room] of this.rooms.entries()) { const playerIndex = room.players.findIndex(p => p.id === socketId); @@ -55,7 +54,7 @@ } // オーナーIDからルームを取得 - public getRoomByOwnerId(ownerId: string): Room | undefined { + public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined { for (const room of this.rooms.values()) { if (room.ownerId === ownerId) { return room; diff --git a/apps/server/src/network/SocketManager.ts b/apps/server/src/network/SocketManager.ts index 9622b54..0aa661c 100644 --- a/apps/server/src/network/SocketManager.ts +++ b/apps/server/src/network/SocketManager.ts @@ -1,7 +1,7 @@ import { Server, Socket } from "socket.io"; import { GameManager } from "../domains/game/GameManager"; import { RoomManager } from "../domains/room/RoomManager"; -import { SocketEvents } from "@repo/shared"; +import { protocol } from "@repo/shared"; import { registerRoomHandlers, handleRoomDisconnect } from "../domains/room/RoomHandler"; import { registerGameHandlers, handleGameDisconnect } from "../domains/game/GameHandler"; @@ -17,13 +17,13 @@ } public initialize() { - this.io.on(SocketEvents.CONNECT, (socket: Socket) => { + this.io.on(protocol.SocketEvents.CONNECT, (socket: Socket) => { console.log(`✅ User connected: ${socket.id}`); registerRoomHandlers(this.io, socket, this.roomManager); registerGameHandlers(this.io, socket, this.gameManager, this.roomManager); - socket.on(SocketEvents.DISCONNECT, () => { + socket.on(protocol.SocketEvents.DISCONNECT, () => { console.log(`❌ User disconnected: ${socket.id}`); // 順番を厳守して実行 diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index e290030..24c70f6 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,7 +1,7 @@ // shared パッケージ公開 API -export * from "./domains/gridMap/gridMap.type"; -export * from "./domains/gridMap/gridMap.logic"; -export * from "./domains/player/player.type"; -export * from "./domains/room/room.type"; -export * from "./protocol/events"; -export * from "./config/gameConfig"; \ No newline at end of file +export * as gridMapTypes from "./domains/gridMap/gridMap.type"; +export * as gridMapLogic from "./domains/gridMap/gridMap.logic"; +export * as playerTypes from "./domains/player/player.type"; +export * as roomTypes from "./domains/room/room.type"; +export * as protocol from "./protocol/events"; +export * as config from "./config/gameConfig"; \ No newline at end of file