Match abort if all players not ready in time (5s)

+ HTML Keys instructions
This commit is contained in:
LuckyLaszlo
2022-12-07 19:33:56 +01:00
parent 6985d2218f
commit d2cdc564ac
7 changed files with 139 additions and 98 deletions

View File

@@ -1,3 +1,12 @@
TODO:
- lors d'un newRound() verifier si tout les joueurs sont encore en ligne et stopper le match sinon
(victoire si encore un joueur en ligne, annulation du match si aucun joueur en ligne)
- mode spectateur
- certaines utilisations de Math.floor() superflu ? Vérifier les appels.
(éventuellement Math.round() ?)
- un autre mode de jeu alternatif ?
- changer les "localhost:8080" dans le code.
Done: Done:
- Connexion client/serveur via un Websocket - Connexion client/serveur via un Websocket
- implémentation basique (authoritative server) - implémentation basique (authoritative server)
@@ -16,30 +25,24 @@ Done:
- mode murs mouvant (la zone de jeu rétréci / agrandi en continu) - mode murs mouvant (la zone de jeu rétréci / agrandi en continu)
- Selection des modes de jeu via HTML - Selection des modes de jeu via HTML
- Selection audio on/off via HTML - Selection audio on/off via HTML
- Match Abort si tout les joueurs n'ont pas répondus assez vite (5 secondes)
TODO:
- Match Abort si tout les joueurs ne sont pas pret assez vite (~15 secondes)
- mode spectateur
- certaines utilisations de Math.floor() superflu ? Vérifier les appels.
(éventuellement Math.round() ?)
- un autre mode de jeu alternatif ?
- changer les "localhost:8080" dans le code.
- sélection couleur des raquettes (your color/opponent color) dans le profil utilisateur.
Enregistrement dans la DB.
init des couleurs dans GameComponentsClient() basé sur les variables de l'utilsateur connecté.
----------- -----------
idées modes de jeu : BUG:
- mode 2 raquettes (un joueur haut/gauche et bas/droite) - Si la balle va très vite, elle peut ignorer la collision avec une raquette ou mur.
- skin patate ??? la collision est testée seulement après le mouvement.
- (prediction de l'avancement de la balle basé sur la latence serveur ?) Pour éviter ce bug il faudrait diviser le mouvement pour faire plusieurs tests de collision successifs.
- d'autres sons (foule qui applaudi/musique de victoire) - Sur un changement de fenêtre, les touches restent enfoncées et il faut les "décoincer"
----------- en réappuyant. Ce n'est pas grave mais peut-on faire mieux ?
- BUG: Si la balle va très vite, elle peut ignorer la collision avec une raquette ou mur.
la collision est testée seulement après le mouvement.
Pour éviter ce bug il faudrait diviser le mouvement pour faire plusieurs tests de collision successifs.
- BUG mineur: sur un changement de fenêtre, les touches restent enfoncées et il faut les "décoincer"
en réappuyant. Ce n'est pas grave mais peut-on faire mieux ?
---------- ----------
OSEF, rebuts: OSEF, rebuts:
- reconnection - idées modes de jeu :
- amélioration du protocole, remplacement du JSON (compression. moins de bande passante). - mode 2 raquettes (un joueur haut/gauche et bas/droite)
- skin patate ???
- (prediction de l'avancement de la balle basé sur la latence serveur ?)
- d'autres sons (foule qui applaudi/musique de victoire)
- reconnection
- amélioration du protocole, remplacement du JSON (compression. moins de bande passante).
- sélection couleur des raquettes (your color/opponent color) dans le profil utilisateur.
Enregistrement dans la DB.
init des couleurs dans GameComponentsClient() basé sur les variables de l'utilsateur connecté.

View File

@@ -7,13 +7,6 @@
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
#preload_font {
font-family: "Bit5x3";
opacity:0;
height:0;
width:0;
display:inline-block;
}
body { body {
margin: 0; margin: 0;
background-color: #222425; background-color: #222425;
@@ -24,7 +17,14 @@ body {
/* max-height: 80vh; */ /* max-height: 80vh; */
/* overflow: hidden; */ /* overflow: hidden; */
} }
#div_game_instructions {
text-align: center;
font-family: "Bit5x3";
color: rgb(245, 245, 245);
font-size: large;
}
#div_game_options { #div_game_options {
margin-top: 20px;
text-align: center; text-align: center;
font-family: "Bit5x3"; font-family: "Bit5x3";
color: rgb(245, 245, 245); color: rgb(245, 245, 245);

View File

@@ -6,8 +6,6 @@
</head> </head>
<body> <body>
<div id="preload_font">.</div>
<div id="div_game_options"> <div id="div_game_options">
<fieldset> <fieldset>
<legend>game options</legend> <legend>game options</legend>
@@ -32,6 +30,13 @@
</fieldset> </fieldset>
</div> </div>
<div id="div_game_instructions">
<h2>--- keys ---</h2>
<p>move up: 'w' or 'up arrow'</p>
<p>move down: 's' OR 'down arrow'</p>
<p>grid on/off: 'g'</p>
</div>
<div id="canvas_container"> <div id="canvas_container">
<!-- <p> =) </p> --> <!-- <p> =) </p> -->
</div> </div>

