feat(ui/battleship): integrate BattleshipBoard and metadata-driven placement/battle flow
- Added metadata state to App and wired incoming match metadata. - Added Fleet + FLEET_ORDER in BattleShipBoard to drive ship placement order. - Added nextShip + nextShipSize calculation for guided placement. - Updated handlePlace and handleShoot to send structured payloads (action + data). - Added lobby/placement/battle status messages. - Updated grids to use shipBoard + shipName/shipSize props instead of generic grid. - Fixed metadata access (state.Metadata vs state.metadata). - Consolidated PlacementGrid usage and disabled it during battle phase. - Added logging for debugging incoming battleship boards.
This commit is contained in:
@@ -16,6 +16,15 @@ interface BattleBoardProps {
|
|||||||
metadata: Record<string, any>;
|
metadata: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Fleet: Record<string, number> = {
|
||||||
|
carrier: 5,
|
||||||
|
battleship: 4,
|
||||||
|
cruiser: 3,
|
||||||
|
submarine: 3,
|
||||||
|
destroyer: 2,
|
||||||
|
};
|
||||||
|
const FLEET_ORDER = ["carrier", "battleship", "cruiser", "submarine", "destroyer"];
|
||||||
|
|
||||||
export default function BattleShipBoard({
|
export default function BattleShipBoard({
|
||||||
boards,
|
boards,
|
||||||
players,
|
players,
|
||||||
@@ -25,49 +34,55 @@ export default function BattleShipBoard({
|
|||||||
gameOver,
|
gameOver,
|
||||||
metadata,
|
metadata,
|
||||||
}: BattleBoardProps) {
|
}: BattleBoardProps) {
|
||||||
const { matchId, sendMatchData } = useNakama();
|
const { sendMatchData, matchId } = useNakama();
|
||||||
|
|
||||||
const myIndex = players.findIndex((p) => p.user_id === myUserId);
|
const myIndex = players.findIndex((p) => p.user_id === myUserId);
|
||||||
const oppIndex = myIndex === 0 ? 1 : 0;
|
const oppIndex = myIndex === 0 ? 1 : 0;
|
||||||
|
|
||||||
const phase = metadata["phase"] ?? "placement";
|
console.log(metadata, "metadata");
|
||||||
|
const phase = metadata["phase"] ?? "lobby";
|
||||||
const isMyTurn = phase === "battle" && turn === myIndex;
|
const isMyTurn = phase === "battle" && turn === myIndex;
|
||||||
|
|
||||||
const myShips = boards[`p${myIndex}_ships`]?.grid ?? [];
|
const myShips = boards[`p${myIndex}_ships`]?.grid ?? [[]];
|
||||||
const myShots = boards[`p${myIndex}_shots`]?.grid ?? [];
|
const myShots = boards[`p${myIndex}_shots`] ?.grid ?? [[]];
|
||||||
|
|
||||||
const placed = metadata[`p${myIndex}_placed`] ?? 0;
|
const placed = metadata[`p${myIndex}_placed`] ?? 0;
|
||||||
|
|
||||||
// ----------- SEND PLACE MESSAGE -----------
|
const nextShip = FLEET_ORDER[placed] || null;
|
||||||
|
const nextShipSize = nextShip ? Fleet[nextShip] : null;
|
||||||
|
|
||||||
|
// ------------------- PLACE SHIP -------------------
|
||||||
function handlePlace(ship: string, r: number, c: number, dir: "h" | "v") {
|
function handlePlace(ship: string, r: number, c: number, dir: "h" | "v") {
|
||||||
sendMatchData(matchId!, 2, {
|
sendMatchData(matchId!, 1, {
|
||||||
action: "place",
|
action: "place",
|
||||||
ship,
|
data: {
|
||||||
row: r,
|
ship: ship,
|
||||||
col: c,
|
row: r,
|
||||||
dir,
|
col: c,
|
||||||
|
dir,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- SEND SHOT MESSAGE -----------
|
// ------------------- SHOOT -------------------
|
||||||
function handleShoot(r: number, c: number) {
|
function handleShoot(r: number, c: number) {
|
||||||
sendMatchData(matchId!, 2, {
|
sendMatchData(matchId!, 1, {
|
||||||
action: "shoot",
|
action: "shoot",
|
||||||
row: r,
|
row: r,
|
||||||
col: c,
|
col: c,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------- STATUS LINE ---------------------
|
// ------------------- STATUS LABEL -------------------
|
||||||
const status = useMemo(() => {
|
const status = useMemo(() => {
|
||||||
if (winner) return `Winner: Player ${winner}`;
|
if (phase === "lobby") return `In Lobby`;
|
||||||
|
if (winner !== null) return `Winner: Player ${winner}`;
|
||||||
if (gameOver) return "Game over — draw";
|
if (gameOver) return "Game over — draw";
|
||||||
if (phase === "placement") return "Place your ships";
|
if (phase === "placement") return `Place your ${nextShip ?? ""}`;
|
||||||
if (myIndex === -1) return "Spectating";
|
if (myIndex === -1) return "Spectating";
|
||||||
if (!isMyTurn) return "Opponent's turn";
|
if (!isMyTurn) return "Opponent’s turn";
|
||||||
return "Your turn";
|
return "Your turn";
|
||||||
}, [winner, gameOver, phase, isMyTurn, myIndex]);
|
}, [winner, gameOver, phase, isMyTurn, myIndex, nextShip]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -79,20 +94,20 @@ export default function BattleShipBoard({
|
|||||||
<h2 style={{ marginBottom: 8 }}>{status}</h2>
|
<h2 style={{ marginBottom: 8 }}>{status}</h2>
|
||||||
|
|
||||||
{/* ---------------- PHASE 1: PLACEMENT ---------------- */}
|
{/* ---------------- PHASE 1: PLACEMENT ---------------- */}
|
||||||
{phase === "placement" && (
|
{phase === "placement" && nextShip && (
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
<PlacementGrid
|
||||||
<PlacementGrid
|
shipBoard={myShips}
|
||||||
grid={myShips}
|
shipName={nextShip}
|
||||||
placed={placed}
|
shipSize={nextShipSize}
|
||||||
onPlace={handlePlace}
|
onPlace={handlePlace}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* ---------------- PHASE 2: BATTLE ---------------- */}
|
{/* ---------------- PHASE 2: BATTLE ---------------- */}
|
||||||
{phase === "battle" && (
|
{phase === "battle" && (
|
||||||
<>
|
<>
|
||||||
<h3>Your Shots</h3>
|
<h3>Your Shots</h3>
|
||||||
|
|
||||||
<ShotGrid
|
<ShotGrid
|
||||||
grid={myShots}
|
grid={myShots}
|
||||||
isMyTurn={isMyTurn}
|
isMyTurn={isMyTurn}
|
||||||
@@ -102,9 +117,10 @@ export default function BattleShipBoard({
|
|||||||
|
|
||||||
<h3 style={{ marginTop: "18px" }}>Your Ships</h3>
|
<h3 style={{ marginTop: "18px" }}>Your Ships</h3>
|
||||||
<PlacementGrid
|
<PlacementGrid
|
||||||
grid={myShips}
|
shipBoard={myShips}
|
||||||
placed={999} // show ships but disable placement
|
shipName="readonly"
|
||||||
readOnly
|
shipSize={0}
|
||||||
|
onPlace={() => {}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user