added alternate game mode "movingWalls"
This commit is contained in:
4
memo.txt
4
memo.txt
@@ -13,15 +13,15 @@ Done:
|
||||
(BUG désynchronisation: revenu à un traitement immédiat en attendant)
|
||||
- Détruire les GameSession une fois finies.
|
||||
- mode multi-balles
|
||||
- mode murs mouvant (la zone de jeu rétréci / agrandi en continu)
|
||||
|
||||
TODO:
|
||||
- mode spectateur
|
||||
- un ou deux modes de jeu alternatif.
|
||||
- certaines utilisations de Math.floor() superflu ? Vérifier les appels.
|
||||
(éventuellement Math.round() ?)
|
||||
- un autre mode de jeu alternatif ?
|
||||
-----------
|
||||
idées modes de jeu :
|
||||
- mode murs mouvant (la zone de jeu rétréci / agrandi en continu)
|
||||
- mode 2 raquettes (un joueur haut/gauche et bas/droite)
|
||||
- skin patate ???
|
||||
- (prediction de l'avancement de la balle basé sur la latence serveur ?)
|
||||
|
||||
@@ -3,28 +3,68 @@ import * as c from "../constants.js"
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import { Vector, VectorInteger } from "../../shared_js/class/Vector.js";
|
||||
import { TextElem, TextNumericValue } from "./Text.js";
|
||||
import { RectangleClient, RacketClient, BallClient, Line } from "./RectangleClient.js";
|
||||
import { RectangleClient, MovingRectangleClient, RacketClient, BallClient, Line } from "./RectangleClient.js";
|
||||
import { GameComponents } from "../../shared_js/class/GameComponents.js";
|
||||
import { assertMovingRectangle } from "../utils.js";
|
||||
|
||||
class GameComponentsExtensionForClient extends GameComponents {
|
||||
wallTop: RectangleClient;
|
||||
wallBottom: RectangleClient;
|
||||
wallTop: RectangleClient | MovingRectangleClient;
|
||||
wallBottom: RectangleClient | MovingRectangleClient;
|
||||
playerLeft: RacketClient;
|
||||
playerRight: RacketClient;
|
||||
ballsArr: BallClient[];
|
||||
constructor(options: en.MatchOptions, ctx: CanvasRenderingContext2D)
|
||||
{
|
||||
super(options);
|
||||
this.wallTop = new RectangleClient(this.wallTop.pos, this.wallTop.width, this.wallTop.height, ctx, "grey");
|
||||
this.wallBottom = new RectangleClient(this.wallBottom.pos, this.wallBottom.width, this.wallBottom.height, ctx, "grey");
|
||||
this.playerLeft = new RacketClient(this.playerLeft.pos, this.playerLeft.width, this.playerLeft.height, this.playerLeft.baseSpeed, ctx, "white");
|
||||
this.playerRight = new RacketClient(this.playerRight.pos, this.playerRight.width, this.playerRight.height, this.playerRight.baseSpeed, ctx, "white");
|
||||
|
||||
// Rackets
|
||||
this.playerLeft = new RacketClient(
|
||||
this.playerLeft.pos, this.playerLeft.width, this.playerLeft.height, this.playerLeft.baseSpeed,
|
||||
ctx, "white");
|
||||
this.playerRight = new RacketClient(
|
||||
this.playerRight.pos, this.playerRight.width, this.playerRight.height, this.playerRight.baseSpeed,
|
||||
ctx, "white");
|
||||
|
||||
// Balls
|
||||
const newBallsArr: BallClient[] = [];
|
||||
this.ballsArr.forEach((ball) => {
|
||||
newBallsArr.push(new BallClient(ball.pos, ball.width, ball.baseSpeed, ball.speedIncrease, ctx, "white"));
|
||||
newBallsArr.push(new BallClient(
|
||||
ball.pos, ball.width, ball.baseSpeed, ball.speedIncrease,
|
||||
ctx, "white")
|
||||
);
|
||||
});
|
||||
this.ballsArr = newBallsArr;
|
||||
|
||||
// Walls
|
||||
if (options & en.MatchOptions.movingWalls)
|
||||
{
|
||||
const dir = new Vector;
|
||||
|
||||
assertMovingRectangle(this.wallTop);
|
||||
dir.assign(this.wallTop.dir.x, this.wallTop.dir.y);
|
||||
this.wallTop = new MovingRectangleClient(
|
||||
this.wallTop.pos, this.wallTop.width, this.wallTop.height,
|
||||
this.wallTop.baseSpeed,
|
||||
ctx, "grey");
|
||||
(<MovingRectangleClient>this.wallTop).dir.assign(dir.x, dir.y);
|
||||
|
||||
assertMovingRectangle(this.wallBottom);
|
||||
dir.assign(this.wallBottom.dir.x, this.wallBottom.dir.y);
|
||||
this.wallBottom = new MovingRectangleClient(
|
||||
this.wallBottom.pos, this.wallBottom.width, this.wallBottom.height,
|
||||
this.wallBottom.baseSpeed,
|
||||
ctx, "grey");
|
||||
(<MovingRectangleClient>this.wallBottom).dir.assign(dir.x, dir.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.wallTop = new RectangleClient(
|
||||
this.wallTop.pos, this.wallTop.width, this.wallTop.height,
|
||||
ctx, "grey");
|
||||
this.wallBottom = new RectangleClient(
|
||||
this.wallBottom.pos, this.wallBottom.width, this.wallBottom.height,
|
||||
ctx, "grey");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,7 @@ export const soundPongVolume = 0.3; // between 0 and 1
|
||||
|
||||
// TODO: replace by a selector on the website
|
||||
import * as en from "../shared_js/enums.js"
|
||||
export const optionsPLACEHOLDER = en.MatchOptions.noOption | en.MatchOptions.multiBalls;
|
||||
export const optionsPLACEHOLDER = en.MatchOptions.noOption;
|
||||
// export const optionsPLACEHOLDER = en.MatchOptions.multiBalls;
|
||||
// export const optionsPLACEHOLDER = en.MatchOptions.movingWalls;
|
||||
// export const optionsPLACEHOLDER = en.MatchOptions.movingWalls | en.MatchOptions.multiBalls;
|
||||
|
||||
@@ -32,9 +32,9 @@ function drawDynamic()
|
||||
|
||||
function drawStatic()
|
||||
{
|
||||
gc.midLine.update();
|
||||
gc.wallTop.update();
|
||||
gc.wallBottom.update();
|
||||
gc.midLine.update();
|
||||
}
|
||||
|
||||
function drawGrid()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import * as c from "./constants.js";
|
||||
import * as en from "../shared_js/enums.js"
|
||||
import { gc, clientInfo } from "./global.js";
|
||||
import { wallsMovements } from "../shared_js/wallsMovement.js";
|
||||
|
||||
let actual_time: number = Date.now();
|
||||
let last_time: number;
|
||||
@@ -26,6 +27,10 @@ function gameLoop()
|
||||
gc.ballsArr.forEach((ball) => {
|
||||
ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]);
|
||||
});
|
||||
|
||||
if (c.optionsPLACEHOLDER & en.MatchOptions.movingWalls) {
|
||||
wallsMovements(delta_time, gc);
|
||||
}
|
||||
}
|
||||
|
||||
function opponentInterpolation(delta: number)
|
||||
|
||||
@@ -90,6 +90,11 @@ function gameUpdate(data: ev.EventGameUpdate)
|
||||
{
|
||||
console.log("gameUpdate");
|
||||
|
||||
if (c.optionsPLACEHOLDER & en.MatchOptions.movingWalls) {
|
||||
gc.wallTop.pos.y = data.wallTop.y;
|
||||
gc.wallBottom.pos.y = data.wallBottom.y;
|
||||
}
|
||||
|
||||
data.ballsArr.forEach((ball, i) => {
|
||||
gc.ballsArr[i].pos.assign(ball.x, ball.y);
|
||||
gc.ballsArr[i].dir.assign(ball.dirX, ball.dirY);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GameComponentsServer } from "./GameComponentsServer.js";
|
||||
import { clientInputListener } from "../wsServer.js";
|
||||
import { random } from "../utils.js";
|
||||
import { Ball } from "../../shared_js/class/Rectangle.js";
|
||||
import { wallsMovements } from "../../shared_js/wallsMovement.js";
|
||||
|
||||
/*
|
||||
Arg "s: GameSession" replace "this: GameSession" for use with setTimeout(),
|
||||
@@ -95,6 +96,10 @@ class GameSession {
|
||||
gc.ballsArr.forEach((ball) => {
|
||||
s._ballMovement(s.delta_time, ball);
|
||||
});
|
||||
|
||||
if (s.matchOptions & en.MatchOptions.movingWalls) {
|
||||
wallsMovements(s.delta_time, gc);
|
||||
}
|
||||
}
|
||||
private _ballMovement(delta: number, ball: Ball) {
|
||||
const gc = this.components;
|
||||
@@ -133,6 +138,10 @@ class GameSession {
|
||||
speed: ball.speed
|
||||
});
|
||||
});
|
||||
if (s.matchOptions & en.MatchOptions.movingWalls) {
|
||||
update.wallTop.y = gc.wallTop.pos.y;
|
||||
update.wallBottom.y = gc.wallBottom.pos.y;
|
||||
}
|
||||
|
||||
s.playersMap.forEach( (client) => {
|
||||
update.lastInputId = client.lastInputId;
|
||||
@@ -152,7 +161,7 @@ class GameSession {
|
||||
}
|
||||
}
|
||||
ball.pos.x = c.w_mid;
|
||||
ball.pos.y = Math.floor((c.h * 0.1) + random() * (c.h * 0.8));
|
||||
ball.pos.y = random(c.h*0.3, c.h*0.7);
|
||||
ball.speed = ball.baseSpeed;
|
||||
ball.ballInPlay = true;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,12 @@ class EventGameUpdate extends ServerEvent {
|
||||
dirY: number,
|
||||
speed: number
|
||||
}[] = [];
|
||||
wallTop? = {
|
||||
y: 0
|
||||
};
|
||||
wallBottom? = {
|
||||
y: 0
|
||||
};
|
||||
lastInputId = 0;
|
||||
constructor() { // TODO: constructor that take GameComponentsServer maybe ?
|
||||
super(en.EventTypes.gameUpdate);
|
||||
|
||||
@@ -2,29 +2,26 @@
|
||||
import * as c from "../constants.js"
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import { VectorInteger } from "./Vector.js";
|
||||
import { Rectangle, Racket, Ball } from "./Rectangle.js";
|
||||
import { Rectangle, MovingRectangle, Racket, Ball } from "./Rectangle.js";
|
||||
import { clamp, random } from "../utils.js";
|
||||
|
||||
class GameComponents {
|
||||
wallTop: Rectangle;
|
||||
wallBottom: Rectangle;
|
||||
wallTop: Rectangle | MovingRectangle;
|
||||
wallBottom: Rectangle | MovingRectangle;
|
||||
playerLeft: Racket;
|
||||
playerRight: Racket;
|
||||
ballsArr: Ball[] = [];
|
||||
constructor(options: en.MatchOptions)
|
||||
{
|
||||
let pos = new VectorInteger;
|
||||
const pos = new VectorInteger;
|
||||
|
||||
pos.assign(0, 0);
|
||||
this.wallTop = new Rectangle(pos, c.w, c.wallSize);
|
||||
pos.assign(0, c.h-c.wallSize);
|
||||
this.wallBottom = new Rectangle(pos, c.w, c.wallSize);
|
||||
|
||||
// Rackets
|
||||
pos.assign(0+c.pw, c.h_mid-c.ph/2);
|
||||
this.playerLeft = new Racket(pos, c.pw, c.ph, c.racketSpeed);
|
||||
pos.assign(c.w-c.pw-c.pw, c.h_mid-c.ph/2);
|
||||
this.playerRight = new Racket(pos, c.pw, c.ph, c.racketSpeed);
|
||||
|
||||
// Balls
|
||||
let ballsCount = 1;
|
||||
if (options & en.MatchOptions.multiBalls) {
|
||||
ballsCount = c.multiBallsCount;
|
||||
@@ -46,6 +43,22 @@ class GameComponents {
|
||||
|
||||
ball.dir = ball.dir.normalized();
|
||||
});
|
||||
|
||||
// Walls
|
||||
if (options & en.MatchOptions.movingWalls) {
|
||||
pos.assign(0, 0);
|
||||
this.wallTop = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed);
|
||||
(<MovingRectangle>this.wallTop).dir.y = -1;
|
||||
pos.assign(0, c.h-c.wallSize);
|
||||
this.wallBottom = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed);
|
||||
(<MovingRectangle>this.wallBottom).dir.y = 1;
|
||||
}
|
||||
else {
|
||||
pos.assign(0, 0);
|
||||
this.wallTop = new Rectangle(pos, c.w, c.wallSize);
|
||||
pos.assign(0, c.h-c.wallSize);
|
||||
this.wallBottom = new Rectangle(pos, c.w, c.wallSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,7 @@ export const normalizedSpeed = false; // for consistency in speed independent of
|
||||
export const matchStartDelay = 3000; // millisecond
|
||||
export const newRoundDelay = 1500; // millisecond
|
||||
|
||||
// Game Variantes
|
||||
export const multiBallsCount = 3;
|
||||
export const movingWallPosMax = Math.floor(w*0.12);
|
||||
export const movingWallSpeed = Math.floor(w*0.08);
|
||||
|
||||
@@ -40,7 +40,8 @@ enum ClientRole {
|
||||
enum MatchOptions {
|
||||
// binary flags, can be mixed
|
||||
noOption = 0b0,
|
||||
multiBalls = 1 << 0
|
||||
multiBalls = 1 << 0,
|
||||
movingWalls = 1 << 1
|
||||
}
|
||||
|
||||
export {EventTypes, InputEnum, PlayerSide, ClientRole, MatchOptions}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
import { MovingRectangle } from "./class/Rectangle.js";
|
||||
|
||||
function random(min: number = 0, max: number = 1) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
@@ -16,4 +18,9 @@ function clamp(n: number, min: number, max: number) : number
|
||||
return (n);
|
||||
}
|
||||
|
||||
export {random, sleep, clamp}
|
||||
function assertMovingRectangle(value: unknown): asserts value is MovingRectangle {
|
||||
// if (value !== MovingRectangle) throw new Error("Not a MovingRectangle");
|
||||
return;
|
||||
}
|
||||
|
||||
export {random, sleep, clamp, assertMovingRectangle}
|
||||
|
||||
20
src/shared_js/wallsMovement.ts
Normal file
20
src/shared_js/wallsMovement.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
import * as c from "./constants.js";
|
||||
import { MovingRectangle } from "../shared_js/class/Rectangle.js";
|
||||
import { GameComponents } from "./class/GameComponents.js";
|
||||
|
||||
function wallsMovements(delta: number, gc: GameComponents)
|
||||
{
|
||||
const wallTop = <MovingRectangle>gc.wallTop;
|
||||
const wallBottom = <MovingRectangle>gc.wallBottom;
|
||||
if (wallTop.pos.y <= 0 || wallTop.pos.y >= c.movingWallPosMax) {
|
||||
wallTop.dir.y *= -1;
|
||||
}
|
||||
if (wallBottom.pos.y >= c.h-c.wallSize || wallBottom.pos.y <= c.h-c.movingWallPosMax) {
|
||||
wallBottom.dir.y *= -1;
|
||||
}
|
||||
wallTop.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]);
|
||||
wallBottom.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]);
|
||||
}
|
||||
|
||||
export {wallsMovements}
|
||||
Reference in New Issue
Block a user