diff --git a/README.md b/README.md index 267bde6..c7df7e2 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,4 @@ npm start ``` it's now listening on *:3001 +![preview2](preview2.png) \ No newline at end of file diff --git a/client/main.js b/client/main.js index 17d2955..1b50cd3 100644 --- a/client/main.js +++ b/client/main.js @@ -5,6 +5,9 @@ let hsize = 300; let current; let players; let room; +let lastScores; +let leaderboard; +let lock; let history = {}; function ellipse(cx, cy, rx, ry) { @@ -26,14 +29,17 @@ function drawPlayer(ratio, p) { ellipse(p.pos.x, p.pos.y, ratio * 3, ratio * 3); if (p.starting > 0) return; - if (!history[p.name]) - history[p.name] = { - i0: 0, - list: new Array(hsize) - }; - else - history[p.name].i0 = (history[p.name].i0 + 1) % hsize; - history[p.name].list[history[p.name].i0] = p.pos; + + if (!lock) { + if (!history[p.name]) + history[p.name] = { + i0: 0, + list: new Array(hsize) + }; + else + history[p.name].i0 = (history[p.name].i0 + 1) % hsize; + history[p.name].list[history[p.name].i0] = p.pos; + } } if (history[p.name]) { @@ -70,30 +76,29 @@ function drawGame() { ctx.clearRect(0, 0, canvas.width, canvas.height); const ratio = canvas.height / window.innerHeight; - const writeTitleText = function (txt, x, y) { - ctx.font = `bold 120px Roboto`; - ctx.textAlign = 'center'; - + const writeText = function (txt, size, x, y, font) { + ctx.font = `${font} ${size}px Roboto`; const lines = txt.split('\n'); - lines.forEach(function (line, i) { ctx.fillStyle = '#4b4b4b'; - ctx.fillText(line, x - 3, y + 37 - (120 * lines.length) / 2 + 120 * i); + ctx.fillText(line, x - size / 40, y + size / 2 - (size * lines.length) / 2 + size * i - size / 40); ctx.fillStyle = '#545454'; - ctx.fillText(line, x, y + 40 - (120 * lines.length) / 2 + 120 * i); + ctx.fillText(line, x, y + size / 2 - (size * lines.length) / 2 + size * i); }); - - }; - writeTitleText(`snex.io\n#${room}`, canvas.width / 2, canvas.height / 2); + ctx.textAlign = 'center'; + writeText(`snex.io\n#${room}`, 120, canvas.width / 2, canvas.height / 2, 'bold'); + + ctx.textAlign = 'left'; + writeText(leaderboard, 30, canvas.width / 30, canvas.height / 15, 'normal'); ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.lineWidth = 3; ctx.textAlign = 'left'; - ctx.font = `normal ${ratio * 10}px Roboto`; + ctx.font = `normal ${ratio * 15}px Roboto`; const names = Object.keys(players); names.forEach(function (name) { drawPlayer(ratio, players[name]); @@ -104,6 +109,16 @@ function drawGame() { requestAnimationFrame(drawGame); } +function updateLeaderboard() { + const pl = Object.keys(players); + const scores = pl.map(p => `${players[p].score} - ${p}`).join('\n'); + if (!lastScores || scores !== lastScores) { + lastScores = scores; + pl.sort((p1, p2) => players[p2].score - players[p1].score); + leaderboard = pl.map(p => `${players[p].score} - ${p}` + (p === current.name ? ' *' : '')).join('\n'); + } +} + const socket = io({ 'reconnection': true, 'reconnectionDelay': 1000, @@ -128,6 +143,7 @@ socket.on('info', function (res) { players = res.players; room = res.room; window.location.hash = '#' + room; + updateLeaderboard(); drawGame(); $(window).focus(function () { socket.emit('history', current); @@ -138,8 +154,13 @@ socket.on('history', function (h) { history = h; }); +socket.on('lock', function (l) { + lock = l; +}); + socket.on('players', function (p) { players = p; + updateLeaderboard(); }); const keys = {}; @@ -167,6 +188,10 @@ $(document).on('keydown', function (e) { $(document).on('keyup', function (e) { switch (e.keyCode) { + case 32://space; + current.color = 'new'; + socket.emit('update', current); + return; case 37://left; if (keys[39]) changeAngle(1); diff --git a/preview2.png b/preview2.png new file mode 100644 index 0000000..f480163 Binary files /dev/null and b/preview2.png differ diff --git a/server.js b/server.js index a1c2d4a..be03e69 100644 --- a/server.js +++ b/server.js @@ -55,9 +55,44 @@ let playerCount = 0; setInterval(function () { //main loop - Object.keys(rooms).forEach(function (room) { - Object.keys(rooms[room].players).forEach(function (name) { - const p = rooms[room].players[name]; + Object.keys(rooms).forEach(function (rname) { + const room = rooms[rname]; + const pl = Object.keys(room.players); + + if (room.waiting > 0) { + room.waiting -= 20; + if (room.waiting <= 0) { //restart + process.stdout.write(`\rroom #${rname} > restarting game \n`); + room.history = {}; + pl.forEach(function (name) { + const p = room.players[name]; + room.players[name] = { + pos: { + x: randInt(100, MAXX - 100), + y: randInt(100, MAXY - 100) + }, + angle: Math.random() * Math.PI, + angleSpd: 0, + color: p.color, + name: p.name, + alive: true, + starting: 2000, + score: p.score + }; + room.history[name] = { + i0: -1, + list: new Array(HSIZE) + } + }); + io.to(rname).emit('players', room.players); + io.to(rname).emit('history', room.history); + io.to(rname).emit('lock', false); + } + return; + } + + pl.forEach(function (name) { + const p = room.players[name]; if (p.alive) { const lastpos = clone(p.pos); p.pos.x += SPD * Math.cos(p.angle); @@ -82,7 +117,7 @@ setInterval(function () { } if (p.starting <= 0) { - const h = rooms[room].history[name]; + const h = room.history[name]; h.i0 = (h.i0 + 1) % HSIZE; h.list[h.i0] = clone(p.pos); } @@ -94,9 +129,9 @@ setInterval(function () { if (ds >= SPD * 1.1) process.stdout.write(`\r${name} moved too quickly : ${ds} [${lastpos.x},${lastpos.y}]->[${p.pos.x},${p.pos.y}]\n`); - Object.keys(rooms[room].history).forEach(function (name2) { + Object.keys(room.history).forEach(function (name2) { if (p.alive && name !== name2) { - const h2 = rooms[room].history[name2]; + const h2 = room.history[name2]; let lastpoint = h2.list[h2.i0]; if (!lastpoint) return; @@ -106,7 +141,7 @@ setInterval(function () { if (Math.abs(lastpoint.x - point.x) < 1600 * .9 && Math.abs(lastpoint.y - point.y) < 900 * .9) { intersectCount++; if (intersects(lastpos, p.pos, lastpoint, point)) { - process.stdout.write(`\r${name} collided with ${name2} \n`); + process.stdout.write(`\rroom #${rname} > ${name} collided with ${name2} \n`); p.alive = false; break; } @@ -125,7 +160,15 @@ setInterval(function () { } }); - io.to(room).emit('players', rooms[room].players); + const palive = pl.filter(p => room.players[p].alive); + + if (pl.length > 1 && palive.length === 1) { //end of game + room.players[palive[0]].score++; + room.waiting = 3000; + process.stdout.write(`\rroom #${rname} > ${palive[0]} won \n`); + io.to(rname).emit('lock', true); + } + io.to(rname).emit('players', room.players); }); updateCount++; }, 20); @@ -154,6 +197,7 @@ io.on('connection', function (socket) { if (!rooms[socket.room]) { rooms[socket.room] = { + waiting: 0, players: {}, history: {} } @@ -169,7 +213,8 @@ io.on('connection', function (socket) { color: randomColor(), name: socket.name, alive: true, - starting: 2000 + starting: 2000, + score: 0 }; rooms[socket.room].history[socket.name] = { i0: -1, @@ -215,6 +260,8 @@ io.on('connection', function (socket) { } if (!p.alive) return; + if (newp.color === 'new') + rooms[socket.room].players[newp.name].color = randomColor(); if (newp.angleSpd > 0) rooms[socket.room].players[newp.name].angleSpd = MAX_ANGLE_SPEED; else if (newp.angleSpd < 0)