Skip to content

Commit

Permalink
feat: create a game context
Browse files Browse the repository at this point in the history
  • Loading branch information
iaurg committed Jul 13, 2023
1 parent bbd0fa1 commit b0cf4f0
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 151 deletions.
161 changes: 10 additions & 151 deletions frontend/src/app/(private)/game/play/page.tsx
Original file line number Diff line number Diff line change
@@ -1,162 +1,21 @@
"use client";
import { GameContext } from "@/contexts/GameContext";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useRef, useState } from "react";
import io, { Socket } from "socket.io-client";
import { useCallback, useContext, useEffect, useRef, useState } from "react";

const Game = dynamic(() => import("../../../../components/Game"), {
ssr: false,
});

/**
* Backend websocket events
* 1. joinGame
* 2. startGame
* 3. updatedGame
* 4. movePlayer
* 5. gameFinished
* 6. gameAbandoned
*/

export type GameData = {
gameId: string;
finished: boolean;
player1: {
id: string;
x: number;
y: number;
width: number;
height: number;
};
player2: {
id: string;
x: number;
y: number;
width: number;
height: number;
};
ball: {
x: number;
y: number;
dx: number;
dy: number;
radius: number;
};
canvas: {
width: number;
height: number;
};
score: {
player1: number;
player2: number;
};
};

export type MovePlayerData = {
gameId: string;
player: string;
direction: string;
};

export default function PlayPage() {
const {
waitingPlayer2,
gameFinished,
gameAbandoned,
gameFinishedData,
gameData,
} = useContext(GameContext);
const canvasRef = useRef() as React.RefObject<HTMLDivElement>;
const [waitingPlayer2, setWaitingPlayer2] = useState(true);
const [gameFinished, setGameFinished] = useState(false);
const [gameAbandoned, setGameAbandoned] = useState(false);
const [clientId, setClientId] = useState("");
const [gameData, setGameData] = useState({} as GameData);
const [gameFinishedData, setGameFinishedData] = useState({} as GameData);
const socket = useRef<Socket | null>(null);

useEffect(() => {
// Listen for the 'connect' event
socket.current = io("http://localhost:3000/game", {
transports: ["websocket", "polling", "flashsocket"],
});

socket.current.on("connect", () => {
console.log("Connected to the WebSocket server");
if (socket.current) {
setClientId(socket.current.id);
}
});

socket.current.on("disconnect", () => {
console.log("Disconnected from the WebSocket server");
if (socket.current) {
socket.current.emit("finishGame");
}
});

socket.current.emit("joinGame");

socket.current.on("waitingPlayer2", () => {
console.log("waitingPlayer2");
setWaitingPlayer2(true);
});

socket.current.on("gameCreated", (data: any, data2: any) => {
console.log("gameCreated", data);
setWaitingPlayer2(false);
if (socket.current) {
socket.current.emit("startGame");
}
});

// listen event from server called updatedGame
socket.current.on("updatedGame", (data: any) => {
//set game data based on data from server
setGameData((gameData: GameData) => ({
...gameData,
...data,
}));
});

socket.current.on("gameFinished", (data: any) => {
console.log("gameFinished", data);
setGameFinishedData(data);
setGameFinished(true);
});

socket.current.on("gameAbandoned", (data: any) => {
console.log("gameAbandoned", data);
setGameAbandoned(true);
});

return () => {
if (socket.current) {
socket.current.disconnect();
}
};
}, []);

useEffect(() => {
const handleMovePlayer = (direction: string) => {
if (socket.current) {
console.log("movePlayer", direction, gameData.gameId, clientId);
socket.current.emit("movePlayer", {
gameId: gameData.gameId,
player_id: clientId,
direction: direction,
});
}
};

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "ArrowUp") {
console.log("up");
handleMovePlayer("UP");
} else if (e.key === "ArrowDown") {
console.log("down");
handleMovePlayer("DOWN");
}
};

window.addEventListener("keydown", handleKeyDown);

return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [clientId, gameData]);

