feat(pong): made changes to allow local play

This commit is contained in:
Maieul BOYER 2026-01-04 14:58:20 +01:00 committed by Maix0
parent 9947970f63
commit 4ec44420db
5 changed files with 66 additions and 11 deletions

View file

@ -119,6 +119,13 @@ export class Pong {
public ball: Ball = new Ball(Pong.GAME_WIDTH / 2, Pong.GAME_HEIGHT / 2, Pong.BALL_START_ANGLES[this.ballAngleIdx++]);
public score: [number, number] = [0, 0];
public local: boolean = false;
public static makeLocal(owner: UserId): Pong {
const game = new Pong(owner, owner);
game.local = true;
return game;
}
constructor(
public userLeft: UserId,
@ -202,13 +209,14 @@ export class Pong {
return null;
}
public movePaddle(user: UserId, dir: 'up' | 'down') {
const paddle =
user === this.userLeft
? this.leftPaddle
: user == this.userRight
? this.rightPaddle
: null;
public movePaddle(user: UserId | ('left' | 'right'), dir: 'up' | 'down') {
let paddle: Paddle | null = null;
if (this.local) {
if (user === 'left') { paddle = this.leftPaddle; }
else if (user === 'right') { paddle = this.rightPaddle; }
}
else if (user === this.userLeft) { paddle = this.leftPaddle; }
else if (user === this.userRight) { paddle = this.rightPaddle; }
if (paddle === null) return;
paddle.move(dir);
paddle.clamp(0, Pong.GAME_HEIGHT);

View file

@ -20,10 +20,13 @@ export type GameUpdate = {
right: { id: string, paddle: PaddleData, score: number };
ball: { x: number, y: number, size: number };
local: boolean,
}
export type GameMove = {
move: 'up' | 'down' | null,
// only used in local games
moveRight: 'up' | 'down' | null,
}
export interface ClientToServer {
@ -32,6 +35,7 @@ export interface ClientToServer {
debugInfo: () => void;
gameMove: (up: GameMove) => void;
connectedToGame: (gameId: string) => void;
localGame: () => void,
};
export interface ServerToClient {

View file

@ -34,6 +34,7 @@ class StateI {
left: { id: g.userLeft, score: g.score[0], paddle: { x: g.leftPaddle.x, y: g.leftPaddle.y, width: g.leftPaddle.width, height: g.leftPaddle.height } },
right: { id: g.userRight, score: g.score[1], paddle: { x: g.rightPaddle.x, y: g.rightPaddle.y, width: g.rightPaddle.width, height: g.rightPaddle.height } },
ball: { x: g.ball.x, y: g.ball.y, size: g.ball.size },
local: g.local,
};
}
@ -76,6 +77,27 @@ class StateI {
}
}
private newLocalGame(sock: SSocket) {
const user = this.users.get(sock.authUser.id);
if (!user) return;
const gameId = newUUID() as unknown as GameId;
const g = Pong.makeLocal(user.id);
const iState: GameUpdate = StateI.getGameUpdateData(gameId, g);
user.socket.emit('newGame', iState);
this.games.set(gameId, g);
user.currentGame = gameId;
g.gameUpdate = setInterval(() => {
g.tick();
this.gameUpdate(gameId, user.socket);
if (g.checkWinner() !== null) { this.cleanupGame(gameId, g); }
}, 1000 / StateI.UPDATE_INTERVAL_FRAMES);
}
private gameUpdate(id: GameId, sock: SSocket) {
// does the game we want to update the client exists ?
if (!this.games.has(id)) return;
@ -94,7 +116,11 @@ class StateI {
if (user.currentGame === null || !this.games.has(user.currentGame)) return;
const game = this.games.get(user.currentGame)!;
if (u.move !== null) { game.movePaddle(user.id, u.move); }
if (game.local) {
if (u.move !== null) { game.movePaddle('left', u.move); }
if (u.moveRight !== null) { game.movePaddle('right', u.moveRight); }
}
else if (u.move !== null) { game.movePaddle(user.id, u.move); }
}
@ -119,6 +145,7 @@ class StateI {
socket.on('dequeue', () => this.dequeueUser(socket));
socket.on('gameMove', (e) => this.gameMove(socket, e));
socket.on('localGame', () => this.newLocalGame(socket));
}
private updateClient(socket: SSocket): void {