refactored frontent to separate files
This commit is contained in:
89
client/src/game/BoardDisplay.tsx
Normal file
89
client/src/game/BoardDisplay.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useGameChannelContext } from "../contexts/useGameChannelContext";
|
||||
|
||||
interface Player {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface GameState {
|
||||
[playerId: string]: Player;
|
||||
}
|
||||
|
||||
export const BoardDisplay = () => {
|
||||
const { channel, isJoined } = useGameChannelContext();
|
||||
const [players, setPlayers] = useState<GameState>({});
|
||||
const [myPlayerId, setMyPlayerId] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!channel || !isJoined) return;
|
||||
|
||||
// Listen for game state updates
|
||||
const ref = channel.on("game_state", (payload: { players: GameState }) => {
|
||||
setPlayers(payload.players);
|
||||
|
||||
if (!myPlayerId && Object.keys(payload.players).length > 0) {
|
||||
const playerIds = Object.keys(payload.players);
|
||||
if (playerIds.length > 0) {
|
||||
setMyPlayerId(playerIds[playerIds.length - 1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup listener on unmount
|
||||
return () => {
|
||||
channel.off("game_state", ref);
|
||||
};
|
||||
}, [channel, isJoined, myPlayerId]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
width: "800px",
|
||||
height: "600px",
|
||||
background: "#16213e",
|
||||
margin: "50px auto",
|
||||
border: "2px solid #0f3460",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{Object.entries(players).map(([id, player]) => (
|
||||
<div
|
||||
key={id}
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: player.x,
|
||||
top: player.y,
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
borderRadius: "50%",
|
||||
background: id === myPlayerId ? "#e94560" : "#53a8b6",
|
||||
border:
|
||||
id === myPlayerId ? "3px solid #ff6b6b" : "2px solid #48d6e0",
|
||||
transition: "all 0.1s linear",
|
||||
transform: "translate(-50%, -50%)",
|
||||
boxShadow:
|
||||
id === myPlayerId ? "0 0 10px #e94560" : "0 0 5px #53a8b6",
|
||||
}}
|
||||
>
|
||||
{id === myPlayerId && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-25px",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
color: "#fff",
|
||||
fontSize: "10px",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
You
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
26
client/src/game/ConnectionStatus.tsx
Normal file
26
client/src/game/ConnectionStatus.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useWebSocketContext } from "../contexts/useWebSocketContext";
|
||||
import { useGameChannelContext } from "../contexts/useGameChannelContext";
|
||||
|
||||
export const ConnectionStatus = () => {
|
||||
const { connectionStatus } = useWebSocketContext();
|
||||
const { channelStatus } = useGameChannelContext();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 10,
|
||||
right: 10,
|
||||
color: "white",
|
||||
fontFamily: "monospace",
|
||||
background: "rgba(0,0,0,0.5)",
|
||||
padding: "10px",
|
||||
borderRadius: "5px",
|
||||
fontSize: "12px",
|
||||
}}
|
||||
>
|
||||
<div>WebSocket: {connectionStatus}</div>
|
||||
<div>Channel: {channelStatus}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
45
client/src/game/UserInput.tsx
Normal file
45
client/src/game/UserInput.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useGameChannelContext } from "../contexts/useGameChannelContext";
|
||||
|
||||
export const UserInput = () => {
|
||||
const { channel } = useGameChannelContext();
|
||||
const keysPressed = useRef<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
if (!channel) return;
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const key = e.key.toLowerCase();
|
||||
if (["w", "a", "s", "d"].includes(key)) {
|
||||
e.preventDefault();
|
||||
|
||||
// Only send if not already pressed (prevent repeat)
|
||||
if (!keysPressed.current.has(key)) {
|
||||
keysPressed.current.add(key);
|
||||
|
||||
// Send to active channel
|
||||
if (channel.state === "joined") {
|
||||
channel.push("move", { direction: key });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
const key = e.key.toLowerCase();
|
||||
if (["w", "a", "s", "d"].includes(key)) {
|
||||
keysPressed.current.delete(key);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
window.addEventListener("keyup", handleKeyUp);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown);
|
||||
window.removeEventListener("keyup", handleKeyUp);
|
||||
};
|
||||
}, [channel]);
|
||||
|
||||
return null;
|
||||
};
|
||||
Reference in New Issue
Block a user