diff options
-rw-r--r-- | game.css | 34 | ||||
-rw-r--r-- | game.html | 11 | ||||
-rw-r--r-- | game.js | 31 | ||||
-rwxr-xr-x | server.js | 53 |
4 files changed, 120 insertions, 9 deletions
@@ -11,18 +11,22 @@ body { font-family: sans-serif; } -#overlay-container { +.invisible { + display: none; +} + +.centerbox { position: absolute; left: 0; top: 0; right: 0; bottom: 0; - align-items: center; display: flex; + align-items: center; justify-content: center; } -#status { +.largetext { color: #ffffff; font-size: 40pt; text-shadow: 0px 0px 3px #000000; @@ -31,3 +35,27 @@ body { -moz-user-select: none; -webkit-user-select: none; } + +#overlay-container { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +#score-container { + position: absolute; + left: 0; + top: 0; + right: 0; + height: 30%; +} + +#score-left, #score-right { + display: inline-block; + width: 30vw; +} +#score-left { + text-align: right; +} @@ -10,7 +10,16 @@ <body> <canvas id="cvs"></canvas> <div id="overlay-container"> - <div id="status"></div> + <div class="centerbox"> + <div id="status" class="largetext"></div> + </div> + <div id="score-container" class="centerbox"> + <div id="score" class="largetext invisible"> + <span id="score-left"></span> + — + <span id="score-right"></span> + </div> + </div> </div> </body> </html> @@ -85,6 +85,16 @@ function displayStatus(msg) { document.getElementById("status").innerHTML = msg; } +function displayScore(score) { + document.getElementById("score").classList.remove("invisible"); + document.getElementById("score-left").innerHTML = score[0]; + document.getElementById("score-right").innerHTML = score[1]; + + setTimeout(function() { + document.getElementById("score").classList.add("invisible"); + }, 2000); +} + function openGame() { socket = io(); socket.on("redirect", function(url) { @@ -95,6 +105,10 @@ function openGame() { displayStatus(msg); }); + socket.on("score", function(score) { + displayScore(score); + }); + socket.on("serve", function(side, x, y) { playing = true; flip = side == "right"; @@ -151,7 +165,12 @@ function stopGraphicsLoop() { function startPhysicsLoop() { var interval = 1 / 120; physicsLoopId = setInterval(function() { - advancePhysics(interval); + if (advancePhysics(interval)) { + socket.emit("ballvec", ballX, ballY, ballVX, ballVY); + } + if (ballX < -ballRadius) { + socket.emit("ballout"); + } }, interval * 1000); } @@ -168,7 +187,10 @@ function initPhysics() { padVel = pad2Vel = 0; } +// Returns whether a new ballvec should be sent function advancePhysics(deltaT) { + var sendBallvec = false; + var newballX = ballX + ballVX * deltaT; var newballY = ballY + ballVY * deltaT; var newpadPos = padPos + padVel * deltaT; @@ -190,6 +212,7 @@ function advancePhysics(deltaT) { if (newballX <= padX + padWidth + ballRadius && Math.abs(newballY - padPos) < padHeight / 2 + ballRadius) { t = (padX + padWidth + ballRadius - ballX) / ballVX; + sendBallvec = true; // rebound from *our* pad } else if (newballX >= 1 - (padX + padWidth + ballRadius) && Math.abs(newballY - pad2Pos) < padHeight / 2 + ballRadius) { t = (1 - (padX + padWidth + ballRadius) - ballX) / ballVX; @@ -201,10 +224,16 @@ function advancePhysics(deltaT) { ballVX = -ballVX; } + if ((ballX < 0.5) ^ (newballX < 0.5)) { + sendBallvec = true; + } + ballX = newballX; ballY = newballY; padPos = newpadPos; pad2Pos = newpad2Pos; + + return sendBallvec; } function setupBindings() { @@ -9,7 +9,7 @@ const app = express(); const server = http.Server(app); const io = socketio(server); -// gameid -> {pl: [socket], started: Bool} +// gameid -> {pl: [socket]*{1,2}, started: Bool, nextServe: Int, score: [Int, Int]} const games = new Map(); function genId() { @@ -74,8 +74,9 @@ io.on("connection", (conn) => { if (!gameobj || gameobj.pl.length != 2) return; gameobj.pl[0].emit("status", ""); gameobj.pl[1].emit("status", ""); - gameobj.pl[0].emit("startBall"); - gameobj.pl[1].emit("start"); + gameobj.pl[0].emit(gameobj.nextServe == 0 ? "startBall" : "start"); + gameobj.pl[1].emit(gameobj.nextServe == 1 ? "startBall" : "start"); + gameobj.nextServe = 1 - gameobj.nextServe; }, 2000); } else { console.log(" full"); @@ -89,7 +90,7 @@ io.on("connection", (conn) => { } else { console.log(" new"); gameid = id; - gameobj = {pl: [conn], started: false}; + gameobj = {pl: [conn], started: false, nextServe: 0, score: [0, 0]}; games.set(gameid, gameobj); conn.emit("status", "Waiting for other player..."); } @@ -129,6 +130,50 @@ io.on("connection", (conn) => { } } }); + + conn.on("ballvec", (x, y, vx, vy) => { + if (!gameobj) return; + for (const p of gameobj.pl) { + if (p != conn) { + p.emit("ballvec", x, y, vx, vy); + } + } + }); + + conn.on("ballout", () => { + if (!gameobj || gameobj.pl.length != 2) return; + + gameobj.pl[0].emit("stop"); + gameobj.pl[1].emit("stop"); + gameobj.pl[0].emit("status", "Ball out!"); + gameobj.pl[1].emit("status", "Ball out!"); + + for (let i = 0; i < gameobj.pl.length; i++) { + if (gameobj.pl[i] != conn) { + gameobj.score[i]++; + } + } + + gameobj.pl[0].emit("score", gameobj.score); + gameobj.pl[1].emit("score", gameobj.score); + + setTimeout(() => { + if (!gameobj || gameobj.pl.length != 2) return; + gameobj.pl[0].emit("status", "Get ready..."); + gameobj.pl[1].emit("status", "Get ready..."); + gameobj.pl[0].emit("serve", "left", 0.5, 0.5); + gameobj.pl[1].emit("serve", "right", 0.5, 0.5); + + setTimeout(() => { + if (!gameobj || gameobj.pl.length != 2) return; + gameobj.pl[0].emit("status", ""); + gameobj.pl[1].emit("status", ""); + gameobj.pl[0].emit(gameobj.nextServe == 0 ? "startBall" : "start"); + gameobj.pl[1].emit(gameobj.nextServe == 1 ? "startBall" : "start"); + gameobj.nextServe = 1 - gameobj.nextServe; + }, 2000); + }, 2000); + }); }); server.listen(PORT, () => console.log("Listening on port " + PORT)); |