feat(pong): detect when the client hasnt sent anything in X secs
This commit is contained in:
parent
613bb31100
commit
8eac0a0d4e
5 changed files with 61 additions and 13 deletions
|
|
@ -194,15 +194,15 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
showError("couldn't find your id in game");
|
||||
}); // TODO: notif user of new game w "ready up" btn
|
||||
|
||||
socket.on("gameEnd", () => {
|
||||
socket.on("gameEnd", (winner) => {
|
||||
queueBtn.innerHTML = QueueState.Iddle;
|
||||
queueBtn.style.color = 'white';
|
||||
|
||||
if (!isNullish(currentGame)) {
|
||||
let new_div = document.createElement('div');
|
||||
let end_txt = "";
|
||||
if ((user.id === currentGame.left.id && currentGame.left.score > currentGame.right.score) ||
|
||||
(user.id === currentGame.right.id && currentGame.right.score > currentGame.left.score))
|
||||
if ((user.id === currentGame.left.id && winner === 'left') ||
|
||||
(user.id === currentGame.right.id && winner === 'right'))
|
||||
end_txt = 'won! #yippe';
|
||||
else
|
||||
end_txt = 'lost #sadge';
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export interface ServerToClient {
|
|||
updateInformation: (info: UpdateInfo) => void,
|
||||
newGame: (initState: GameUpdate) => void, // <- consider this the gameProc eg not start of game but wait for client to "ready up"
|
||||
gameUpdate: (state: GameUpdate) => void,
|
||||
gameEnd: () => void;
|
||||
gameEnd: (winner: 'left' | 'right') => void;
|
||||
};
|
||||
|
||||
export type SSocket = Socket<ClientToServer, ServerToClient>;
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ function makeAngle(i: number): [number, number, number, number] {
|
|||
export class Pong {
|
||||
public gameUpdate: NodeJS.Timeout | null = null;
|
||||
|
||||
public static readonly CONCEDED_TIMEOUT: number = 1500;
|
||||
|
||||
public static readonly BALL_START_ANGLES: number[] = [
|
||||
...makeAngle(4),
|
||||
...makeAngle(6),
|
||||
|
|
@ -127,6 +129,11 @@ export class Pong {
|
|||
public score: [number, number] = [0, 0];
|
||||
public local: boolean = false;
|
||||
|
||||
public rightLastSeen: number = -1;
|
||||
public leftLastSeen: number = -1;
|
||||
|
||||
private cachedWinner: 'left' | 'right' | null = null;
|
||||
|
||||
public static makeLocal(owner: UserId): Pong {
|
||||
const game = new Pong(owner, owner);
|
||||
game.local = true;
|
||||
|
|
@ -200,7 +207,9 @@ export class Pong {
|
|||
if (
|
||||
(Math.abs(this.ball.angle) > Math.PI / 2 && side !== 'left') ||
|
||||
(Math.abs(this.ball.angle) < Math.PI / 2 && side !== 'right')
|
||||
) {return false;}
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// now we check only if the ball is near enought in the y axis to permform the collision
|
||||
if (
|
||||
|
|
@ -212,7 +221,9 @@ export class Pong {
|
|||
this.ball.y < paddle.y + paddle.height + this.ball.size
|
||||
)
|
||||
)
|
||||
) {return false;}
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// so we know that the y is close enougth to be a bit, so we check the X. are we closer than the ball size ? if yes -> hit
|
||||
if (
|
||||
|
|
@ -222,14 +233,49 @@ export class Pong {
|
|||
paddle.width * (side === 'left' ? 1 : 0) -
|
||||
this.ball.x,
|
||||
) < this.ball.size
|
||||
) {return true;}
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public updateLastSeen(user: UserId) {
|
||||
if (this.local && this.userLeft === user) {
|
||||
this.leftLastSeen = Date.now();
|
||||
this.rightLastSeen = Date.now();
|
||||
}
|
||||
else if (this.userLeft === user) {
|
||||
this.leftLastSeen = Date.now();
|
||||
}
|
||||
else if (this.userRight === user) {
|
||||
this.rightLastSeen = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
public checkWinner(): 'left' | 'right' | null {
|
||||
const checkInner = () => {
|
||||
if (this.score[0] >= 5) return 'left';
|
||||
if (this.score[1] >= 5) return 'right';
|
||||
|
||||
if (
|
||||
this.leftLastSeen !== -1 &&
|
||||
Date.now() - this.leftLastSeen > Pong.CONCEDED_TIMEOUT
|
||||
) {
|
||||
return 'right';
|
||||
}
|
||||
if (
|
||||
this.rightLastSeen !== -1 &&
|
||||
Date.now() - this.rightLastSeen > Pong.CONCEDED_TIMEOUT
|
||||
) {
|
||||
return 'left';
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
if (this.cachedWinner === null) {
|
||||
this.cachedWinner = checkInner();
|
||||
}
|
||||
return this.cachedWinner;
|
||||
}
|
||||
|
||||
public movePaddle(user: UserId | ('left' | 'right'), dir: 'up' | 'down') {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export interface ServerToClient {
|
|||
updateInformation: (info: UpdateInfo) => void,
|
||||
newGame: (initState: GameUpdate) => void,
|
||||
gameUpdate: (state: GameUpdate) => void,
|
||||
gameEnd: () => void;
|
||||
gameEnd: (winner: 'left' | 'right') => void;
|
||||
};
|
||||
|
||||
export type SSocket = Socket<ClientToServer, ServerToClient>;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ class StateI {
|
|||
if (u.moveRight !== null) { game.movePaddle('right', u.moveRight); }
|
||||
}
|
||||
else if (u.move !== null) { game.movePaddle(user.id, u.move); }
|
||||
game.updateLastSeen(user.id);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -174,14 +175,15 @@ class StateI {
|
|||
private cleanupGame(gameId: GameId, game: Pong): void {
|
||||
clearInterval(game.gameUpdate ?? undefined);
|
||||
this.games.delete(gameId);
|
||||
const winner = game.checkWinner() ?? 'left';
|
||||
let player: PUser | undefined = undefined;
|
||||
if ((player = this.users.get(game.userLeft)) !== undefined) {
|
||||
player.currentGame = null;
|
||||
player.socket.emit('gameEnd');
|
||||
player.socket.emit('gameEnd', winner);
|
||||
}
|
||||
if ((player = this.users.get(game.userRight)) !== undefined) {
|
||||
player.currentGame = null;
|
||||
player.socket.emit('gameEnd');
|
||||
player.socket.emit('gameEnd', winner);
|
||||
}
|
||||
const rOutcome = game.checkWinner();
|
||||
let outcome: PongGameOutcome = 'other';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue