[wip] - frontend meh/20 back-end meh/20 still, works. works badly but does work...
This commit is contained in:
parent
f87a991441
commit
572392f640
5 changed files with 176 additions and 53 deletions
|
|
@ -141,4 +141,16 @@
|
||||||
text-black
|
text-black
|
||||||
text-center
|
text-center
|
||||||
bg-white
|
bg-white
|
||||||
|
z-50
|
||||||
|
}
|
||||||
|
|
||||||
|
.pong-rdy-screen {
|
||||||
|
@apply
|
||||||
|
rounded-2xl
|
||||||
|
absolute
|
||||||
|
justify-center
|
||||||
|
text-black
|
||||||
|
text-center
|
||||||
|
bg-white
|
||||||
|
z-50
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
Pong Box<span id="t-username"></span>
|
Pong Box<span id="t-username"></span>
|
||||||
</h1><br>
|
</h1><br>
|
||||||
|
|
||||||
|
<!-- todo: print keys for moving -->
|
||||||
|
|
||||||
<!-- Horizontal Message Box -->
|
<!-- Horizontal Message Box -->
|
||||||
<div id="score-box" class="grid grid-cols-[1fr_auto_1fr] items-center">
|
<div id="score-box" class="grid grid-cols-[1fr_auto_1fr] items-center">
|
||||||
<h1 id="player-left"></h1>
|
<h1 id="player-left"></h1>
|
||||||
|
|
@ -18,6 +20,7 @@
|
||||||
<div class="flex justify-center mt-2">
|
<div class="flex justify-center mt-2">
|
||||||
<div id="pongspace" class="flex flex-col">
|
<div id="pongspace" class="flex flex-col">
|
||||||
<div id="pongbox" class="pongbox-style">
|
<div id="pongbox" class="pongbox-style">
|
||||||
|
<button class="pong-rdy-screen" id="readyup-btn">ready!</button>
|
||||||
<div class="pong-field">
|
<div class="pong-field">
|
||||||
<div id="batleft" class="pong-batleft top-0"></div>
|
<div id="batleft" class="pong-batleft top-0"></div>
|
||||||
<div class="pong-center-line"></div>
|
<div class="pong-center-line"></div>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,11 @@ enum QueueState {
|
||||||
In_local = "In Local",
|
In_local = "In Local",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ReadyState {
|
||||||
|
readyUp = "ready up?",
|
||||||
|
readyDown = "ready down",
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener("ft:pageChange", (newUrl) => {
|
document.addEventListener("ft:pageChange", (newUrl) => {
|
||||||
if (newUrl.detail.startsWith('/app/pong') || newUrl.detail.startsWith('/pong')) return;
|
if (newUrl.detail.startsWith('/app/pong') || newUrl.detail.startsWith('/pong')) return;
|
||||||
if (window.__state.pongSock !== undefined) window.__state.pongSock.close();
|
if (window.__state.pongSock !== undefined) window.__state.pongSock.close();
|
||||||
|
|
@ -49,6 +54,7 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
const user = getUser();
|
const user = getUser();
|
||||||
let currentGame: GameUpdate | null = null;
|
let currentGame: GameUpdate | null = null;
|
||||||
let opponent: User | null = null;
|
let opponent: User | null = null;
|
||||||
|
const rdy_btn = document.querySelector<HTMLButtonElement>('#readyup-btn');
|
||||||
const batLeft = document.querySelector<HTMLDivElement>("#batleft");
|
const batLeft = document.querySelector<HTMLDivElement>("#batleft");
|
||||||
const batRight = document.querySelector<HTMLDivElement>("#batright");
|
const batRight = document.querySelector<HTMLDivElement>("#batright");
|
||||||
const ball = document.querySelector<HTMLDivElement>("#ball");
|
const ball = document.querySelector<HTMLDivElement>("#ball");
|
||||||
|
|
@ -66,7 +72,7 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
navigateTo("/app");
|
navigateTo("/app");
|
||||||
return ;
|
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');
|
return showError('fatal error');
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
@ -112,6 +118,18 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
local:false
|
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) => {
|
const render = (state: GameUpdate) => {
|
||||||
currentGame = state;
|
currentGame = state;
|
||||||
batLeft.style.top = `${state.left.paddle.y}px`;
|
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}`
|
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
|
// position logic (client) end
|
||||||
// ---
|
// ---
|
||||||
|
|
@ -138,35 +159,13 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
// ---
|
// ---
|
||||||
// queue evt
|
// queue evt
|
||||||
// ---
|
// ---
|
||||||
|
// utils
|
||||||
function set_pretty(batU : HTMLDivElement, txtU : HTMLDivElement, txtO : HTMLDivElement, colorYou : string) {
|
function set_pretty(batU : HTMLDivElement, txtU : HTMLDivElement, txtO : HTMLDivElement, colorYou : string) {
|
||||||
batU.style.backgroundColor = colorYou;
|
batU.style.backgroundColor = colorYou;
|
||||||
txtU.style.color = colorYou;
|
txtU.style.color = colorYou;
|
||||||
txtU.innerText = isNullish(user) ? "you" : user.name;
|
txtU.innerText = isNullish(user) ? "you" : user.name;
|
||||||
txtO.innerText = isNullish(opponent) ? "the mechant" : opponent.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) {
|
async function get_opponent(opponent_id : string) {
|
||||||
let t = await client.getUser({user:opponent_id});
|
let t = await client.getUser({user:opponent_id});
|
||||||
|
|
||||||
|
|
@ -178,10 +177,50 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
opponent = null;
|
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) => {
|
socket.on('newGame', async (state) => {
|
||||||
render(state);
|
render(state);
|
||||||
|
|
||||||
await get_opponent(state.left.id == user.id ? state.right.id : state.left.id);
|
await get_opponent(state.left.id == user.id ? state.right.id : state.left.id);
|
||||||
queueBtn.innerText = QueueState.InGame;
|
queueBtn.innerText = QueueState.InGame;
|
||||||
queueBtn.style.color = 'red';
|
queueBtn.style.color = 'red';
|
||||||
|
|
@ -193,7 +232,13 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
set_pretty(batRight, playerR, playerL, SELF_COLOR);
|
set_pretty(batRight, playerR, playerL, SELF_COLOR);
|
||||||
} else
|
} else
|
||||||
showError("couldn't find your id in game");
|
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) => {
|
socket.on("gameEnd", (winner) => {
|
||||||
queueBtn.innerHTML = QueueState.Iddle;
|
queueBtn.innerHTML = QueueState.Iddle;
|
||||||
|
|
@ -218,33 +263,24 @@ function pongClient(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
||||||
LocalGameBtn.innerText = "Local Game"
|
LocalGameBtn.innerText = "Local Game"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render(DEFAULT_POSITIONS);
|
resetBoard(batLeft, batRight, playerL, playerR);
|
||||||
batLeft.style.backgroundColor = DEFAULT_COLOR;
|
|
||||||
batRight.style.backgroundColor = DEFAULT_COLOR;
|
|
||||||
playerR.style.color = "";
|
|
||||||
playerL.style.color = "";
|
|
||||||
playerR.innerText = "";
|
|
||||||
playerL.innerText = "";
|
|
||||||
currentGame = null;
|
|
||||||
opponent = null;
|
|
||||||
})
|
})
|
||||||
// ---
|
// pretty info for queue :3
|
||||||
// queue evt end
|
|
||||||
// ---
|
|
||||||
|
|
||||||
queueBtn.innerText = QueueState.Iddle;
|
|
||||||
render(DEFAULT_POSITIONS);
|
|
||||||
currentGame = null;
|
|
||||||
batLeft.style.backgroundColor = DEFAULT_COLOR;
|
|
||||||
batRight.style.backgroundColor = DEFAULT_COLOR;
|
|
||||||
|
|
||||||
socket.on('updateInformation', (e) => {
|
socket.on('updateInformation', (e) => {
|
||||||
queue_infos.innerText = `${e.totalUser}👤 ${e.inQueue}⏳ ${e.totalGames}▮•▮`;
|
queue_infos.innerText = `${e.totalUser}👤 ${e.inQueue}⏳ ${e.totalGames}▮•▮`;
|
||||||
});
|
});
|
||||||
socket.on('queueEvent', (e) => showInfo(`QueueEvent: ${e}`));
|
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");
|
||||||
showInfo("butter-toast");
|
showInfo("butter-toast");
|
||||||
// socket.emit('localGame');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { UserId } from '@shared/database/mixin/user';
|
import { UserId } from '@shared/database/mixin/user';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Paddle {
|
export class Paddle {
|
||||||
public static readonly DEFAULT_SPEED = 10;
|
public static readonly DEFAULT_SPEED = 10;
|
||||||
public static readonly DEFAULT_HEIGHT = 80;
|
public static readonly DEFAULT_HEIGHT = 80;
|
||||||
|
|
@ -94,8 +96,16 @@ function makeAngle(i: number): [number, number, number, number] {
|
||||||
-Math.PI / i + Math.PI,
|
-Math.PI / i + Math.PI,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
const LEFT :number = 0;
|
||||||
|
const RIGHT :number = 1;
|
||||||
|
enum ReadyState {
|
||||||
|
noState,
|
||||||
|
readyUp,
|
||||||
|
readyDown,
|
||||||
|
}
|
||||||
|
|
||||||
export class Pong {
|
export class Pong {
|
||||||
|
|
||||||
public gameUpdate: NodeJS.Timeout | null = null;
|
public gameUpdate: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
public static readonly CONCEDED_TIMEOUT: number = 1500;
|
public static readonly CONCEDED_TIMEOUT: number = 1500;
|
||||||
|
|
@ -126,6 +136,8 @@ export class Pong {
|
||||||
Pong.BALL_START_ANGLES[this.ballAngleIdx++],
|
Pong.BALL_START_ANGLES[this.ballAngleIdx++],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public ready_checks: [ReadyState, ReadyState] = [ReadyState.noState, ReadyState.noState];
|
||||||
|
|
||||||
public score: [number, number] = [0, 0];
|
public score: [number, number] = [0, 0];
|
||||||
public local: boolean = false;
|
public local: boolean = false;
|
||||||
|
|
||||||
|
|
@ -145,7 +157,44 @@ export class Pong {
|
||||||
public userRight: UserId,
|
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() {
|
public tick() {
|
||||||
|
if (this.ready_checks[LEFT] !== ReadyState.readyUp || this.ready_checks[RIGHT] !== ReadyState.readyUp)
|
||||||
|
return;
|
||||||
if (this.paddleCollision(this.leftPaddle, 'left')) {
|
if (this.paddleCollision(this.leftPaddle, 'left')) {
|
||||||
this.ball.collided(
|
this.ball.collided(
|
||||||
'left',
|
'left',
|
||||||
|
|
@ -254,8 +303,8 @@ export class Pong {
|
||||||
|
|
||||||
public checkWinner(): 'left' | 'right' | null {
|
public checkWinner(): 'left' | 'right' | null {
|
||||||
const checkInner = () => {
|
const checkInner = () => {
|
||||||
if (this.score[0] >= 5) return 'left';
|
if (this.score[LEFT] >= 5) return 'left';
|
||||||
if (this.score[1] >= 5) return 'right';
|
if (this.score[RIGHT] >= 5) return 'right';
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.leftLastSeen !== -1 &&
|
this.leftLastSeen !== -1 &&
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,10 @@ class StateI {
|
||||||
u1.currentGame = gameId;
|
u1.currentGame = gameId;
|
||||||
u2.currentGame = gameId;
|
u2.currentGame = gameId;
|
||||||
|
|
||||||
// ---
|
|
||||||
// wait for ready up
|
|
||||||
// ---
|
|
||||||
|
|
||||||
g.gameUpdate = setInterval(() => {
|
g.gameUpdate = setInterval(() => {
|
||||||
|
// ---
|
||||||
|
// wait for ready up
|
||||||
|
// ---
|
||||||
g.tick();
|
g.tick();
|
||||||
this.gameUpdate(gameId, u1.socket);
|
this.gameUpdate(gameId, u1.socket);
|
||||||
this.gameUpdate(gameId, u2.socket);
|
this.gameUpdate(gameId, u2.socket);
|
||||||
|
|
@ -152,6 +151,9 @@ class StateI {
|
||||||
socket.on('enqueue', () => this.enqueueUser(socket));
|
socket.on('enqueue', () => this.enqueueUser(socket));
|
||||||
socket.on('dequeue', () => this.dequeueUser(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('gameMove', (e) => this.gameMove(socket, e));
|
||||||
socket.on('localGame', () => this.newLocalGame(socket));
|
socket.on('localGame', () => this.newLocalGame(socket));
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +217,27 @@ class StateI {
|
||||||
socket.emit('queueEvent', 'unregistered');
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue