Skip to content

Commit

Permalink
Refactor viewer mode (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
takumihara authored Dec 20, 2023
1 parent 33479a9 commit f4b0a38
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 25 deletions.
22 changes: 22 additions & 0 deletions frontend/app/lib/hooks/useUserMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useCallback } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";

export type UserModeType = "viewer" | "player";

export function useUserMode(): [UserModeType, (mode: UserModeType) => void] {
const pathname = usePathname();
const { replace } = useRouter();
const searchParams = useSearchParams();
const userMode = searchParams.get("mode") == "player" ? "player" : "viewer";

const setUserMode = useCallback(
(mode: UserModeType) => {
const params = new URLSearchParams(searchParams);
params.set("mode", mode);
replace(`${pathname}?${params.toString()}`);
},
[searchParams, pathname, replace],
);

return [userMode, setUserMode];
}
40 changes: 25 additions & 15 deletions frontend/app/pong/[id]/PongBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { io } from "socket.io-client";
import type { Socket } from "socket.io-client";
import PongInformationBoard from "./PongInformationBoard";
import { useTheme } from "next-themes";
import { useSearchParams } from "next/navigation";
import { useUserMode } from "@/app/lib/hooks/useUserMode";

type setState<T> = T | ((prevState: T) => T);

Expand All @@ -34,12 +34,13 @@ interface HandleActionProps {

const POINT_TO_WIN = 3;

function PongBoard({ id: id }: PongBoardProps) {
function PongBoard({ id }: PongBoardProps) {
const [fps, setFps] = useStateCallback<number>(0);
const [speed, setSpeed] = useStateCallback<number>(0);
const [player1Position, setPlayer1Position] = useStateCallback<number>(0);
const [player2Position, setPlayer2Position] = useStateCallback<number>(0);
const [logs, setLogs] = useStateCallback<string[]>([]);
const [userMode, setUserMode] = useUserMode();

const canvasRef = useRef<HTMLCanvasElement | null>(null); // only initialized once
const gameRef = useRef<PongGame | null>(null); // only initialized once
Expand All @@ -49,8 +50,6 @@ function PongBoard({ id: id }: PongBoardProps) {
const [battleDisabled] = useState(true);
const { resolvedTheme } = useTheme();
const defaultColor = "hsl(0, 0%, 0%)";
const searchParams = useSearchParams();
const isPlayer = searchParams.get("mode") == "player";

const getGame = useCallback(() => {
const ctx = canvasRef.current?.getContext("2d");
Expand All @@ -66,16 +65,16 @@ function PongBoard({ id: id }: PongBoardProps) {
setPlayer2Position,
defaultColor,
defaultColor,
isPlayer,
userMode,
);
gameRef.current = game;
return game;
}
return gameRef.current;
}, [setFps, setSpeed, setPlayer1Position, setPlayer2Position, isPlayer]);
}, [setFps, setSpeed, setPlayer1Position, setPlayer2Position, userMode]);

const start = useCallback(() => {
if (!isPlayer) return;
if (!userMode) return;
const game = getGame();

setStartDisabled(true);
Expand All @@ -85,7 +84,12 @@ function PongBoard({ id: id }: PongBoardProps) {
vx: -vx,
vy: -vy,
});
}, [getGame, isPlayer]);
}, [getGame, userMode]);

useEffect(() => {
const game = getGame();
game.setUserMode(userMode);
}, [getGame, userMode]);

useEffect(() => {
// TODO: Use --foreground color from CSS
Expand Down Expand Up @@ -130,7 +134,9 @@ function PongBoard({ id: id }: PongBoardProps) {
}, [getGame]);

useEffect(() => {
const socket = io("/pong", { query: { game_id: id, is_player: isPlayer } });
const socket = io("/pong", {
query: { game_id: id, is_player: userMode === "player" },
});
socketRef.current = socket;

const game = getGame();
Expand All @@ -139,6 +145,10 @@ function PongBoard({ id: id }: PongBoardProps) {
};

const handleLog = (log: string) => {
// TODO
if (log == "The game is full. You joined as a viewer.") {
setUserMode("viewer");
}
setLogs((logs) => [...logs, log]);
};
const handleConnect = () => {
Expand All @@ -154,23 +164,23 @@ function PongBoard({ id: id }: PongBoardProps) {
};

const handleRight = ({ playerNumber }: HandleActionProps) => {
if (!isPlayer && playerNumber == 1) {
if (userMode !== "player" && playerNumber == 1) {
game.movePlayer1Left();
} else {
game.movePlayer2Left();
}
};

const handleLeft = ({ playerNumber }: HandleActionProps) => {
if (!isPlayer && playerNumber == 1) {
if (userMode !== "player" && playerNumber == 1) {
game.movePlayer1Right();
} else {
game.movePlayer2Right();
}
};

const handleBounce = ({ playerNumber }: HandleActionProps) => {
if (!isPlayer && playerNumber == 1) {
if (userMode !== "player" && playerNumber == 1) {
game.bounceOffPaddlePlayer1();
} else {
game.bounceOffPaddlePlayer2();
Expand All @@ -180,7 +190,7 @@ function PongBoard({ id: id }: PongBoardProps) {
const handleCollide = (msg: HandleActionProps) => {
const { playerNumber } = msg;
console.log(msg);
if (isPlayer) {
if (userMode === "player") {
const score = game.increaseScorePlayer1();
if (score != POINT_TO_WIN) {
setTimeout(() => start(), 1000);
Expand Down Expand Up @@ -241,7 +251,7 @@ function PongBoard({ id: id }: PongBoardProps) {
socket.off("finish", handleFinish);
socket.disconnect();
};
}, [id, getGame, setLogs, start, isPlayer]);
}, [id, getGame, setLogs, start, userMode, setUserMode]);

return (
<div className="overflow-hidden flex-grow flex gap-8 pb-8">
Expand Down Expand Up @@ -275,7 +285,7 @@ function PongBoard({ id: id }: PongBoardProps) {
player1Position={player1Position}
player2Position={player2Position}
logs={logs}
isPlayer={isPlayer}
userMode={userMode}
/>
</div>
</div>
Expand Down
17 changes: 11 additions & 6 deletions frontend/app/pong/[id]/PongGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type setFunction<T> = (value: T | ((prevState: T) => T)) => void;
type movingDirectionType = "none" | "left" | "right";
type onActionType = (action: string) => void;
type userModeType = "player" | "viewer";

export class PongGame {
private ctx: CanvasRenderingContext2D;
Expand All @@ -34,7 +35,7 @@ export class PongGame {
onAction: onActionType | undefined;
private paddleColor: string;
private ballColor: string;
private isPlayer: boolean;
private userMode: userModeType;

constructor(
ctx: CanvasRenderingContext2D,
Expand All @@ -44,7 +45,7 @@ export class PongGame {
setPlayer2Position: setFunction<number>,
paddleColor: string,
ballColor: string,
isPlayer: boolean,
userMode: userModeType,
) {
this.ctx = ctx;
this.ctx.textAlign = "center";
Expand Down Expand Up @@ -78,7 +79,7 @@ export class PongGame {
this.setSpeed = setSpeed;
this.setPlayer1Position = setPlayer1Position;
this.setPlayer2Position = setPlayer2Position;
this.isPlayer = isPlayer;
this.userMode = userMode;
}

update_fps = () => {
Expand Down Expand Up @@ -113,12 +114,12 @@ export class PongGame {
// Draw objects
this.ball.move(this.elapsed);
if (this.player1.collide_with(this.ball)) {
if (this.isPlayer) {
if (this.userMode === "player") {
this.ball.bounce_off_paddle(this.player1);
this.onAction && this.onAction("bounce");
}
} else if (this.ball.y + this.ball.radius * 2 >= CANVAS_HEIGHT) {
if (this.isPlayer) {
if (this.userMode === "player") {
this.ball.reset();
this.score.player2++;
this.onAction && this.onAction("collide");
Expand Down Expand Up @@ -148,7 +149,7 @@ export class PongGame {
this.update_fps();
this.update_speed(this.ball.speed());
this.update_players();
if (this.isPlayer) {
if (this.userMode === "player") {
if (this.movingDirection === "left") {
this.player1.clear(this.ctx);
this.player1.move_left();
Expand Down Expand Up @@ -300,4 +301,8 @@ export class PongGame {
this.player1.color = color;
this.player2.color = color;
}

setUserMode(userMode: userModeType) {
this.userMode = userMode;
}
}
6 changes: 3 additions & 3 deletions frontend/app/pong/[id]/PongInformationBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface PongInformationBoardProps {
player1Position: number;
player2Position: number;
logs: string[];
isPlayer: boolean;
userMode: "viewer" | "player";
}

export default function PongInformationBoard({
Expand All @@ -15,11 +15,11 @@ export default function PongInformationBoard({
player1Position,
player2Position,
logs,
isPlayer,
userMode,
}: PongInformationBoardProps) {
return (
<div className="overflow-hidden flex-grow flex flex-col gap-1">
<div>You are a {isPlayer ? "player" : "viewer"}</div>
<div>You are a {userMode}</div>
<div id="fps">FPS: {fps}</div>
<div id="speed">Speed: {speed}</div>
<div>
Expand Down
1 change: 0 additions & 1 deletion frontend/app/pong/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
"use client";
import PongBoard from "./PongBoard";

export default function Page({ params: { id } }: { params: { id: string } }) {
Expand Down

0 comments on commit f4b0a38

Please sign in to comment.