diff --git a/frontend/src/pages/pong/pong.ts b/frontend/src/pages/pong/pong.ts
index bbb47de..b58136b 100644
--- a/frontend/src/pages/pong/pong.ts
+++ b/frontend/src/pages/pong/pong.ts
@@ -24,6 +24,11 @@ enum QueueState {
In_local = "In Local",
};
+enum ReadyState {
+ readyUp = "ready up?",
+ readyDown = "ready down",
+};
+
document.addEventListener("ft:pageChange", (newUrl) => {
if (newUrl.detail.startsWith('/app/pong') || newUrl.detail.startsWith('/pong')) return;
if (window.__state.pongSock !== undefined) window.__state.pongSock.close();
@@ -49,6 +54,7 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
const user = getUser();
let currentGame: GameUpdate | null = null;
let opponent: User | null = null;
+ const rdy_btn = document.querySelector
('#readyup-btn');
const batLeft = document.querySelector("#batleft");
const batRight = document.querySelector("#batright");
const ball = document.querySelector("#ball");
@@ -66,7 +72,7 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
navigateTo("/app");
return ;
}
- if (!batLeft || !batRight || !ball || !score || !queueBtn || !playerL || !playerR || !gameBoard || !queue_infos || !LocalGameBtn) // sanity check
+ if (!batLeft || !batRight || !ball || !score || !queueBtn || !playerL || !playerR || !gameBoard || !queue_infos || !LocalGameBtn || !rdy_btn) // sanity check
return showError('fatal error');
// ---
@@ -112,6 +118,18 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
local:false
};
+ function resetBoard(batLeft : HTMLDivElement, batRight : HTMLDivElement, playerL : HTMLDivElement, playerR : HTMLDivElement) {
+ render(DEFAULT_POSITIONS);
+ batLeft.style.backgroundColor = DEFAULT_COLOR;
+ batRight.style.backgroundColor = DEFAULT_COLOR;
+ playerR.style.color = "";
+ playerL.style.color = "";
+ playerR.innerText = "";
+ playerL.innerText = "";
+ currentGame = null;
+ opponent = null;
+ }
+
const render = (state: GameUpdate) => {
currentGame = state;
batLeft.style.top = `${state.left.paddle.y}px`;
@@ -130,7 +148,10 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
score.innerText = `${state.left.score} | ${state.right.score}`
}
- socket.on('gameUpdate', (state: GameUpdate) => render(state));
+ socket.on('gameUpdate', (state: GameUpdate) => {
+ // if (rdy_btn)
+ // rdy_btn.classList.add('hidden');
+ render(state);});
// ---
// position logic (client) end
// ---
@@ -138,35 +159,13 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
// ---
// queue evt
// ---
+ // utils
function set_pretty(batU : HTMLDivElement, txtU : HTMLDivElement, txtO : HTMLDivElement, colorYou : string) {
batU.style.backgroundColor = colorYou;
txtU.style.color = colorYou;
txtU.innerText = isNullish(user) ? "you" : user.name;
txtO.innerText = isNullish(opponent) ? "the mechant" : opponent.name;
}
- queueBtn.addEventListener("click", ()=>{
- if (queueBtn.innerText !== QueueState.Iddle) {
- if (queueBtn.innerText === QueueState.InQueu) {
- socket.emit("dequeue");
- queueBtn.innerText = QueueState.Iddle;
- }
- return ;
- }
- queueBtn.innerText = QueueState.InQueu;
- socket.emit('enqueue');
- });
-
- LocalGameBtn.addEventListener("click", () => {
- if (queueBtn.innerText !== QueueState.Iddle || currentGame !== null) {
- showError("cant launch a local game while in queue/in game");
- return ;
- }
- socket.emit("localGame");
- queueBtn.innerText = QueueState.In_local;
- LocalGameBtn.innerText = "playing";
- });
-
-
async function get_opponent(opponent_id : string) {
let t = await client.getUser({user:opponent_id});
@@ -178,10 +177,50 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
opponent = null;
}
}
-
+
+ // btn setup
+ queueBtn.addEventListener("click", ()=>{
+ if (queueBtn.innerText !== QueueState.Iddle) {
+ if (queueBtn.innerText === QueueState.InQueu) {
+ socket.emit("dequeue");
+ queueBtn.innerText = QueueState.Iddle;
+ }
+ return ;
+ }
+ queueBtn.innerText = QueueState.InQueu;
+ socket.emit('enqueue');
+ });
+ LocalGameBtn.addEventListener("click", () => {
+ if (queueBtn.innerText !== QueueState.Iddle || currentGame !== null) {
+ showError("cant launch a local game while in queue/in game");
+ return ;
+ }
+ socket.emit("localGame");
+ queueBtn.innerText = QueueState.In_local;
+ LocalGameBtn.innerText = "playing";
+ });
+ rdy_btn.addEventListener("click", ()=>{
+ showInfo("rdy-evt");
+ switch (rdy_btn.innerText) {
+ case ReadyState.readyUp:
+ showInfo("sent:rdyup");
+ socket.emit('readyUp');
+ rdy_btn.innerText = ReadyState.readyDown;
+ break ;
+ case ReadyState.readyDown:
+ showInfo("sent:rdydwn");
+ socket.emit('readyDown');
+ rdy_btn.innerText = ReadyState.readyUp;
+ break ;
+ default:
+ showError("error on ready btn");
+ }
+
+ });
socket.on('newGame', async (state) => {
render(state);
+
await get_opponent(state.left.id == user.id ? state.right.id : state.left.id);
queueBtn.innerText = QueueState.InGame;
queueBtn.style.color = 'red';
@@ -193,7 +232,13 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
set_pretty(batRight, playerR, playerL, SELF_COLOR);
} else
showError("couldn't find your id in game");
- }); // TODO: notif user of new game w "ready up" btn
+
+ rdy_btn.classList.remove('hidden');
+ rdy_btn.innerText = ReadyState.readyUp;
+
+ setTimeout(() => {
+ rdy_btn.classList.add('hidden');}, 2000); // 1500 : pong.CONCEDED_TIMEOUT
+ });
socket.on("gameEnd", (winner) => {
queueBtn.innerHTML = QueueState.Iddle;
@@ -218,33 +263,24 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
LocalGameBtn.innerText = "Local Game"
}
}
- render(DEFAULT_POSITIONS);
- batLeft.style.backgroundColor = DEFAULT_COLOR;
- batRight.style.backgroundColor = DEFAULT_COLOR;
- playerR.style.color = "";
- playerL.style.color = "";
- playerR.innerText = "";
- playerL.innerText = "";
- currentGame = null;
- opponent = null;
+ resetBoard(batLeft, batRight, playerL, playerR);
})
- // ---
- // queue evt end
- // ---
-
- queueBtn.innerText = QueueState.Iddle;
- render(DEFAULT_POSITIONS);
- currentGame = null;
- batLeft.style.backgroundColor = DEFAULT_COLOR;
- batRight.style.backgroundColor = DEFAULT_COLOR;
-
+ // pretty info for queue :3
socket.on('updateInformation', (e) => {
queue_infos.innerText = `${e.totalUser}👤 ${e.inQueue}⏳ ${e.totalGames}▮•▮`;
});
socket.on('queueEvent', (e) => showInfo(`QueueEvent: ${e}`));
+ // ---
+ // queue evt end
+ // ---
+
+ // init
+ rdy_btn.classList.add('hidden');
+ queueBtn.innerText = QueueState.Iddle;
+ rdy_btn.innerText = ReadyState.readyUp;
+ resetBoard(batLeft, batRight, playerL, playerR);
showInfo("butter");
showInfo("butter-toast");
- // socket.emit('localGame');
}
}
};
diff --git a/src/pong/src/game.ts b/src/pong/src/game.ts
index 8fd2a60..ad78741 100644
--- a/src/pong/src/game.ts
+++ b/src/pong/src/game.ts
@@ -1,5 +1,7 @@
import { UserId } from '@shared/database/mixin/user';
+
+
export class Paddle {
public static readonly DEFAULT_SPEED = 10;
public static readonly DEFAULT_HEIGHT = 80;
@@ -94,8 +96,16 @@ function makeAngle(i: number): [number, number, number, number] {
-Math.PI / i + Math.PI,
];
}
+const LEFT :number = 0;
+const RIGHT :number = 1;
+enum ReadyState {
+ noState,
+ readyUp,
+ readyDown,
+}
export class Pong {
+
public gameUpdate: NodeJS.Timeout | null = null;
public static readonly CONCEDED_TIMEOUT: number = 1500;
@@ -126,6 +136,8 @@ export class Pong {
Pong.BALL_START_ANGLES[this.ballAngleIdx++],
);
+ public ready_checks: [ReadyState, ReadyState] = [ReadyState.noState, ReadyState.noState];
+
public score: [number, number] = [0, 0];
public local: boolean = false;
@@ -145,7 +157,44 @@ export class Pong {
public userRight: UserId,
) { }
+ public readyup(uid : UserId)
+ {
+ // debug
+ console.log(this.userLeft + " | " + this.userRight);
+ if (uid === this.userLeft) {
+ console.log("rdy.up : lft " + uid);
+ } else if (uid === this.userRight) {
+ console.log("rdy.up : rgt " + uid);
+ }
+
+ if (uid === this.userLeft) {
+ this.ready_checks[LEFT] = ReadyState.readyUp;
+ } else if (uid === this.userRight) {
+ this.ready_checks[RIGHT] = ReadyState.readyUp;
+ }
+ }
+ public readydown(uid : UserId)
+ {
+ // debug
+ console.log(this.userLeft + " | " + this.userRight);
+ if (uid === this.userLeft) {
+ console.log("rdy.down : lft " + uid);
+ } else if (uid === this.userRight) {
+ console.log("rdy.down : rgt " + uid);
+ }
+
+ // is everyone already ready?
+ if (this.ready_checks[LEFT] === ReadyState.readyUp && this.ready_checks[RIGHT] === ReadyState.readyUp) return ;
+
+ if (uid === this.userLeft)
+ this.ready_checks[LEFT] = ReadyState.readyDown;
+ else if (uid === this.userRight)
+ this.ready_checks[RIGHT] = ReadyState.readyDown;
+ }
+
public tick() {
+ if (this.ready_checks[LEFT] !== ReadyState.readyUp || this.ready_checks[RIGHT] !== ReadyState.readyUp)
+ return;
if (this.paddleCollision(this.leftPaddle, 'left')) {
this.ball.collided(
'left',
@@ -254,8 +303,8 @@ export class Pong {
public checkWinner(): 'left' | 'right' | null {
const checkInner = () => {
- if (this.score[0] >= 5) return 'left';
- if (this.score[1] >= 5) return 'right';
+ if (this.score[LEFT] >= 5) return 'left';
+ if (this.score[RIGHT] >= 5) return 'right';
if (
this.leftLastSeen !== -1 &&
diff --git a/src/pong/src/state.ts b/src/pong/src/state.ts
index cf7d4e5..2d44096 100644
--- a/src/pong/src/state.ts
+++ b/src/pong/src/state.ts
@@ -69,11 +69,10 @@ class StateI {
u1.currentGame = gameId;
u2.currentGame = gameId;
- // ---
- // wait for ready up
- // ---
-
g.gameUpdate = setInterval(() => {
+ // ---
+ // wait for ready up
+ // ---
g.tick();
this.gameUpdate(gameId, u1.socket);
this.gameUpdate(gameId, u2.socket);
@@ -152,6 +151,9 @@ class StateI {
socket.on('enqueue', () => this.enqueueUser(socket));
socket.on('dequeue', () => this.dequeueUser(socket));
+ socket.on('readyUp', () => this.readyupUser(socket));
+ socket.on('readyDown', () => this.readydownUser(socket));
+
socket.on('gameMove', (e) => this.gameMove(socket, e));
socket.on('localGame', () => this.newLocalGame(socket));
}
@@ -215,6 +217,27 @@ class StateI {
socket.emit('queueEvent', 'unregistered');
}
+ private readydownUser(socket: SSocket) : void { //
+ // do we know this user ?
+ if (!this.users.has(socket.authUser.id)) return;
+ const user = this.users.get(socket.authUser.id)!;
+ // does the user have a game and do we know such game ?
+ if (user.currentGame === null || !this.games.has(user.currentGame)) return;
+ const game = this.games.get(user.currentGame)!;
+ // is this a local game?
+ if (game.local === true) return;
+ game.readydown(user.id);
+ }
+ private readyupUser(socket: SSocket) : void { //
+ // do we know this user ?
+ if (!this.users.has(socket.authUser.id)) return;
+ const user = this.users.get(socket.authUser.id)!;
+ // does the user have a game and do we know such game ?
+ if (user.currentGame === null || !this.games.has(user.currentGame)) return;
+ const game = this.games.get(user.currentGame)!;
+ if (game.local === true) return;
+ game.readyup(user.id);
+ }
}