refactor(game): unify GameState, standardize board props, and rename game components
- Replaced multiple App-level state fields with unified GameState
- Added INITIAL_GAME_STATE and migrated App.tsx to use single game state
- Introduced GameProps as shared base props for all turn-based board games
- Created TicTacToeGameProps and BattleshipGameProps extending GameProps
- Updated TicTacToe and Battleship components to use new props
- Replaced verbose prop passing with spread {...commonProps}
- Updated renderGameBoard to use game.metadata consistently
- Renamed TicTacToeBoard -> TicTacToeGame for clarity
- Renamed BattleShipBoard -> BattleShipGame for naming consistency
- Updated all import paths to reflect new component names
- Replaced MatchDataMessage with MatchDataModel
- Moved GameState definition from models.ts to interfaces/states.ts
- Removed old board-specific prop structures and per-field state management
- Increased type safety and reduced duplication across the codebase
This commit consolidates game state flow, introduces a clean component props
architecture, and standardizes naming convention
This commit is contained in:
103
src/App.tsx
103
src/App.tsx
@@ -1,57 +1,67 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { useNakama } from "./providers/NakamaProvider";
|
||||
import Player from "./Player";
|
||||
import { PlayerModel } from "./interfaces/models";
|
||||
|
||||
import TicTacToeBoard from "./games/tictactoe/TicTacToeBoard";
|
||||
import BattleShipBoard from "./games/battleship/BattleShipBoard";
|
||||
import Player from "./Player";
|
||||
import TicTacToeGame from "./games/tictactoe/TicTacToeGame";
|
||||
import { TicTacToeGameProps } from "./games/tictactoe/props";
|
||||
import BattleShipGame from "./games/battleship/BattleShipGame";
|
||||
import { BattleshipGameProps } from "./games/battleship/props";
|
||||
|
||||
import { GameState } from "./interfaces/states";
|
||||
import { GameProps } from "./interfaces/props";
|
||||
|
||||
const INITIAL_GAME_STATE: GameState = {
|
||||
boards: {},
|
||||
turn: 0,
|
||||
winner: null,
|
||||
gameOver: false,
|
||||
players: [],
|
||||
metadata: {},
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
// setting up a 2D game boards
|
||||
const [boards, setBoards] = useState<Record<string, { grid: string[][] }>>({});
|
||||
const [turn, setTurn] = useState<number>(0);
|
||||
const [winner, setWinner] = useState<string | null>(null);
|
||||
const [gameOver, setGameOver] = useState<boolean | null>(null);
|
||||
const [players, setPlayers] = useState<PlayerModel[]>([]);
|
||||
const [metadata, setMetadata] = useState<Record<string, any>>({});
|
||||
|
||||
// unified game state
|
||||
const [game, setGame] = useState<GameState>(INITIAL_GAME_STATE);
|
||||
const { sendMatchData, onMatchData, matchId, session } = useNakama();
|
||||
|
||||
function renderGameBoard() {
|
||||
if (!matchId || !metadata?.game) return null;
|
||||
const commonProps: GameProps = {
|
||||
boards: game.boards,
|
||||
turn: game.turn,
|
||||
winner: game.winner,
|
||||
gameOver: game.gameOver,
|
||||
players: game.players,
|
||||
myUserId: session?.user_id ?? null,
|
||||
};
|
||||
|
||||
switch (metadata.game) {
|
||||
// ---------------------------------------------------
|
||||
// RENDER GAME BOARD
|
||||
// ---------------------------------------------------
|
||||
function renderGameBoard() {
|
||||
if (!matchId || !game.metadata?.game) return null;
|
||||
|
||||
switch (game.metadata.game) {
|
||||
case "tictactoe":
|
||||
return (
|
||||
<TicTacToeBoard
|
||||
boards={boards}
|
||||
turn={turn}
|
||||
winner={winner}
|
||||
gameOver={gameOver}
|
||||
players={players}
|
||||
myUserId={session?.user_id ?? null}
|
||||
<TicTacToeGame
|
||||
{...commonProps}
|
||||
onCellClick={handleCellClick}
|
||||
/>
|
||||
);
|
||||
|
||||
case "battleship":
|
||||
return (
|
||||
<BattleShipBoard
|
||||
boards={boards}
|
||||
turn={turn}
|
||||
winner={winner}
|
||||
gameOver={gameOver}
|
||||
players={players}
|
||||
myUserId={session?.user_id ?? null}
|
||||
metadata={metadata}
|
||||
<BattleShipGame
|
||||
{...commonProps}
|
||||
metadata={game.metadata}
|
||||
/>
|
||||
);
|
||||
|
||||
default:
|
||||
return <div>Unknown game: {metadata.game}</div>;
|
||||
return <div>Unknown game: {game.metadata.game}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
// MATCH DATA CALLBACK (from Player component)
|
||||
// ------------------------------------------
|
||||
@@ -62,23 +72,21 @@ export default function App() {
|
||||
const state = msg.data;
|
||||
console.log("Match state:", state);
|
||||
|
||||
setBoards(state.boards);
|
||||
setTurn(state.turn);
|
||||
setGameOver(state.game_over);
|
||||
if (state.winner >= 0) {
|
||||
setWinner(state.players[state.winner].username);
|
||||
// } else if (state.game_over) {
|
||||
// // Game ended but winner = -1 → draw
|
||||
// setWinner("draw");
|
||||
} else {
|
||||
// Ongoing game, no winner
|
||||
setWinner(null);
|
||||
}
|
||||
setPlayers(state.players || []);
|
||||
setMetadata(state.metadata || {});
|
||||
setGame({
|
||||
boards: state.boards,
|
||||
turn: state.turn,
|
||||
gameOver: state.game_over,
|
||||
winner:
|
||||
state.winner >= 0 ? state.players[state.winner].username : null,
|
||||
players: state.players ?? [],
|
||||
metadata: state.metadata ?? {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
// EFFECTS
|
||||
// ---------------------------------------------------
|
||||
useEffect(() => {
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => {
|
||||
@@ -96,9 +104,12 @@ export default function App() {
|
||||
function handleCellClick(row: number, col: number) {
|
||||
if (!matchId) return;
|
||||
|
||||
sendMatchData(matchId, 1, {data: {row, col}});
|
||||
sendMatchData(matchId, 1, { data: { row, col } });
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
// UI LAYOUT
|
||||
// ---------------------------------------------------
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user