From 8e152bd33c6777616a01d928ee265d56486eb1c0 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Thu, 23 Feb 2017 22:02:47 +0000 Subject: [PATCH] Some UI touches, start experimenting with node.js --- game.js | 202 +++++++++++++++++++++++++++++++++++++++++------------- player.js | 23 ++++--- server.js | 5 ++ test.html | 28 ++++++-- 4 files changed, 196 insertions(+), 62 deletions(-) create mode 100644 server.js diff --git a/game.js b/game.js index 48f3aca..94d1462 100644 --- a/game.js +++ b/game.js @@ -12,9 +12,9 @@ if (!Grid) * Provides requestAnimationFrame in a cross browser way. * @author paulirish / http://paulirish.com/ */ -window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { - window.setTimeout( callback, 1000 / 60 ); - }; +// window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { +// window.setTimeout( callback, 1000 / 60 ); +// }; if ( !window.requestAnimationFrame ) { window.requestAnimationFrame = ( function() { return window.webkitRequestAnimationFrame || @@ -30,24 +30,41 @@ if ( !window.requestAnimationFrame ) { $(function() { var BORDER_WIDTH = 20; - var GRID_SIZE = 200; - var CELL_WIDTH = 30; + var GRID_SIZE = 80; + var CELL_WIDTH = 40; var SPEED = 5; var SHADOW_OFFSET = 5; - var MAX_FRAMES = 16; - var DROP_HEIGHT = 16; - var BOUNCE_FRAMES = 8; + var ANIMATE_FRAMES = 24; + var BOUNCE_FRAMES = [8, 4]; + var DROP_HEIGHT = 24; var DROP_SPEED = 2; + var MIN_BAR_WIDTH = 65; + var BAR_HEIGHT = SHADOW_OFFSET + CELL_WIDTH; + var BAR_WIDTH = 400; var canvas = $("#main-ui")[0]; var ctx = canvas.getContext('2d'); - var width = canvas.width = window.innerWidth - 20; - var height = canvas.height = window.innerHeight - 20; + var canvasWidth = canvas.width = window.innerWidth; + var canvasHeight = canvas.height = window.innerHeight - 20; + canvas.style.marginTop = 20 / 2; + var gameWidth = canvasWidth; + var gameHeight = canvasHeight - BAR_HEIGHT; + + var newPlayerFrames = []; + var playerPortion = []; + var allPlayers = []; var players = []; - var animateOff = true; + var animateOff = false; var animateGrid = new Grid(GRID_SIZE); var grid = new Grid(GRID_SIZE, function(row, col, before, after) { + //Keep track of areas. + if (before) + playerPortion[before.num]--; + if (after) + playerPortion[after.num]++; + + //Queue animation if (before === after || animateOff) return; animateGrid.set(row, col, { @@ -61,7 +78,16 @@ $(function() { for (var p = 0; p < 9; p++) { //TODO: socket loading. - players[p] = new Player(null, grid, p, getRandomInt(0, GRID_SIZE), getRandomInt(0, GRID_SIZE)); + var pRow = getRandomInt(0, GRID_SIZE); + var pCol = getRandomInt(0, GRID_SIZE); + + playerPortion[p] = 0; + allPlayers[p] = players[p] = new Player(null, grid, p, pRow, pCol); + + for (var dr = -1; dr <= 1; dr++) + for (var dc = -1; dc <= 1; dc++) + if (!grid.isOutOfBounds(dr + pRow, dc + pCol)) + grid.set(dr + pRow, dc + pCol, players[p]); } //Load grid. @@ -70,8 +96,8 @@ $(function() { for (var c = 0; c < grid.size; c++) { //TODO: load data. - if (Math.random() > .9) - grid.set(r, c, players[getRandomInt(0, players.length)]); + //if (Math.random() > .9) + // grid.set(r, c, players[getRandomInt(0, players.length)]); } } animateOff = false; @@ -80,8 +106,13 @@ $(function() { var animateTo = [0, 0]; var offset = [0, 0]; + var userPortion = 0; + var lagPortion = 0; + var portionSpeed = 0; + //TODO: current player index var user = players[0]; + centerOnPlayer(user, offset); function update() @@ -98,11 +129,26 @@ $(function() { } } + //Change area percentage + if (lagPortion !== userPortion) + { + delta = userPortion - lagPortion; + dir = Math.sign(delta); + mag = Math.min(Math.abs(portionSpeed), Math.abs(delta)); + lagPortion += dir * mag; + } //Move players. var dead = []; players = players.filter(function(val) { - val.move(); + if (!newPlayerFrames[val.num]) + newPlayerFrames[val.num] = 0; + + if (newPlayerFrames[val.num] < ANIMATE_FRAMES) + newPlayerFrames[val.num]++; + else + val.move(); + if (val.dead) dead.push(val); return !val.dead; @@ -158,6 +204,7 @@ $(function() { dead.forEach(function(val) { console.log(val.name + " is dead"); + allPlayers[val.num] = undefined; }); for (var r = 0; r < grid.size; r++) { @@ -168,16 +215,21 @@ $(function() { } } - //TODO: animate dead, and if this player is dead. + //Update user's portions and top ranks. + userPortion = playerPortion[user.num] / (GRID_SIZE * GRID_SIZE); + portionSpeed = Math.abs(userPortion - lagPortion) / ANIMATE_FRAMES; + + //TODO: animate player is dead. (maybe explosion?) + //TODO: show when this player is dead centerOnPlayer(user, animateTo); } function centerOnPlayer(player, pos) { - var xOff = Math.floor(player.posX - (width - CELL_WIDTH) / 2); - var yOff = Math.floor(player.posY - (height - CELL_WIDTH) / 2); - pos[0] = Math.max(Math.min(xOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - width), 0); - pos[1] = Math.max(Math.min(yOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - height), 0); + var xOff = Math.floor(player.posX - (gameWidth - CELL_WIDTH) / 2); + var yOff = Math.floor(player.posY - (gameHeight - CELL_WIDTH) / 2); + pos[0] = Math.max(Math.min(xOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameWidth), 0); + pos[1] = Math.max(Math.min(yOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameHeight), 0); } function area(player) @@ -221,15 +273,15 @@ $(function() { { ctx.fillStyle = 'lightgray'; ctx.beginPath(); - for (var x = modRotate(-offset[0], CELL_WIDTH); x < width; x += CELL_WIDTH) + for (var x = modRotate(-offset[0], CELL_WIDTH); x < gameWidth; x += CELL_WIDTH) { ctx.moveTo(x, 0); - ctx.lineTo(x, height); + ctx.lineTo(x, gameHeight); } - for (var y = modRotate(-offset[1], CELL_WIDTH); y < height; y+= CELL_WIDTH) + for (var y = modRotate(-offset[1], CELL_WIDTH); y < gameHeight; y+= CELL_WIDTH) { ctx.moveTo(0, y); - ctx.lineTo(width, y); + ctx.lineTo(gameWidth, y); } ctx.stroke(); } @@ -245,7 +297,9 @@ $(function() { function paintGrid() { - ctx.translate(BORDER_WIDTH, BORDER_WIDTH); + //Paint background. + ctx.fillStyle = "#e2ebf3"; + ctx.fillRect(0, 0, CELL_WIDTH * GRID_SIZE, CELL_WIDTH * GRID_SIZE); paintGridBorder(); //paintGridLines(); @@ -253,8 +307,8 @@ $(function() { //Get viewing limits var minRow = Math.max(Math.floor((offset[1] - BORDER_WIDTH) / CELL_WIDTH), 0); var minCol = Math.max(Math.floor((offset[0] - BORDER_WIDTH) / CELL_WIDTH), 0); - var maxRow = Math.min(Math.ceil((offset[1] + height) / CELL_WIDTH), grid.size); - var maxCol = Math.min(Math.ceil((offset[0] + width) / CELL_WIDTH), grid.size); + var maxRow = Math.min(Math.ceil((offset[1] + gameHeight) / CELL_WIDTH), grid.size); + var maxCol = Math.min(Math.ceil((offset[0] + gameWidth) / CELL_WIDTH), grid.size); //Paint occupied areas. (and fading ones). for (var r = minRow; r < maxRow; r++) @@ -269,7 +323,7 @@ $(function() { { if (animateSpec.before) //fading animation { - var alpha = 1 - (animateSpec.frame / MAX_FRAMES); + var alpha = 1 - (animateSpec.frame / ANIMATE_FRAMES); baseColor = animateSpec.before.baseColor.deriveAlpha(alpha); shadowColor = animateSpec.before.shadowColor.deriveAlpha(alpha); } @@ -284,7 +338,10 @@ $(function() { else //No animation nor is this player owned. continue; - if (!grid.isOutOfBounds(r + 1, c) && !grid.get(r + 1, c) && !animateGrid.get(r + 1, c)) + var hasBottom = !grid.isOutOfBounds(r + 1, c); + var bottomAnimate = hasBottom && animateGrid.get(r + 1, c); + var bottomEmpty = !bottomAnimate || (bottomAnimate.after && bottomAnimate.before); + if (hasBottom && ((!!bottomAnimate ^ !!animateSpec) || bottomEmpty)) { ctx.fillStyle = shadowColor.rgbString(); ctx.fillRect(x, y + CELL_WIDTH, CELL_WIDTH, SHADOW_OFFSET); @@ -311,19 +368,7 @@ $(function() { if (animateSpec.after && viewable) { //Bouncing the squares. - var offsetBounce = 0; - if (animateSpec.frame >= MAX_FRAMES - BOUNCE_FRAMES) - { - var bounce = animateSpec.frame - MAX_FRAMES + BOUNCE_FRAMES; - var bounceHeight = BOUNCE_FRAMES / 2 * DROP_SPEED; - if (bounce >= BOUNCE_FRAMES / 2) - offsetBounce = bounceHeight - (bounce - BOUNCE_FRAMES / 2) * DROP_SPEED; - else - offsetBounce = bounce * DROP_SPEED; - } - else - offsetBounce = DROP_HEIGHT - DROP_SPEED * animateSpec.frame; - + var offsetBounce = getBounceOffset(animateSpec.frame); y -= offsetBounce; shadowColor = animateSpec.after.shadowColor; @@ -336,26 +381,89 @@ $(function() { } animateSpec.frame++; - if (animateSpec.frame >= MAX_FRAMES) + if (animateSpec.frame >= ANIMATE_FRAMES) animateGrid.set(r, c, null); } } } } + function getBounceOffset(frame) + { + var offsetBounce = ANIMATE_FRAMES; + var bounceNum = BOUNCE_FRAMES.length - 1; + while (bounceNum >= 0 && frame < offsetBounce - BOUNCE_FRAMES[bounceNum]) + { + offsetBounce -= BOUNCE_FRAMES[bounceNum]; + bounceNum--; + } + + if (bounceNum === -1) + { + return (offsetBounce - frame) * DROP_SPEED; + } + else + { + offsetBounce -= BOUNCE_FRAMES[bounceNum]; + frame = frame - offsetBounce; + var midFrame = BOUNCE_FRAMES[bounceNum] / 2; + if (frame >= midFrame) + return (BOUNCE_FRAMES[bounceNum] - frame) * DROP_SPEED; + else + return frame * DROP_SPEED; + } + } var showedDead = false; function paintLoop() { ctx.fillStyle = 'whitesmoke'; - ctx.fillRect(0, 0, width, height); + ctx.fillRect(0, 0, canvasWidth, canvasHeight); - ctx.translate(-offset[0], -offset[1]); + //Draw the grid items. + ctx.save(); + ctx.beginPath(); + ctx.translate(-offset[0] + BORDER_WIDTH, -offset[1] + BORDER_WIDTH + BAR_HEIGHT); + ctx.rect(offset[0] - BORDER_WIDTH, offset[1] - BORDER_WIDTH, canvasWidth, canvasHeight); + ctx.clip(); paintGrid(); players.forEach(function (p) { - p.render(ctx); + var fr = newPlayerFrames[p.num] || 0; + if (fr < ANIMATE_FRAMES) + p.render(ctx, fr / ANIMATE_FRAMES); + else + p.render(ctx); }); - ctx.setTransform(1, 0, 0, 1, 0, 0); //Reset transform. + + + + //Reset transform to paint fixed UI elements + ctx.restore(); + + //UI Bar background + ctx.fillStyle = "#24422c"; + ctx.fillRect(0, 0, canvasWidth, BAR_HEIGHT); + + var barOffset; + ctx.fillStyle = "white"; + ctx.font = "24px Arial"; + barOffset = ctx.measureText(user.name).width + 10; + ctx.fillText(user.name, 5, CELL_WIDTH - 5); + + //Draw filled bar. + ctx.fillStyle = "rgba(180, 180, 180, .3)"; + ctx.fillRect(barOffset, 0, BAR_WIDTH, BAR_HEIGHT); + + var barSize = Math.ceil((BAR_WIDTH - MIN_BAR_WIDTH) * lagPortion + MIN_BAR_WIDTH); + ctx.fillStyle = user.baseColor.rgbString(); + ctx.fillRect(barOffset, 0, barSize, CELL_WIDTH); + ctx.fillStyle = user.shadowColor.rgbString(); + ctx.fillRect(barOffset, CELL_WIDTH, barSize, SHADOW_OFFSET); + + //Percentage + ctx.fillStyle = "white"; + ctx.font = "18px Arial"; + ctx.fillText((lagPortion * 100).toFixed(3) + "%", 5 + barOffset, CELL_WIDTH - 5); if (user.dead && !showedDead) { diff --git a/player.js b/player.js index 7472ad7..8464d5c 100644 --- a/player.js +++ b/player.js @@ -7,8 +7,8 @@ if (!Color) throw new Error("Requre color.js"); var Tail = (function() { - var CELL_WIDTH = 30; - var GRID_SIZE = 200; + var CELL_WIDTH = 40; + var GRID_SIZE = 80; function TailMove(orientation) { @@ -111,7 +111,7 @@ var Tail = (function() { var prevOrient = -1; var start = [data.startRow, data.startCol]; - fillTailRect(ctx, start, start); + //fillTailRect(ctx, start, start); data.tail.forEach(function(tail) { var negDir = tail.orientation === 0 || tail.orientation === 3; @@ -293,14 +293,15 @@ var Tail = (function() { function hitsTail(data, other) { - return (data.prevRow !== other.row || data.prevCol !== other.col) && + return (data.prevRow !== other.row || data.prevCol !== other.col) && + (data.startRow !== other.row || data.startCol !== other.col) && !!(data.tailGrid[other.row] && data.tailGrid[other.row][other.col]); } return Tail; }()); this.Player = (function() { - var CELL_WIDTH = 30; + var CELL_WIDTH = 40; var SPEED = 5; var SHADOW_OFFSET = 10; @@ -345,22 +346,28 @@ this.Player = (function() { } //Instance methods - Player.prototype.render = function(ctx) + Player.prototype.render = function(ctx, fade) { //Render tail. this.tail.render(ctx); //Render player. - ctx.fillStyle = this.shadowColor.rgbString(); + fade = fade || 1; + ctx.fillStyle = this.shadowColor.deriveAlpha(fade).rgbString(); ctx.fillRect(this.posX, this.posY, CELL_WIDTH, CELL_WIDTH); var mid = CELL_WIDTH / 2; var grd = ctx.createRadialGradient(this.posX + mid, this.posY + mid - SHADOW_OFFSET, 1, this.posX + mid, this.posY + mid - SHADOW_OFFSET, CELL_WIDTH); - grd.addColorStop(0, this.baseColor.rgbString()); + grd.addColorStop(0, this.baseColor.deriveAlpha(fade).rgbString()); grd.addColorStop(1, "white"); ctx.fillStyle = grd; ctx.fillRect(this.posX, this.posY - SHADOW_OFFSET, CELL_WIDTH, CELL_WIDTH); + + //Render name + ctx.fillStyle = this.shadowColor.deriveAlpha(fade).rgbString(); + ctx.textAlign = "center"; + ctx.fillText(this.name, this.posX + CELL_WIDTH / 2, this.posY - SHADOW_OFFSET * 2); }; function move(data) diff --git a/server.js b/server.js new file mode 100644 index 0000000..0adf361 --- /dev/null +++ b/server.js @@ -0,0 +1,5 @@ +io.on('connection', function(socket){ + socket.emit('request', /* */); // emit an event to the socket + io.emit('broadcast', /* */); // emit an event to all connected sockets + socket.on('reply', function(){ /* */ }); // listen to the event +}); \ No newline at end of file diff --git a/test.html b/test.html index 4a35a7e..e374cfa 100644 --- a/test.html +++ b/test.html @@ -1,7 +1,21 @@ - - - - - - - \ No newline at end of file + + + + + + + + + + + + \ No newline at end of file