Zoom depending on player's area. Not done

This commit is contained in:
Henry Wang 2017-02-24 18:57:13 -06:00
parent 4a0bd33a44
commit 7e6f2505b4
6 changed files with 184 additions and 48 deletions

View File

@ -23,6 +23,17 @@ function verifyRange()
}
}
Color.prototype.interpolateToString = function(color, amount)
{
var rgbThis = hslToRgb(this.hue, this.sat, this.lum);
var rgbThat = hslToRgb(color.hue, color.sat, color.lum);
var rgb = [];
for (var i = 0; i < 3; i++)
rgb[i] = Math.floor((rgbThat[i] - rgbThis[i]) * amount + rgbThis[i]);
return {rgbString: function() {return 'rgb(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ')'}};
}
Color.prototype.deriveLumination = function(amount)
{
var lum = this.lum + amount;

View File

@ -1,5 +1,6 @@
var Player = require("./player.js");
var Grid = require("./grid.js");
var Color = require("./color.js");
/**
* Provides requestAnimationFrame in a cross browser way.
@ -109,6 +110,7 @@ $(function() {
var userPortion = 0;
var lagPortion = 0;
var portionSpeed = 0;
var zoom = 1;
//TODO: current player index
var user = players[0];
@ -226,10 +228,10 @@ $(function() {
function centerOnPlayer(player, pos)
{
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);
var xOff = Math.floor(player.posX - (gameWidth / zoom - CELL_WIDTH) / 2);
var yOff = Math.floor(player.posY - (gameHeight / zoom - CELL_WIDTH) / 2);
pos[0] = Math.max(Math.min(xOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameWidth / zoom), 0);
pos[1] = Math.max(Math.min(yOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameHeight / zoom), 0);
}
function area(player)
@ -305,10 +307,13 @@ $(function() {
//paintGridLines();
//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] + gameHeight) / CELL_WIDTH), grid.size);
var maxCol = Math.min(Math.ceil((offset[0] + gameWidth) / CELL_WIDTH), grid.size);
var offsetX = (offset[0] - BORDER_WIDTH);
var offsetY = (offset[1] - BORDER_WIDTH);
var minRow = Math.max(Math.floor(offsetY / CELL_WIDTH), 0);
var minCol = Math.max(Math.floor(offsetX / CELL_WIDTH), 0);
var maxRow = Math.min(Math.ceil((offsetY + gameHeight / zoom) / CELL_WIDTH), grid.size);
var maxCol = Math.min(Math.ceil((offsetX + gameWidth / zoom) / CELL_WIDTH), grid.size);
//Paint occupied areas. (and fading ones).
for (var r = minRow; r < maxRow; r++)
@ -319,13 +324,16 @@ $(function() {
var x = c * CELL_WIDTH, y = r * CELL_WIDTH, baseColor, shadowColor;
var animateSpec = animateGrid.get(r, c);
var adjust = 1;
if (!animateOff && animateSpec)
{
if (animateSpec.before) //fading animation
{
var alpha = 1 - (animateSpec.frame / ANIMATE_FRAMES);
baseColor = animateSpec.before.baseColor.deriveAlpha(alpha);
shadowColor = animateSpec.before.shadowColor.deriveAlpha(alpha);
var frac = (animateSpec.frame / ANIMATE_FRAMES);
var back = new Color(.58, .41, .92, 1);
baseColor = animateSpec.before.baseColor.interpolateToString(back, frac);
shadowColor = animateSpec.before.shadowColor.interpolateToString(back, frac);
adjust = 0;
}
else
continue;
@ -343,11 +351,12 @@ $(function() {
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);
ctx.fillRect(x, y + CELL_WIDTH + 1, CELL_WIDTH + 1, SHADOW_OFFSET);
}
ctx.fillStyle = baseColor.rgbString();
ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y, CELL_WIDTH + 1, CELL_WIDTH + 1);
}
}
@ -375,9 +384,9 @@ $(function() {
baseColor = animateSpec.after.baseColor.deriveLumination(-(offsetBounce / DROP_HEIGHT) * .1);
ctx.fillStyle = shadowColor.rgbString();
ctx.fillRect(x, y + SHADOW_OFFSET, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y + CELL_WIDTH, CELL_WIDTH, SHADOW_OFFSET);
ctx.fillStyle = baseColor.rgbString();
ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y, CELL_WIDTH + 1, CELL_WIDTH + 1);
}
animateSpec.frame++;
@ -420,12 +429,17 @@ $(function() {
ctx.fillStyle = 'whitesmoke';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
//Draw the grid items.
//Move grid to viewport as said with the offsets, below the stats
ctx.save();
ctx.translate(0, BAR_HEIGHT);
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.rect(0, 0, gameWidth, gameHeight);
ctx.clip();
//Zoom in/out based on player stats.
ctx.scale(zoom, zoom);
ctx.translate(-offset[0] + BORDER_WIDTH, -offset[1] + BORDER_WIDTH);
paintGrid();
players.forEach(function (p) {
var fr = newPlayerFrames[p.num] || 0;
@ -435,8 +449,6 @@ $(function() {
p.render(ctx);
});
//Reset transform to paint fixed UI elements
ctx.restore();
@ -450,6 +462,8 @@ $(function() {
barOffset = ctx.measureText(user.name).width + 10;
ctx.fillText(user.name, 5, CELL_WIDTH - 5);
zoom = .0014 / lagPortion;
//Draw filled bar.
ctx.fillStyle = "rgba(180, 180, 180, .3)";
ctx.fillRect(barOffset, 0, BAR_WIDTH, BAR_HEIGHT);

View File

@ -1,20 +1,79 @@
var Player = require("./player-server.js");
var GRID_SIZE = 80;
var CELL_WIDTH = 40;
var Player = require("./player.js");
function Game(id)
{
var players = [];
var newPlayers = [];
var frame = 0;
var filled = 0;
var grid = new Grid(GRID_SIZE, function(row, col, before, after) {
if (!!after ^ !!before)
{
if (after)
filled++;
else
filled--;
}
});
this.id = id;
this.addPlayer = function(client) {
var p = {num: players.length, client: client};
players.push(p);
newPlayers.push(p);
this.addPlayer = function(client, name) {
var start = findEmpty(grid);
if (!start)
return false;
var params = {
posX: start.col * CELL_WIDTH,
posY: start.row * CELL_WIDTH,
currentHeading: getRandomInt(0, 4),
name: name,
num: players.length
}
var p = new Player(false, grid, params);
p.client = client;
player.push(p);
newPlayer.push(p);
client.emit("game", {players, })
return true;
}
}
function findEmpty(grid)
{
var available = [];
for (var r = 1; r < grid.size - 1; r++)
for (var c = 1; c < grid.size - 1; c++)
{
var cluttered = false;
checkclutter: for (var dr = -1; dr <= 1; dr++)
{
for (var dc = -1; dc <= 1; dc++)
{
if (grid.get(r + dr, c + dc))
{
cluttered = true;
break checkclutter;
}
}
}
if (!cluttered)
available.push({row: r, col: c});
}
if (available.length === 0)
return null;
else
return available[Math.floor(available.length * Math.random())];
}
module.exports = Game;

View File

@ -386,7 +386,16 @@ function Player(isClient, grid, sdata) {
//Instance methods.
this.move = move.bind(this, data);
this.die = function() {data.dead = true;};
this.serialData = function() {
return {
num: data.num,
name: data.name,
posX: data.posX,
posY: data.posY,
currentHeading: data.currentHeading,
tail: data.tail.serialData()
};
}
//Read-only Properties.
defineAccessorProperties(this, data, "currentHeading", "dead", "name", "num", "posX", "posY", "tail");
Object.defineProperties(this, {

View File

@ -24,6 +24,17 @@ function verifyRange()
}
}
Color.prototype.interpolateToString = function(color, amount)
{
var rgbThis = hslToRgb(this.hue, this.sat, this.lum);
var rgbThat = hslToRgb(color.hue, color.sat, color.lum);
var rgb = [];
for (var i = 0; i < 3; i++)
rgb[i] = Math.floor((rgbThat[i] - rgbThis[i]) * amount + rgbThis[i]);
return {rgbString: function() {return 'rgb(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ')'}};
}
Color.prototype.deriveLumination = function(amount)
{
var lum = this.lum + amount;
@ -87,6 +98,7 @@ module.exports = Color;
},{}],2:[function(require,module,exports){
var Player = require("./player.js");
var Grid = require("./grid.js");
var Color = require("./color.js");
/**
* Provides requestAnimationFrame in a cross browser way.
@ -196,6 +208,7 @@ $(function() {
var userPortion = 0;
var lagPortion = 0;
var portionSpeed = 0;
var zoom = 1;
//TODO: current player index
var user = players[0];
@ -313,10 +326,10 @@ $(function() {
function centerOnPlayer(player, pos)
{
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);
var xOff = Math.floor(player.posX - (gameWidth / zoom - CELL_WIDTH) / 2);
var yOff = Math.floor(player.posY - (gameHeight / zoom - CELL_WIDTH) / 2);
pos[0] = Math.max(Math.min(xOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameWidth / zoom), 0);
pos[1] = Math.max(Math.min(yOff, grid.size * CELL_WIDTH + BORDER_WIDTH * 2 - gameHeight / zoom), 0);
}
function area(player)
@ -392,10 +405,13 @@ $(function() {
//paintGridLines();
//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] + gameHeight) / CELL_WIDTH), grid.size);
var maxCol = Math.min(Math.ceil((offset[0] + gameWidth) / CELL_WIDTH), grid.size);
var offsetX = (offset[0] - BORDER_WIDTH);
var offsetY = (offset[1] - BORDER_WIDTH);
var minRow = Math.max(Math.floor(offsetY / CELL_WIDTH), 0);
var minCol = Math.max(Math.floor(offsetX / CELL_WIDTH), 0);
var maxRow = Math.min(Math.ceil((offsetY + gameHeight / zoom) / CELL_WIDTH), grid.size);
var maxCol = Math.min(Math.ceil((offsetX + gameWidth / zoom) / CELL_WIDTH), grid.size);
//Paint occupied areas. (and fading ones).
for (var r = minRow; r < maxRow; r++)
@ -406,13 +422,16 @@ $(function() {
var x = c * CELL_WIDTH, y = r * CELL_WIDTH, baseColor, shadowColor;
var animateSpec = animateGrid.get(r, c);
var adjust = 1;
if (!animateOff && animateSpec)
{
if (animateSpec.before) //fading animation
{
var alpha = 1 - (animateSpec.frame / ANIMATE_FRAMES);
baseColor = animateSpec.before.baseColor.deriveAlpha(alpha);
shadowColor = animateSpec.before.shadowColor.deriveAlpha(alpha);
var frac = (animateSpec.frame / ANIMATE_FRAMES);
var back = new Color(.58, .41, .92, 1);
baseColor = animateSpec.before.baseColor.interpolateToString(back, frac);
shadowColor = animateSpec.before.shadowColor.interpolateToString(back, frac);
adjust = 0;
}
else
continue;
@ -430,11 +449,12 @@ $(function() {
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);
ctx.fillRect(x, y + CELL_WIDTH + 1, CELL_WIDTH + 1, SHADOW_OFFSET);
}
ctx.fillStyle = baseColor.rgbString();
ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y, CELL_WIDTH + 1, CELL_WIDTH + 1);
}
}
@ -462,9 +482,9 @@ $(function() {
baseColor = animateSpec.after.baseColor.deriveLumination(-(offsetBounce / DROP_HEIGHT) * .1);
ctx.fillStyle = shadowColor.rgbString();
ctx.fillRect(x, y + SHADOW_OFFSET, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y + CELL_WIDTH, CELL_WIDTH, SHADOW_OFFSET);
ctx.fillStyle = baseColor.rgbString();
ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
ctx.fillRect(x, y, CELL_WIDTH + 1, CELL_WIDTH + 1);
}
animateSpec.frame++;
@ -507,12 +527,17 @@ $(function() {
ctx.fillStyle = 'whitesmoke';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
//Draw the grid items.
//Move grid to viewport as said with the offsets, below the stats
ctx.save();
ctx.translate(0, BAR_HEIGHT);
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.rect(0, 0, gameWidth, gameHeight);
ctx.clip();
//Zoom in/out based on player stats.
ctx.scale(zoom, zoom);
ctx.translate(-offset[0] + BORDER_WIDTH, -offset[1] + BORDER_WIDTH);
paintGrid();
players.forEach(function (p) {
var fr = newPlayerFrames[p.num] || 0;
@ -522,8 +547,6 @@ $(function() {
p.render(ctx);
});
//Reset transform to paint fixed UI elements
ctx.restore();
@ -537,6 +560,8 @@ $(function() {
barOffset = ctx.measureText(user.name).width + 10;
ctx.fillText(user.name, 5, CELL_WIDTH - 5);
zoom = .0014 / lagPortion;
//Draw filled bar.
ctx.fillStyle = "rgba(180, 180, 180, .3)";
ctx.fillRect(barOffset, 0, BAR_WIDTH, BAR_HEIGHT);
@ -591,7 +616,7 @@ $(function() {
});
});
},{"./grid.js":3,"./player.js":4}],3:[function(require,module,exports){
},{"./color.js":1,"./grid.js":3,"./player.js":4}],3:[function(require,module,exports){
function Grid(size, changeCallback)
{
var grid = new Array(size);
@ -1027,7 +1052,16 @@ function Player(isClient, grid, sdata) {
//Instance methods.
this.move = move.bind(this, data);
this.die = function() {data.dead = true;};
this.serialData = function() {
return {
num: data.num,
name: data.name,
posX: data.posX,
posY: data.posY,
currentHeading: data.currentHeading,
tail: data.tail.serialData()
};
}
//Read-only Properties.
defineAccessorProperties(this, data, "currentHeading", "dead", "name", "num", "posX", "posY", "tail");
Object.defineProperties(this, {

View File

@ -11,6 +11,15 @@
overflow: hidden;
background: black;
}
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
</style>
</head>
<body>