View File

@@ -17,11 +17,6 @@ import { initWebSocket } from "./ws.js";
import { initAudio } from "./audio.js"; import { initAudio } from "./audio.js";
/* Keys
Racket: W/S OR Up/Down
Grid On-Off: G
*/
/* TODO: A way to delay the init of variables, but still use "const" not "let" ? */ /* TODO: A way to delay the init of variables, but still use "const" not "let" ? */
export let pong: GameArea; export let pong: GameArea;
export let gc: GameComponentsClient; export let gc: GameComponentsClient;
@@ -46,7 +41,8 @@ function init()
matchOptions |= en.MatchOptions.movingWalls; matchOptions |= en.MatchOptions.movingWalls;
} }
document.getElementById("div_game_options").hidden = true; document.getElementById("div_game_options").remove();
document.getElementById("div_game_instructions").remove();
pong = new GameArea(); pong = new GameArea();
gc = new GameComponentsClient(matchOptions, pong.ctx); gc = new GameComponentsClient(matchOptions, pong.ctx);
@@ -55,32 +51,52 @@ function init()
function matchmaking() function matchmaking()
{ {
console.log("Searching an opponent..."); const text = "searching...";
console.log(text);
gc.text1.clear(); gc.text1.clear();
gc.text1.pos.assign(c.w/5, c.h_mid); gc.text1.pos.assign(c.w*0.2, c.h*0.5);
gc.text1.text = "Searching..."; gc.text1.text = text;
gc.text1.update(); gc.text1.update();
} }
function matchmakingComplete() function matchmakingComplete()
{ {
console.log("Match Found !"); const text = "match found !";
console.log(text);
gc.text1.clear(); gc.text1.clear();
gc.text1.pos.assign(c.w/8, c.h_mid); gc.text1.pos.assign(c.w*0.15, c.h*0.5);
gc.text1.text = "Match Found !"; gc.text1.text = text;
gc.text1.update(); gc.text1.update();
} }
function startGame() { function matchAbort()
gc.text1.pos.assign(c.w_mid, c.h_mid+c.h/4); {
const text = "match abort";
console.log(text);
gc.text1.clear();
gc.text1.pos.assign(c.w*0.15, c.h*0.5);
gc.text1.text = text;
gc.text1.update();
gc.text1.pos.assign(c.w*0.44, c.h*0.6);
gc.text1.text = "sorry =(";
const oriSize = gc.text1.size;
gc.text1.size = gc.text1.size*0.2;
gc.text1.update();
gc.text1.size = oriSize;
}
function matchStart()
{
gc.text1.pos.assign(c.w*0.5, c.h*0.75);
countdown(c.matchStartDelay/1000, (count: number) => { countdown(c.matchStartDelay/1000, (count: number) => {
gc.text1.clear(); gc.text1.clear();
gc.text1.text = `${count}`; gc.text1.text = `${count}`;
gc.text1.update(); gc.text1.update();
}, resumeGame); }, matchResume);
} }
function resumeGame() function matchResume()
{ {
gc.text1.text = ""; gc.text1.text = "";
window.addEventListener('keydown', function (e) { window.addEventListener('keydown', function (e) {
@@ -96,4 +112,4 @@ function resumeGame()
} }
export {matchmaking, matchmakingComplete, startGame} export {matchmaking, matchmakingComplete, matchAbort, matchStart}

View File

@@ -3,7 +3,7 @@ import * as c from "./constants.js"
import { gc, matchOptions } from "./global.js" import { gc, matchOptions } from "./global.js"
import * as ev from "../shared_js/class/Event.js" import * as ev from "../shared_js/class/Event.js"
import * as en from "../shared_js/enums.js" import * as en from "../shared_js/enums.js"
import { matchmaking, matchmakingComplete, startGame } from "./pong.js"; import { matchmaking, matchmakingComplete, matchAbort, matchStart } from "./pong.js";
import { RacketClient } from "./class/RectangleClient.js"; import { RacketClient } from "./class/RectangleClient.js";
import { repeatInput } from "./handleInput.js"; import { repeatInput } from "./handleInput.js";
import { soundRoblox } from "./audio.js" import { soundRoblox } from "./audio.js"
@@ -67,7 +67,11 @@ function preMatchListener(this: WebSocket, event: MessageEvent)
case en.EventTypes.matchStart: case en.EventTypes.matchStart:
socket.removeEventListener("message", preMatchListener); socket.removeEventListener("message", preMatchListener);
socket.addEventListener("message", inGameListener); socket.addEventListener("message", inGameListener);
startGame(); matchStart();
break;
case en.EventTypes.matchAbort:
socket.removeEventListener("message", preMatchListener);
matchAbort();
break; break;
} }
} }

