167 lines
4.6 KiB
TypeScript
167 lines
4.6 KiB
TypeScript
|
|
import * as en from "../../shared_js/enums.js"
|
|
import * as ev from "../../shared_js/class/Event.js"
|
|
import * as c from "../constants.js"
|
|
import { ClientPlayer } from "./Client";
|
|
import { GameComponentsServer } from "./GameComponentsServer.js";
|
|
import { clientInputListener } from "../wsServer.js";
|
|
import { random } from "../../shared_js/utils.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>;
|
|
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.components = new GameComponentsServer();
|
|
}
|
|
start() {
|
|
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);
|
|
}
|
|
private _handleInput(delta: number, client: ClientPlayer) {
|
|
const gc = this.components;
|
|
client.inputArr.forEach( (value) => {
|
|
const input = value.input;
|
|
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(delta, [gc.wallTop, gc.wallBottom]);
|
|
});
|
|
client.lastInputId = client.inputArr[client.inputArr.length - 1].inputId;
|
|
client.inputArr.length = 0;
|
|
}
|
|
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; */
|
|
s.delta_time = c.fixedDeltaTime;
|
|
|
|
console.log(s.delta_time);
|
|
|
|
s.playersMap.forEach( (client) => {
|
|
if (client.inputArr.length != 0) {
|
|
s._handleInput(s.delta_time, client);
|
|
}
|
|
});
|
|
|
|
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,
|
|
dirX: gc.ball.dir.x,
|
|
dirY: gc.ball.dir.y,
|
|
speed: gc.ball.speed
|
|
},
|
|
lastInputId: 0
|
|
};
|
|
s.playersMap.forEach( (client) => {
|
|
update.lastInputId = client.lastInputId;
|
|
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 (gc.scoreLeft >= 2 || gc.scoreRight >= 2) // WIP: for testing
|
|
{
|
|
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));
|
|
});
|
|
}
|
|
}
|
|
|
|
export {GameSession}
|