diff --git a/apps/client/src/network/handlers/GameHandler.ts b/apps/client/src/network/handlers/GameHandler.ts index 2d5b226..e87bf04 100644 --- a/apps/client/src/network/handlers/GameHandler.ts +++ b/apps/client/src/network/handlers/GameHandler.ts @@ -1,14 +1,20 @@ +/** + * GameHandler + * ゲーム関連のソケット購読と送信APIを提供する + * シーン層が利用する通信操作を集約する + */ import type { Socket } from "socket.io-client"; import { protocol } from "@repo/shared"; import type { playerTypes, gridMapTypes } from "@repo/shared"; -type GameHandler = { +/** ゲームシーンが利用するソケット操作の契約 */ +export type GameHandler = { onCurrentPlayers: (callback: (players: playerTypes.PlayerData[] | Record) => void) => void; offCurrentPlayers: (callback: (players: playerTypes.PlayerData[] | Record) => void) => void; onNewPlayer: (callback: (player: playerTypes.PlayerData) => void) => void; offNewPlayer: (callback: (player: playerTypes.PlayerData) => void) => void; - onUpdatePlayer: (callback: (data: Partial & { id: string }) => void) => void; - offUpdatePlayer: (callback: (data: Partial & { id: string }) => void) => void; + onUpdatePlayers: (callback: (players: playerTypes.PlayerData[]) => void) => void; + offUpdatePlayers: (callback: (players: playerTypes.PlayerData[]) => void) => void; onRemovePlayer: (callback: (id: string) => void) => void; offRemovePlayer: (callback: (id: string) => void) => void; onUpdateMapCells: (callback: (updates: gridMapTypes.CellUpdate[]) => void) => void; @@ -19,6 +25,7 @@ readyForGame: () => void; }; +/** ソケットインスタンスからゲーム向けハンドラを生成する */ export const createGameHandler = (socket: Socket): GameHandler => { return { onCurrentPlayers: (callback) => { @@ -33,11 +40,11 @@ offNewPlayer: (callback) => { socket.off(protocol.SocketEvents.NEW_PLAYER, callback); }, - onUpdatePlayer: (callback) => { - socket.on(protocol.SocketEvents.UPDATE_PLAYER, callback); + onUpdatePlayers: (callback) => { + socket.on(protocol.SocketEvents.UPDATE_PLAYERS, callback); }, - offUpdatePlayer: (callback) => { - socket.off(protocol.SocketEvents.UPDATE_PLAYER, callback); + offUpdatePlayers: (callback) => { + socket.off(protocol.SocketEvents.UPDATE_PLAYERS, callback); }, onRemovePlayer: (callback) => { socket.on(protocol.SocketEvents.REMOVE_PLAYER, callback); @@ -66,5 +73,3 @@ } }; }; - -export type { GameHandler }; diff --git a/apps/client/src/scenes/game/application/GameNetworkSync.ts b/apps/client/src/scenes/game/application/GameNetworkSync.ts index a34e55f..6e7422a 100644 --- a/apps/client/src/scenes/game/application/GameNetworkSync.ts +++ b/apps/client/src/scenes/game/application/GameNetworkSync.ts @@ -49,12 +49,15 @@ } }; - private handleUpdatePlayer = (data: Partial & { id: string }) => { - if (data.id === this.myId) return; - const target = this.players[data.id]; - if (target && target instanceof RemotePlayerController) { - target.applyRemoteUpdate({ x: data.x, y: data.y }); - } + private handleUpdatePlayers = (serverPlayers: playerTypes.PlayerData[]) => { + serverPlayers.forEach((playerData) => { + if (playerData.id === this.myId) return; + + const target = this.players[playerData.id]; + if (target && target instanceof RemotePlayerController) { + target.applyRemoteUpdate({ x: playerData.x, y: playerData.y }); + } + }); }; private handleRemovePlayer = (id: string) => { @@ -84,7 +87,7 @@ socketManager.game.onCurrentPlayers(this.handleCurrentPlayers); socketManager.game.onNewPlayer(this.handleNewPlayer); socketManager.game.onGameStart(this.handleGameStart); - socketManager.game.onUpdatePlayer(this.handleUpdatePlayer); + socketManager.game.onUpdatePlayers(this.handleUpdatePlayers); socketManager.game.onRemovePlayer(this.handleRemovePlayer); socketManager.game.onUpdateMapCells(this.handleUpdateMapCells); @@ -97,7 +100,7 @@ socketManager.game.offCurrentPlayers(this.handleCurrentPlayers); socketManager.game.offNewPlayer(this.handleNewPlayer); socketManager.game.offGameStart(this.handleGameStart); - socketManager.game.offUpdatePlayer(this.handleUpdatePlayer); + socketManager.game.offUpdatePlayers(this.handleUpdatePlayers); socketManager.game.offRemovePlayer(this.handleRemovePlayer); socketManager.game.offUpdateMapCells(this.handleUpdateMapCells); diff --git a/apps/server/src/application/coordinators/startGameCoordinator.ts b/apps/server/src/application/coordinators/startGameCoordinator.ts index 87220ce..cddf474 100644 --- a/apps/server/src/application/coordinators/startGameCoordinator.ts +++ b/apps/server/src/application/coordinators/startGameCoordinator.ts @@ -17,7 +17,7 @@ roomManager: StartGameRoomPort; output: Pick< GameOutputPort, - | "publishUpdatePlayerToRoom" + | "publishUpdatePlayersToRoom" | "publishMapCellUpdatesToRoom" | "publishGameEndToRoom" | "publishGameStartToRoom" diff --git a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts index c3f8e0f..4d03233 100644 --- a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts +++ b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts @@ -47,7 +47,10 @@ /** ゲーム系ユースケースが利用する送信出力ポート */ export interface GameOutputPort { publishPongToSocket(payload: { clientTime: number; serverTime: number }): void; - publishUpdatePlayerToRoom(roomId: roomTypes.Room["roomId"], playerData: playerTypes.PlayerData): void; + publishUpdatePlayersToRoom( + roomId: roomTypes.Room["roomId"], + players: playerTypes.PlayerData[] + ): void; publishMapCellUpdatesToRoom( roomId: roomTypes.Room["roomId"], cellUpdates: gridMapTypes.CellUpdate[] diff --git a/apps/server/src/domains/game/application/useCases/startGameUseCase.ts b/apps/server/src/domains/game/application/useCases/startGameUseCase.ts index f4075f0..9f95b56 100644 --- a/apps/server/src/domains/game/application/useCases/startGameUseCase.ts +++ b/apps/server/src/domains/game/application/useCases/startGameUseCase.ts @@ -12,7 +12,7 @@ onGameEnd: () => void; output: Pick< GameOutputPort, - | "publishUpdatePlayerToRoom" + | "publishUpdatePlayersToRoom" | "publishMapCellUpdatesToRoom" | "publishGameEndToRoom" | "publishGameStartToRoom" @@ -31,9 +31,7 @@ roomId, playerIds, (tickData) => { - tickData.players.forEach((playerData) => { - output.publishUpdatePlayerToRoom(roomId, playerData); - }); + output.publishUpdatePlayersToRoom(roomId, tickData.players); if (tickData.cellUpdates.length > 0) { output.publishMapCellUpdatesToRoom(roomId, tickData.cellUpdates); diff --git a/apps/server/src/network/handlers/game/createGameOutputAdapter.ts b/apps/server/src/network/handlers/game/createGameOutputAdapter.ts index 98d1c63..4e43e44 100644 --- a/apps/server/src/network/handlers/game/createGameOutputAdapter.ts +++ b/apps/server/src/network/handlers/game/createGameOutputAdapter.ts @@ -14,7 +14,7 @@ type PongPayload = { clientTime: number; serverTime: number }; type GameStartPayload = { startTime: number }; type CurrentPlayersPayload = playerTypes.PlayerData[]; -type UpdatePlayerPayload = playerTypes.PlayerData; +type UpdatePlayersPayload = playerTypes.PlayerData[]; type MapCellUpdatesPayload = gridMapTypes.CellUpdate[]; /** ゲーム出力アダプターのインターフェース */ @@ -29,8 +29,8 @@ publishPongToSocket: (payload: PongPayload) => { common.emitToSocket(protocol.SocketEvents.PONG, payload); }, - publishUpdatePlayerToRoom: (roomId: RoomId, playerData: UpdatePlayerPayload) => { - common.emitToRoom(roomId, protocol.SocketEvents.UPDATE_PLAYER, playerData); + publishUpdatePlayersToRoom: (roomId: RoomId, players: UpdatePlayersPayload) => { + common.emitToRoom(roomId, protocol.SocketEvents.UPDATE_PLAYERS, players); }, publishMapCellUpdatesToRoom: (roomId: RoomId, cellUpdates: MapCellUpdatesPayload) => { common.emitToRoom(roomId, protocol.SocketEvents.UPDATE_MAP_CELLS, cellUpdates); diff --git a/packages/shared/src/protocol/events.ts b/packages/shared/src/protocol/events.ts index 39a1c4a..6082e05 100644 --- a/packages/shared/src/protocol/events.ts +++ b/packages/shared/src/protocol/events.ts @@ -1,3 +1,9 @@ +/** + * events + * ソケット通信で利用するイベント名定数を定義する + * クライアントとサーバー間のイベント契約を共有する + */ +/** ソケットイベント名の一覧定数 */ export const SocketEvents = { // 接続・切断イベント名 CONNECT: "connect", @@ -14,7 +20,8 @@ // ゲームプレイ関連イベント名 CURRENT_PLAYERS: "current_players", NEW_PLAYER: "new_player", - UPDATE_PLAYER: "update_player", + // 1ティック分のプレイヤー状態を配列でまとめて通知する + UPDATE_PLAYERS: "update_players", REMOVE_PLAYER: "remove_player", MOVE: "move", UPDATE_MAP_CELLS: "update_map_cells",