drawing now seperate from gameLoop
+ refactoring + added soundMutedFlag
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -5,6 +5,7 @@ class GameArea {
|
||||
keys: string[] = [];
|
||||
handleInputInterval: number = 0;
|
||||
gameLoopInterval: number = 0;
|
||||
drawLoopInterval: number = 0;
|
||||
canvas: HTMLCanvasElement;
|
||||
ctx: CanvasRenderingContext2D;
|
||||
constructor() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
15
src/client/class/InputHistory.ts
Normal file
15
src/client/class/InputHistory.ts
Normal file
@@ -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}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
|
||||
export {pong, gc} from "./pong.js"
|
||||
export {clientInfo} from "./ws.js"
|
||||
export {socket, clientInfo} from "./ws.js"
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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"});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import {Vector, VectorInteger} from "./Vector.js";
|
||||
import { Vector, VectorInteger } from "./Vector.js";
|
||||
|
||||
interface Component {
|
||||
pos: VectorInteger;
|
||||
|
||||
Reference in New Issue
Block a user