Match abort if all players not ready in time (5s)
+ HTML Keys instructions
This commit is contained in:
49
memo.txt
49
memo.txt
@@ -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é.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user