View File

@@ -129,6 +129,18 @@ function matchmaking(player: ClientPlayer)
compatiblePlayers[0].socket.send(JSON.stringify( new ev.EventMatchmakingComplete(en.PlayerSide.right) )); compatiblePlayers[0].socket.send(JSON.stringify( new ev.EventMatchmakingComplete(en.PlayerSide.right) ));
compatiblePlayers[1].socket.send(JSON.stringify( new ev.EventMatchmakingComplete(en.PlayerSide.left) )); compatiblePlayers[1].socket.send(JSON.stringify( new ev.EventMatchmakingComplete(en.PlayerSide.left) ));
setTimeout(function abortMatch() {
if (gameSession.unreadyPlayersMap.size !== 0)
{
gameSessionsMap.delete(gameSession.id);
gameSession.playersMap.forEach((client) => {
client.socket.send(JSON.stringify( new ev.ServerEvent(en.EventTypes.matchAbort) ));
client.gameSession = null;
clientTerminate(client);
});
}
}, 5000);
} }
@@ -185,10 +197,10 @@ export function clientInputListener(this: WebSocket, data: string)
const pingInterval = setInterval( () => { const pingInterval = setInterval( () => {
let deleteLog = ""; let deleteLog = "";
clientsMap.forEach( (client, key, map) => { clientsMap.forEach( (client) => {
if (!client.isAlive) { if (!client.isAlive) {
clientTerminate(client, key, map); clientTerminate(client);
deleteLog += ` ${shortId(key)} |`; deleteLog += ` ${shortId(client.id)} |`;
} }
else { else {
client.isAlive = false; client.isAlive = false;
@@ -206,12 +218,12 @@ const pingInterval = setInterval( () => {
}, 4200); }, 4200);
function clientTerminate(client: Client, key: string, map: Map<string, Client>) function clientTerminate(client: Client)
{ {
client.socket.terminate(); client.socket.terminate();
if (client.gameSession) if (client.gameSession)
{ {
client.gameSession.playersMap.delete(key); client.gameSession.playersMap.delete(client.id);
if (client.gameSession.playersMap.size === 0) if (client.gameSession.playersMap.size === 0)
{ {
clearInterval(client.gameSession.clientsUpdateInterval); clearInterval(client.gameSession.clientsUpdateInterval);
@@ -219,9 +231,9 @@ function clientTerminate(client: Client, key: string, map: Map<string, Client>)
gameSessionsMap.delete(client.gameSession.id); gameSessionsMap.delete(client.gameSession.id);
} }
} }
map.delete(key); clientsMap.delete(client.id);
if (matchmakingPlayersMap.has(key)) { if (matchmakingPlayersMap.has(client.id)) {
matchmakingPlayersMap.delete(key); matchmakingPlayersMap.delete(client.id);
} }
} }

View File

@@ -10,6 +10,7 @@ enum EventTypes {
// Generic // Generic
matchmakingInProgress, matchmakingInProgress,
matchStart, matchStart,
matchAbort,
matchNewRound, // unused matchNewRound, // unused
matchPause, // unused matchPause, // unused
matchResume, // unused matchResume, // unused