authoritative server OK
+ TODO actual matchmaking
This commit is contained in:
@@ -1,29 +1,141 @@
|
||||
import { ClientPlayer } from "./Client";
|
||||
import {gameUpdate} from "../gameUpdate.js"
|
||||
import { GameComponentsServer } from "./GameComponentsServer";
|
||||
|
||||
// Empty object replacement to the web-API (web-API useless on server-side)
|
||||
import { GameComponents } from "../../shared_js/class/GameComponents.js";
|
||||
import { clientInputListener } from "../wsServer.js";
|
||||
import * as c from "../constants.js"
|
||||
import { GameComponentsServer } from "./GameComponentsServer.js";
|
||||
import { random } from "../../shared_js/utils.js";
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import * as ev from "../../shared_js/class/Event.js"
|
||||
|
||||
/*
|
||||
Arg "s: GameSession" replace "this: GameSession" for use with setTimeout(),
|
||||
because "this" is equal to "this: Timeout"
|
||||
*/
|
||||
class GameSession {
|
||||
id: string; // url ?
|
||||
playersMap: Map<string, ClientPlayer>;
|
||||
unreadyPlayersMap: Map<string, ClientPlayer>;
|
||||
updateInterval: NodeJS.Timer;
|
||||
// gc: GameComponentsServer;
|
||||
// updateInterval: NodeJS.Timer;
|
||||
gameLoopInterval: NodeJS.Timer | number;
|
||||
clientsUpdateInterval: NodeJS.Timer | number;
|
||||
components: GameComponentsServer;
|
||||
|
||||
actual_time: number;
|
||||
last_time: number;
|
||||
delta_time: number;
|
||||
|
||||
constructor(id: string) {
|
||||
this.id = id;
|
||||
this.playersMap = new Map();
|
||||
this.unreadyPlayersMap = new Map();
|
||||
// this.gc = new GameComponentsServer();
|
||||
this.components = new GameComponentsServer();
|
||||
}
|
||||
start() {
|
||||
this.updateInterval = setInterval( () => {
|
||||
const update = gameUpdate();
|
||||
this.playersMap.forEach( (client) => {
|
||||
client.socket.send(JSON.stringify(update));
|
||||
});
|
||||
}, 500);
|
||||
setTimeout(this.resume, c.matchStartDelay, this);
|
||||
setTimeout(this._newRound, c.matchStartDelay + c.newRoundDelay, this);
|
||||
}
|
||||
resume(s: GameSession) {
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.on("message", clientInputListener);
|
||||
});
|
||||
|
||||
s.actual_time = Date.now();
|
||||
s.gameLoopInterval = setInterval(s._gameLoop, c.gameLoopIntervalMS, s);
|
||||
s.clientsUpdateInterval = setInterval(s._clientsUpdate, c.clientsUpdateIntervalMS, s);
|
||||
}
|
||||
pause(s: GameSession) {
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.off("message", clientInputListener);
|
||||
});
|
||||
|
||||
clearInterval(s.gameLoopInterval);
|
||||
clearInterval(s.clientsUpdateInterval);
|
||||
}
|
||||
handleInput(client: ClientPlayer, input: en.InputEnum) {
|
||||
const gc = this.components;
|
||||
client.racket.dir.y = 0;
|
||||
if (input === en.InputEnum.up) {
|
||||
client.racket.dir.y += -1;
|
||||
}
|
||||
else if (input === en.InputEnum.down) {
|
||||
client.racket.dir.y += 1;
|
||||
}
|
||||
client.racket.moveAndCollide(this.delta_time, [gc.wallTop, gc.wallBottom]);
|
||||
/* how to handle Delta time correctly in handleInput ? */
|
||||
}
|
||||
private _gameLoop(s: GameSession) {
|
||||
s.last_time = s.actual_time;
|
||||
s.actual_time = Date.now();
|
||||
s.delta_time = (s.actual_time - s.last_time) / 1000;
|
||||
|
||||
const gc = s.components;
|
||||
if (gc.ballInPlay)
|
||||
{
|
||||
gc.ball.moveAndBounce(s.delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]);
|
||||
if (gc.ball.pos.x > c.w) {
|
||||
gc.ballInPlay = false;
|
||||
++gc.scoreLeft;
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
|
||||
});
|
||||
setTimeout(s._newRound, c.newRoundDelay, s);
|
||||
}
|
||||
else if (gc.ball.pos.x < 0 - gc.ball.width) {
|
||||
gc.ballInPlay = false;
|
||||
++gc.scoreRight;
|
||||
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
|
||||
});
|
||||
setTimeout(s._newRound, c.newRoundDelay, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
private _clientsUpdate(s: GameSession) {
|
||||
const gc = s.components;
|
||||
const update: ev.EventGameUpdate = {
|
||||
type: en.EventTypes.gameUpdate,
|
||||
playerLeft: {y: gc.playerLeft.pos.y},
|
||||
playerRight: {y: gc.playerRight.pos.y},
|
||||
ball: {x: gc.ball.pos.x, y: gc.ball.pos.y, speed: gc.ball.speed}
|
||||
};
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.send(JSON.stringify(update));
|
||||
});
|
||||
}
|
||||
private _newRound(s: GameSession) {
|
||||
const gc = s.components;
|
||||
// https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches
|
||||
if (gc.scoreLeft >= 11
|
||||
|| gc.scoreRight >= 11)
|
||||
{
|
||||
if (Math.abs(gc.scoreLeft - gc.scoreRight) >= 2)
|
||||
{
|
||||
s._matchEnd(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gc.ball.pos.x = c.w_mid;
|
||||
gc.ball.pos.y = Math.floor((c.h * 0.1) + random() * (c.h * 0.8));
|
||||
gc.ball.speed = gc.ball.baseSpeed;
|
||||
gc.ballInPlay = true;
|
||||
}
|
||||
private _matchEnd(s: GameSession) {
|
||||
const gc = s.components;
|
||||
|
||||
let eventEnd: ev.EventMatchEnd;
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user