serveur de jeu - work in progress
This commit is contained in:
212
jeu/src/server/class/GameSession.js
Normal file
212
jeu/src/server/class/GameSession.js
Normal file
@@ -0,0 +1,212 @@
|
||||
import * as en from "../../shared_js/enums.js";
|
||||
import * as ev from "../../shared_js/class/Event.js";
|
||||
import * as c from "../constants.js";
|
||||
import { GameComponentsServer } from "./GameComponentsServer.js";
|
||||
import { clientInputListener } from "../wsServer.js";
|
||||
import { random } from "../utils.js";
|
||||
import { wallsMovements } from "../../shared_js/wallsMovement.js";
|
||||
/*
|
||||
multiples methods of GameSession have parameter "s: GameSession".
|
||||
its used with calls to setTimeout(),
|
||||
because "this" is not equal to the GameSession but to "this: Timeout"
|
||||
*/
|
||||
export class GameSession {
|
||||
constructor(id, matchOptions) {
|
||||
this.playersMap = new Map();
|
||||
this.unreadyPlayersMap = new Map();
|
||||
this.spectatorsMap = new Map();
|
||||
this.gameLoopInterval = 0;
|
||||
this.playersUpdateInterval = 0;
|
||||
this.spectatorsUpdateInterval = 0;
|
||||
this.matchEnded = false;
|
||||
this.id = id;
|
||||
this.matchOptions = matchOptions;
|
||||
this.components = new GameComponentsServer(this.matchOptions);
|
||||
}
|
||||
start() {
|
||||
const gc = this.components;
|
||||
setTimeout(this.resume, c.matchStartDelay, this);
|
||||
let timeout = c.matchStartDelay + c.newRoundDelay;
|
||||
gc.ballsArr.forEach((ball) => {
|
||||
setTimeout(this._newRound, timeout, this, ball);
|
||||
timeout += c.newRoundDelay * 0.5;
|
||||
});
|
||||
}
|
||||
resume(s) {
|
||||
s.playersMap.forEach((client) => {
|
||||
client.socket.on("message", clientInputListener);
|
||||
});
|
||||
s.actual_time = Date.now();
|
||||
s.gameLoopInterval = setInterval(s._gameLoop, c.serverGameLoopIntervalMS, s);
|
||||
s.playersUpdateInterval = setInterval(s._playersUpdate, c.playersUpdateIntervalMS, s);
|
||||
s.spectatorsUpdateInterval = setInterval(s._spectatorsUpdate, c.spectatorsUpdateIntervalMS, s);
|
||||
}
|
||||
pause(s) {
|
||||
s.playersMap.forEach((client) => {
|
||||
client.socket.off("message", clientInputListener);
|
||||
});
|
||||
clearInterval(s.gameLoopInterval);
|
||||
clearInterval(s.playersUpdateInterval);
|
||||
clearInterval(s.spectatorsUpdateInterval);
|
||||
}
|
||||
instantInputDebug(client) {
|
||||
this._handleInput(c.fixedDeltaTime, client);
|
||||
}
|
||||
_handleInput(delta, client) {
|
||||
// if (client.inputBuffer === null) {return;}
|
||||
const gc = this.components;
|
||||
const input = client.inputBuffer.input;
|
||||
if (input === en.InputEnum.up) {
|
||||
client.racket.dir.y = -1;
|
||||
}
|
||||
else if (input === en.InputEnum.down) {
|
||||
client.racket.dir.y = 1;
|
||||
}
|
||||
if (input !== en.InputEnum.noInput) {
|
||||
client.racket.moveAndCollide(delta, [gc.wallTop, gc.wallBottom]);
|
||||
}
|
||||
client.lastInputId = client.inputBuffer.id;
|
||||
// client.inputBuffer = null;
|
||||
}
|
||||
_gameLoop(s) {
|
||||
/* s.last_time = s.actual_time;
|
||||
s.actual_time = Date.now();
|
||||
s.delta_time = (s.actual_time - s.last_time) / 1000; */
|
||||
s.delta_time = c.fixedDeltaTime;
|
||||
// WIP, replaced by instantInputDebug() to prevent desynchro
|
||||
/* s.playersMap.forEach( (client) => {
|
||||
s._handleInput(s.delta_time, client);
|
||||
}); */
|
||||
const gc = s.components;
|
||||
gc.ballsArr.forEach((ball) => {
|
||||
s._ballMovement(s.delta_time, ball);
|
||||
});
|
||||
if (s.matchOptions & en.MatchOptions.movingWalls) {
|
||||
wallsMovements(s.delta_time, gc);
|
||||
}
|
||||
}
|
||||
_ballMovement(delta, ball) {
|
||||
const gc = this.components;
|
||||
if (ball.ballInPlay) {
|
||||
ball.moveAndBounce(delta, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]);
|
||||
if (ball.pos.x > c.w
|
||||
|| ball.pos.x < 0 - ball.width) {
|
||||
ball.ballInPlay = false;
|
||||
if (this.matchEnded) {
|
||||
return;
|
||||
}
|
||||
this._scoreUpdate(ball);
|
||||
setTimeout(this._newRound, c.newRoundDelay, this, ball);
|
||||
}
|
||||
}
|
||||
}
|
||||
_scoreUpdate(ball) {
|
||||
const gc = this.components;
|
||||
if (ball.pos.x > c.w) {
|
||||
++gc.scoreLeft;
|
||||
}
|
||||
else if (ball.pos.x < 0 - ball.width) {
|
||||
++gc.scoreRight;
|
||||
}
|
||||
this.playersMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
|
||||
});
|
||||
this.spectatorsMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
|
||||
});
|
||||
}
|
||||
_playersUpdate(s) {
|
||||
const gameState = s._gameStateSnapshot();
|
||||
s.playersMap.forEach((client) => {
|
||||
gameState.lastInputId = client.lastInputId;
|
||||
client.socket.send(JSON.stringify(gameState));
|
||||
});
|
||||
}
|
||||
_spectatorsUpdate(s) {
|
||||
const gameState = s._gameStateSnapshot();
|
||||
s.spectatorsMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(gameState));
|
||||
});
|
||||
}
|
||||
_gameStateSnapshot() {
|
||||
const gc = this.components;
|
||||
const snapshot = new ev.EventGameUpdate();
|
||||
snapshot.playerLeft.y = gc.playerLeft.pos.y;
|
||||
snapshot.playerRight.y = gc.playerRight.pos.y;
|
||||
gc.ballsArr.forEach((ball) => {
|
||||
snapshot.ballsArr.push({
|
||||
x: ball.pos.x,
|
||||
y: ball.pos.y,
|
||||
dirX: ball.dir.x,
|
||||
dirY: ball.dir.y,
|
||||
speed: ball.speed
|
||||
});
|
||||
});
|
||||
if (this.matchOptions & en.MatchOptions.movingWalls) {
|
||||
snapshot.wallTop.y = gc.wallTop.pos.y;
|
||||
snapshot.wallBottom.y = gc.wallBottom.pos.y;
|
||||
}
|
||||
return (snapshot);
|
||||
}
|
||||
_newRound(s, ball) {
|
||||
if (s._checkDisconnexions()) {
|
||||
return;
|
||||
}
|
||||
// https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches
|
||||
const gc = s.components;
|
||||
const minScore = 11; // can be changed for testing
|
||||
if (gc.scoreLeft >= minScore || gc.scoreRight >= minScore) {
|
||||
if (Math.abs(gc.scoreLeft - gc.scoreRight) >= 2) {
|
||||
s._matchEnd(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ball.pos.x = c.w_mid;
|
||||
ball.pos.y = random(c.h * 0.3, c.h * 0.7);
|
||||
ball.speed = ball.baseSpeed;
|
||||
ball.ballInPlay = true;
|
||||
}
|
||||
_checkDisconnexions() {
|
||||
if (this.playersMap.size !== 2) {
|
||||
this.matchEnded = true;
|
||||
if (this.playersMap.size != 0) {
|
||||
const gc = this.components;
|
||||
const luckyWinner = this.playersMap.values().next().value;
|
||||
let eventEnd;
|
||||
if (luckyWinner.racket === gc.playerLeft) {
|
||||
eventEnd = new ev.EventMatchEnd(en.PlayerSide.left, true);
|
||||
console.log("Player Left WIN (by forfeit)");
|
||||
}
|
||||
else {
|
||||
eventEnd = new ev.EventMatchEnd(en.PlayerSide.right, true);
|
||||
console.log("Player Right WIN (by forfeit)");
|
||||
}
|
||||
luckyWinner.socket.send(JSON.stringify(eventEnd));
|
||||
this.spectatorsMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(eventEnd));
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_matchEnd(s) {
|
||||
s.matchEnded = true;
|
||||
const gc = s.components;
|
||||
let eventEnd;
|
||||
if (gc.scoreLeft > gc.scoreRight) {
|
||||
eventEnd = new ev.EventMatchEnd(en.PlayerSide.left);
|
||||
console.log("Player Left WIN");
|
||||
}
|
||||
else {
|
||||
eventEnd = new ev.EventMatchEnd(en.PlayerSide.right);
|
||||
console.log("Player Right WIN");
|
||||
}
|
||||
s.playersMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(eventEnd));
|
||||
});
|
||||
s.spectatorsMap.forEach((client) => {
|
||||
client.socket.send(JSON.stringify(eventEnd));
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user