diff --git a/src/client/audio.ts b/src/client/audio.ts index 42e01526..5990b1d8 100644 --- a/src/client/audio.ts +++ b/src/client/audio.ts @@ -1,12 +1,14 @@ import * as c from "./constants.js" -export const soundPong: HTMLAudioElement[] = []; +export const soundPongArr: HTMLAudioElement[] = []; for (let i = 0; i <= 32; i++) { - soundPong.push(new Audio("http://localhost:8080/sound/pong/"+i+".mp3")); - soundPong[i].volume = c.soundPongVolume; + soundPongArr.push(new Audio("http://localhost:8080/sound/pong/"+i+".mp3")); + soundPongArr[i].volume = c.soundPongVolume; + soundPongArr[i].muted = c.soundMutedFlag; } export const soundRoblox = new Audio("http://localhost:8080/sound/roblox-oof.mp3"); soundRoblox.volume = c.soundRobloxVolume; +soundRoblox.muted = c.soundMutedFlag; diff --git a/src/client/class/GameArea.ts b/src/client/class/GameArea.ts index 96e1bfc8..9cd92302 100644 --- a/src/client/class/GameArea.ts +++ b/src/client/class/GameArea.ts @@ -5,6 +5,7 @@ class GameArea { keys: string[] = []; handleInputInterval: number = 0; gameLoopInterval: number = 0; + drawLoopInterval: number = 0; canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; constructor() { diff --git a/src/client/class/GameComponents.ts b/src/client/class/GameComponents.ts index c820b260..64a2911c 100644 --- a/src/client/class/GameComponents.ts +++ b/src/client/class/GameComponents.ts @@ -1,7 +1,7 @@ import * as c from "../constants.js" -import {VectorInteger} from "../../shared_js/class/Vector.js"; -import {RectangleClient, RacketClient, BallClient} from "./RectangleClient.js"; +import { VectorInteger } from "../../shared_js/class/Vector.js"; +import { RectangleClient, RacketClient, BallClient } from "./RectangleClient.js"; class GameComponentsForClient { wallTop: RectangleClient; diff --git a/src/client/class/GameComponentsClient.ts b/src/client/class/GameComponentsClient.ts index 0826554b..6c9f154c 100644 --- a/src/client/class/GameComponentsClient.ts +++ b/src/client/class/GameComponentsClient.ts @@ -1,9 +1,9 @@ import * as c from "../constants.js" -import {Vector, VectorInteger} from "../../shared_js/class/Vector.js"; -import {TextElem, TextNumericValue} from "./Text.js"; -import { GameComponentsForClient } from "./GameComponents.js"; +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { TextElem, TextNumericValue } from "./Text.js"; import { RectangleClient, Line } from "./RectangleClient.js"; +import { GameComponentsForClient } from "./GameComponents.js"; class GameComponentsClient extends GameComponentsForClient { midLine: Line; diff --git a/src/client/class/InputHistory.ts b/src/client/class/InputHistory.ts new file mode 100644 index 00000000..cb7e8644 --- /dev/null +++ b/src/client/class/InputHistory.ts @@ -0,0 +1,15 @@ + +import * as en from "../../shared_js/enums.js" + +class InputHistory { + input: en.InputEnum; + inputId: number; + deltaTime: number; + constructor(input: en.InputEnum, inputId: number, deltaTime: number) { + this.input = input; + this.inputId = inputId; + this.deltaTime = deltaTime; + } +} + +export {InputHistory} diff --git a/src/client/class/RectangleClient.ts b/src/client/class/RectangleClient.ts index ad5b3da4..da2e9396 100644 --- a/src/client/class/RectangleClient.ts +++ b/src/client/class/RectangleClient.ts @@ -1,8 +1,8 @@ -import {Vector, VectorInteger} from "../../shared_js/class/Vector.js"; -import {Component, GraphicComponent, Moving} from "../../shared_js/class/interface.js"; +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { Component, GraphicComponent, Moving } from "../../shared_js/class/interface.js"; import { Rectangle, MovingRectangle, Racket, Ball } from "../../shared_js/class/Rectangle.js"; -import {soundPong, soundRoblox} from "../audio.js" +import { soundPongArr } from "../audio.js" import { random } from "../utils.js"; function updateRectangle(this: RectangleClient) { @@ -91,7 +91,7 @@ class BallClient extends Ball implements GraphicComponent { } bounce(collider?: Rectangle) { this._bounceAlgo(collider); - soundPong[ Math.floor(random(0, soundPong.length)) ].play(); + soundPongArr[ Math.floor(random(0, soundPongArr.length)) ].play(); } /* protected _bouncePlayer(collider: Racket) { this._bouncePlayerAlgo(collider); diff --git a/src/client/class/Text.ts b/src/client/class/Text.ts index e6ac3708..114992e7 100644 --- a/src/client/class/Text.ts +++ b/src/client/class/Text.ts @@ -1,6 +1,6 @@ -import {Vector, VectorInteger} from "../../shared_js/class/Vector.js"; -import {Component, Moving} from "../../shared_js/class/interface.js"; +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { Component } from "../../shared_js/class/interface.js"; // conflict with Text class TextElem implements Component { diff --git a/src/client/constants.ts b/src/client/constants.ts index ae6ecb66..940cfce2 100644 --- a/src/client/constants.ts +++ b/src/client/constants.ts @@ -1,5 +1,5 @@ -import {w} from "../shared_js/constants.js" +import { w } from "../shared_js/constants.js" export * from "../shared_js/constants.js" export const midLineSize = Math.floor(w/150); @@ -9,6 +9,8 @@ export const gridSize = Math.floor(w/500); // min interval on Firefox seems to be 15. Chrome can go lower. export const handleInputIntervalMS = 15; // millisecond export const gameLoopIntervalMS = 15; // millisecond +export const drawLoopIntervalMS = 15; // millisecond -export const soundRobloxVolume = 0; // between 0 and 1 -export const soundPongVolume = 0; // between 0 and 1 +export const soundMutedFlag = true; +export const soundRobloxVolume = 0.3; // between 0 and 1 +export const soundPongVolume = 0.3; // between 0 and 1 diff --git a/src/client/draw.ts b/src/client/draw.ts index 716e5459..11b85b3e 100644 --- a/src/client/draw.ts +++ b/src/client/draw.ts @@ -1,7 +1,8 @@ -import {pong, gc, clientInfo} from "./global.js" -import {gridDisplay} from "./handleInput.js"; -function draw() +import { pong, gc } from "./global.js" +import { gridDisplay } from "./handleInput.js"; + +function drawLoop() { pong.clear(); @@ -10,6 +11,12 @@ function draw() if (gridDisplay) { drawGrid(); } + + drawDynamic(); +} + +function drawDynamic() +{ gc.scoreLeft.update(); gc.scoreRight.update(); gc.playerLeft.update(); @@ -35,4 +42,4 @@ function drawGrid() gc.h_grid_d1.update(); } -export {draw, drawStatic, drawGrid} +export {drawLoop} diff --git a/src/client/gameLoop.ts b/src/client/gameLoop.ts index 4e069d5f..b8c7cafd 100644 --- a/src/client/gameLoop.ts +++ b/src/client/gameLoop.ts @@ -1,5 +1,5 @@ -import {gc} from "./global.js"; -import * as d from "./draw.js"; + +import { gc } from "./global.js"; let actual_time: number = Date.now(); let last_time: number; @@ -18,8 +18,6 @@ function gameLoop() // client prediction gc.ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); - - d.draw(); } export {gameLoop} diff --git a/src/client/global.ts b/src/client/global.ts index eeea8765..70564ece 100644 --- a/src/client/global.ts +++ b/src/client/global.ts @@ -1,3 +1,3 @@ export {pong, gc} from "./pong.js" -export {clientInfo} from "./ws.js" +export {socket, clientInfo} from "./ws.js" diff --git a/src/client/handleInput.ts b/src/client/handleInput.ts index 0bee1aef..db7e14ee 100644 --- a/src/client/handleInput.ts +++ b/src/client/handleInput.ts @@ -1,8 +1,8 @@ -import {pong, gc, clientInfo} from "./global.js" -import * as d from "./draw.js"; -import { socket } from "./ws.js"; + +import { pong, gc, socket, clientInfo } from "./global.js" import * as ev from "../shared_js/class/Event.js" import * as en from "../shared_js/enums.js" +import { InputHistory } from "./class/InputHistory.js" export let gridDisplay = false; @@ -10,17 +10,6 @@ let actual_time: number = Date.now(); let last_time: number; let delta_time: number; -class InputHistory { - input: en.InputEnum; - inputId: number; - deltaTime: number; - constructor(input: en.InputEnum, inputId: number, deltaTime: number) { - this.input = input; - this.inputId = inputId; - this.deltaTime = deltaTime; - } -} - const inputHistoryArr: InputHistory[] = []; let id = 0; /* idMax should be high enough to prevent duplicate "id" in "inputHistoryArr". @@ -29,28 +18,25 @@ const idMax = 999; // 999 arbitrary function handleInput() { - console.log("handleInput"); last_time = actual_time; actual_time = Date.now(); delta_time = (actual_time - last_time) / 1000; + + const keys = pong.keys; + if (keys.length == 0) { + return; + } + // console.log("handleInput"); if (id > idMax) { id = 0; } - var keys = pong.keys; - if (keys.length == 0) - return; - if (keys.indexOf("g") != -1) { - if (gridDisplay) - { - pong.clear(); - d.drawStatic(); - } gridDisplay = !gridDisplay; pong.deleteKey("g"); } + playerMove(delta_time, keys); } @@ -96,15 +82,8 @@ function repeatInput(lastInputId: number) return false; }); - // console.log("repeatInput, lastInputId = " + lastInputId); - // console.log("repeatInput, before splice up to index " + i); - // console.log(inputHistoryArr); - inputHistoryArr.splice(0, i+1); - // console.log("repeatInput, after splice"); - // console.log(inputHistoryArr); - inputHistoryArr.forEach((value: InputHistory) => { playerMovePrediction(value.deltaTime, value.input); }); diff --git a/src/client/pong.ts b/src/client/pong.ts index b3e76040..016d387a 100644 --- a/src/client/pong.ts +++ b/src/client/pong.ts @@ -1,13 +1,13 @@ -import {GameArea} from "./class/GameArea.js"; -import * as d from "./draw.js"; -import {gameLoop} from "./gameLoop.js" import * as c from "./constants.js" +import { GameArea } from "./class/GameArea.js"; import { GameComponentsClient } from "./class/GameComponentsClient.js"; -import {countdown} from "./utils.js"; -import {handleInput} from "./handleInput.js"; +import { handleInput } from "./handleInput.js"; +import { gameLoop } from "./gameLoop.js" +import { drawLoop } from "./draw.js"; +import { countdown } from "./utils.js"; -import {socket} from "./ws.js"; socket; // no-op +import {socket} from "./ws.js"; socket; // no-op, just for loading /* Keys Racket: W/S OR Up/Down @@ -41,6 +41,7 @@ function resumeGame() }); pong.handleInputInterval = window.setInterval(handleInput, c.handleInputIntervalMS); pong.gameLoopInterval = window.setInterval(gameLoop, c.gameLoopIntervalMS); + pong.gameLoopInterval = window.setInterval(drawLoop, c.drawLoopIntervalMS); } diff --git a/src/client/ws.ts b/src/client/ws.ts index 4fe1019a..28e2d6a1 100644 --- a/src/client/ws.ts +++ b/src/client/ws.ts @@ -1,17 +1,17 @@ -import {pong, gc} from "./global.js" -import * as ev from "../shared_js/class/Event.js" -import {matchmaking, matchmakingComplete, startGame} from "./pong.js"; -import * as en from "../shared_js/enums.js" -import { RacketClient } from "./class/RectangleClient.js"; -import { sleep } from "./utils.js"; import * as c from "./constants.js" -import {soundRoblox} from "./audio.js" +import { gc } from "./global.js" +import * as ev from "../shared_js/class/Event.js" +import * as en from "../shared_js/enums.js" +import { matchmaking, matchmakingComplete, startGame } from "./pong.js"; +import { RacketClient } from "./class/RectangleClient.js"; import { repeatInput } from "./handleInput.js"; +import { soundRoblox } from "./audio.js" +import { sleep } from "./utils.js"; const wsPort = 8042; const wsUrl = "ws://" + document.location.hostname + ":" + wsPort + "/pong"; -const socket = new WebSocket(wsUrl, "json"); +export const socket = new WebSocket(wsUrl, "json"); class ClientInfo { id = ""; @@ -66,16 +66,13 @@ function inGameListener(event: MessageEvent) const data: ev.ServerEvent = JSON.parse(event.data); switch (data.type) { case en.EventTypes.gameUpdate: - console.log("gameUpdate"); // setTimeout(gameUpdate, 1000, data as ev.EventGameUpdate); // artificial latency for testing purpose gameUpdate(data as ev.EventGameUpdate); break; case en.EventTypes.scoreUpdate: - console.log("scoreUpdate"); scoreUpdate(data as ev.EventScoreUpdate); break; case en.EventTypes.matchEnd: - console.log("matchEnd"); matchEnd(data as ev.EventMatchEnd); break; } @@ -83,6 +80,7 @@ function inGameListener(event: MessageEvent) function gameUpdate(data: ev.EventGameUpdate) { + console.log("gameUpdate"); gc.playerLeft.pos.y = Math.floor(data.playerLeft.y); gc.playerRight.pos.y = Math.floor(data.playerRight.y); gc.ball.pos.x = Math.floor(data.ball.x); @@ -94,6 +92,7 @@ function gameUpdate(data: ev.EventGameUpdate) function scoreUpdate(data: ev.EventScoreUpdate) { + console.log("scoreUpdate"); if (clientInfo.side === en.PlayerSide.left && data.scoreRight > gc.scoreRight.value) { soundRoblox.play(); } @@ -106,6 +105,7 @@ function scoreUpdate(data: ev.EventScoreUpdate) function matchEnd(data: ev.EventMatchEnd) { + console.log("matchEnd"); if (data.winner === clientInfo.side) { alert("WIN"); // placeholder TODO draw } @@ -113,5 +113,3 @@ function matchEnd(data: ev.EventMatchEnd) alert("LOSE"); // placeholder TODO draw } } - -export {socket} diff --git a/src/server/class/Client.ts b/src/server/class/Client.ts index c244e495..00e311a7 100644 --- a/src/server/class/Client.ts +++ b/src/server/class/Client.ts @@ -1,6 +1,6 @@ -import {WebSocket} from "ws"; -import {Racket} from "../../shared_js/class/Rectangle.js"; +import { WebSocket } from "../wsServer.js"; +import { Racket } from "../../shared_js/class/Rectangle.js"; import { GameSession } from "./GameSession.js"; class Client { diff --git a/src/server/class/GameComponentsServer.ts b/src/server/class/GameComponentsServer.ts index 84b185c4..769c4c3c 100644 --- a/src/server/class/GameComponentsServer.ts +++ b/src/server/class/GameComponentsServer.ts @@ -8,16 +8,13 @@ import { GameComponents } from "../../shared_js/class/GameComponents.js"; // const mockCTX = new CanvasRenderingContext2D(); class GameComponentsServer extends GameComponents { - scoreLeft: number; - scoreRight: number; - ballInPlay: boolean; + scoreLeft: number = 0; + scoreRight: number = 0; + ballInPlay: boolean = false; constructor() { // super(mockCTX); super(); - this.scoreLeft = 0; - this.scoreRight = 0; - this.ballInPlay = false; } } diff --git a/src/server/class/GameSession.ts b/src/server/class/GameSession.ts index 317412a9..cfe0c4c0 100644 --- a/src/server/class/GameSession.ts +++ b/src/server/class/GameSession.ts @@ -1,11 +1,11 @@ -import { ClientPlayer } from "./Client"; -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" +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(), diff --git a/src/server/server.ts b/src/server/server.ts index aa129cdb..09b6c459 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -4,17 +4,16 @@ import url from "url"; import fs from "fs"; import path from "path"; -import {wsServer} from "./wsServer.js"; wsServer; // no-op +import {wsServer} from "./wsServer.js"; wsServer; // no-op, just for loading const hostname = "localhost"; const port = 8080; const root = "../../www/"; const server = http.createServer((req, res) => { - // var q = new URL(req.url, `http://${req.getHeaders().host}`) - // @ts-ignore - var q = url.parse(req.url, true); - var filename = root + q.pathname; + // let q = new URL(req.url, `http://${req.getHeaders().host}`) + let q = url.parse(req.url, true); + let filename = root + q.pathname; fs.readFile(filename, (err, data) => { if (err) { res.writeHead(404, {"Content-Type": "text/html"}); diff --git a/src/server/wsServer.ts b/src/server/wsServer.ts index 922979ae..124a5d7e 100644 --- a/src/server/wsServer.ts +++ b/src/server/wsServer.ts @@ -1,7 +1,7 @@ import { WebSocketServer, WebSocket as BaseLibWebSocket } from "ws"; -class WebSocket extends BaseLibWebSocket { +export class WebSocket extends BaseLibWebSocket { id?: string; } @@ -10,8 +10,8 @@ import { v4 as uuidv4 } from 'uuid'; import * as en from "../shared_js/enums.js" import * as ev from "../shared_js/class/Event.js" -import {Client, ClientPlayer} from "./class/Client.js" -import {GameSession} from "./class/GameSession.js" +import { Client, ClientPlayer } from "./class/Client.js" +import { GameSession } from "./class/GameSession.js" // pas indispensable d'avoir un autre port si le WebSocket est relié à un serveur http préexistant ? const wsPort = 8042; @@ -61,8 +61,8 @@ function clientAnnounceListener(this: WebSocket, data: string) // TODO: reconnection with msg.id ? // TODO: spectator/player distinction with msg.type ? - this.send(JSON.stringify( new ev.EventAssignId(this.id) )) - this.send(JSON.stringify( new ev.ServerEvent(en.EventTypes.matchmakingInProgress) )) + this.send(JSON.stringify( new ev.EventAssignId(this.id) )); + this.send(JSON.stringify( new ev.ServerEvent(en.EventTypes.matchmakingInProgress) )); matchmaking(this); } else { @@ -110,7 +110,7 @@ function matchmaking(socket: WebSocket) }); gameSession.playersMap.forEach( (client) => { /* set listener last to be absolutly sure there no early game launch - (unlikely, but theoretically possible) */ + (unlikely, but possible in theory) */ client.socket.once("message", playerReadyConfirmationListener); }); } diff --git a/src/shared_js/class/GameComponents.ts b/src/shared_js/class/GameComponents.ts index 0c9309c2..0ef0a64a 100644 --- a/src/shared_js/class/GameComponents.ts +++ b/src/shared_js/class/GameComponents.ts @@ -3,8 +3,8 @@ For the moment, this code is only used by the server. */ import * as c from "../constants.js" -import {VectorInteger} from "./Vector.js"; -import {Rectangle, Racket, Ball} from "./Rectangle.js"; +import { VectorInteger } from "./Vector.js"; +import { Rectangle, Racket, Ball } from "./Rectangle.js"; class GameComponents { wallTop: Rectangle; diff --git a/src/shared_js/class/Rectangle.ts b/src/shared_js/class/Rectangle.ts index 35352b70..8ebd6415 100644 --- a/src/shared_js/class/Rectangle.ts +++ b/src/shared_js/class/Rectangle.ts @@ -1,6 +1,6 @@ -import {Vector, VectorInteger} from "./Vector.js"; -import {Component, Moving} from "./interface.js"; +import { Vector, VectorInteger } from "./Vector.js"; +import { Component, Moving } from "./interface.js"; class Rectangle implements Component { pos: VectorInteger; diff --git a/src/shared_js/class/interface.ts b/src/shared_js/class/interface.ts index 5fdb8315..39753de1 100644 --- a/src/shared_js/class/interface.ts +++ b/src/shared_js/class/interface.ts @@ -1,5 +1,5 @@ -import {Vector, VectorInteger} from "./Vector.js"; +import { Vector, VectorInteger } from "./Vector.js"; interface Component { pos: VectorInteger;