if (waitingPlayer2) {
return (
Expand Down Expand Up @@ -230,6 +89,7 @@ export default function PlayPage() {
</>
);
}

return (
<>
<div
Expand All @@ -240,7 +100,6 @@ export default function PlayPage() {
mt-4
"
>
<span className="text-white">Você é o {clientId}</span>
<div
className="
flex
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/app/(private)/game/play/template.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { GameProvider } from "@/contexts/GameContext";

export default function Template({ children }: { children: React.ReactNode }) {
return (
<GameProvider>
<div>{children}</div>
</GameProvider>
)
}
180 changes: 180 additions & 0 deletions frontend/src/contexts/GameContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
"use client";
import React, { createContext, useEffect, useRef, useState } from "react";
import io, { Socket } from "socket.io-client";

/**
* Backend websocket events
* 1. joinGame
* 2. startGame
* 3. updatedGame
* 4. movePlayer
* 5. gameFinished
* 6. gameAbandoned
*/

export type GameData = {
gameId: string;
finished: boolean;
player1: {
id: string;
x: number;
y: number;
width: number;
height: number;
};
player2: {
id: string;
x: number;
y: number;
width: number;
height: number;
};
ball: {
x: number;
y: number;
dx: number;
dy: number;
radius: number;
};
canvas: {
width: number;
height: number;
};
score: {
player1: number;
player2: number;
};
};

export type MovePlayerData = {
gameId: string;
player: string;
direction: string;
};

type GameContextType = {
waitingPlayer2: boolean;
gameFinished: boolean;
gameAbandoned: boolean;
gameFinishedData: GameData;
gameData: GameData;
};

type GameProviderProps = {
children: React.ReactNode;
};

export const GameContext = createContext<GameContextType>(
{} as GameContextType
);

export const GameProvider = ({ children }: GameProviderProps) => {
const [waitingPlayer2, setWaitingPlayer2] = useState(true);
const [gameFinished, setGameFinished] = useState(false);
const [gameAbandoned, setGameAbandoned] = useState(false);
const [clientId, setClientId] = useState("");
const [gameData, setGameData] = useState({} as GameData);
const [gameFinishedData, setGameFinishedData] = useState({} as GameData);
const socket = useRef<Socket | null>(null);

useEffect(() => {
// Listen for the 'connect' event
socket.current = io("http://localhost:3000/game", {
transports: ["websocket", "polling", "flashsocket"],
});

socket.current.on("connect", () => {
console.log("Connected to the WebSocket server");
if (socket.current) {
setClientId(socket.current.id);
}
});

socket.current.on("disconnect", () => {
console.log("Disconnected from the WebSocket server");
if (socket.current) {
socket.current.emit("finishGame");
}
});

socket.current.emit("joinGame");

socket.current.on("waitingPlayer2", () => {
setWaitingPlayer2(true);
});

socket.current.on("gameCreated", (data: any, data2: any) => {
setWaitingPlayer2(false);
if (socket.current) {
socket.current.emit("startGame");
}
});

// listen event from server called updatedGame
socket.current.on("updatedGame", (data: any) => {
//set game data based on data from server
setGameData((gameData: GameData) => ({
...gameData,
...data,
}));
});

socket.current.on("gameFinished", (data: any) => {
console.log("gameFinished", data);
setGameFinishedData(data);
setGameFinished(true);
});

socket.current.on("gameAbandoned", (data: any) => {
console.log("gameAbandoned", data);
setGameAbandoned(true);
});

return () => {
if (socket.current) {
socket.current.disconnect();
}
};
}, []);

useEffect(() => {
const handleMovePlayer = (direction: string) => {
if (socket.current) {
socket.current.emit("movePlayer", {
gameId: gameData.gameId,
player_id: clientId,
direction: direction,
});
}
};

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "ArrowUp") {
console.log("up");
handleMovePlayer("UP");
} else if (e.key === "ArrowDown") {
console.log("down");
handleMovePlayer("DOWN");
}
};

window.addEventListener("keydown", handleKeyDown);

return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [clientId, gameData]);
return (
<GameContext.Provider
value={{
waitingPlayer2,
gameFinished,
gameAbandoned,
gameFinishedData,
gameData,
}}
>
{children}
</GameContext.Provider>
);
};

0 comments on commit b0cf4f0

Please sign in to comment.