Separate rendering and client code, fixes #3

This commit is contained in:
theKidOfArcrania 2017-09-04 16:27:08 +00:00
parent 7ff47d8efc
commit c8cd3d474b
4 changed files with 4435 additions and 4266 deletions

View File

@ -1,51 +1,38 @@
/* global $ */ /* global $ */
var Player = require("./player.js"); var client = require("./player-client.js");
var renderer = require("./game-renderer.js");
var consts = require("./game-consts.js"); var consts = require("./game-consts.js");
var core = require("./game-core.js");
var io = require('socket.io-client'); var io = require('socket.io-client');
var GRID_SIZE = consts.GRID_SIZE; var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH; var CELL_WIDTH = consts.CELL_WIDTH;
renderer.allowAnimation = true; client.allowAnimation = true;
client.renderer = require("./game-renderer.js");
/** /**
* Provides requestAnimationFrame in a cross browser way. * Provides requestAnimationFrame in a cross browser way. (edited so that this is also compatible with node.)
* @author paulirish / http://paulirish.com/ * @author paulirish / http://paulirish.com/
*/ */
// window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { // window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
// window.setTimeout( callback, 1000 / 60 ); // window.setTimeout( callback, 1000 / 60 );
// }; // };
if ( !window.requestAnimationFrame ) { var global;
window.requestAnimationFrame = ( function() { if (!global)
return window.webkitRequestAnimationFrame || global = window;
window.mozRequestAnimationFrame || if ( !global.requestAnimationFrame ) {
window.oRequestAnimationFrame || global.requestAnimationFrame = ( function() {
window.msRequestAnimationFrame || return global.webkitRequestAnimationFrame ||
global.mozRequestAnimationFrame ||
global.oRequestAnimationFrame ||
global.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 ); global.setTimeout( callback, 1000 / 60 );
}; };
})(); })();
} }
var norun = false;
function run() { function run() {
if (norun) client.connectGame('//' + window.location.hostname + ':8081', $('#name').val(), function(success, msg) {
return; //Prevent multiple clicks.
norun = true;
user = null;
deadFrames = 0;
//Socket connection.
//, {transports: ['websocket'], upgrade: false}
connectServer();
socket.emit('hello', {
name: $("#name").val(),
type: 0, //Free-for-all
gameid: -1 //Requested game-id, or -1 for anyone.
}, function(success, msg) {
if (success) if (success)
{ {
console.info("Connected to game!"); console.info("Connected to game!");
@ -59,7 +46,6 @@ function run() {
console.error("Unable to connect to game: " + msg); console.error("Unable to connect to game: " + msg);
var error = $("#error"); var error = $("#error");
error.text(msg); error.text(msg);
norun = false;
} }
}); });
} }
@ -84,7 +70,7 @@ $(function() {
socket.on('connect_error', function() { socket.on('connect_error', function() {
if (!success) if (!success)
error.text("Cannot connect with server. This probably is due to misconfigured proxy server. (Try using a different browser)"); error.text("Cannot connect with server. This probably is due to misconfigured proxy server. (Try using a different browser)");
}) });
socket.emit("checkConn", function() { socket.emit("checkConn", function() {
success = true; success = true;
socket.disconnect(); socket.disconnect();
@ -106,12 +92,9 @@ $(function() {
}, 2000); }, 2000);
}); });
var user, socket, frame;
//Event listeners //Event listeners
$(document).keydown(function(e) { $(document).keydown(function(e) {
if (!user || user.dead)
return;
var newHeading = -1; var newHeading = -1;
switch (e.which) switch (e.which)
{ {
@ -122,231 +105,6 @@ $(document).keydown(function(e) {
default: return; //exit handler for other keys. default: return; //exit handler for other keys.
} }
if (newHeading === user.currentHeading || ((newHeading % 2 === 0) ^ client.changeHeading(newHeading);
(user.currentHeading % 2 === 0)))
{
//user.heading = newHeading;
if (socket)
socket.emit("frame", {
frame: frame,
heading: newHeading
}, function(success, msg) {
if (!success)
console.error(msg);
});
}
e.preventDefault(); e.preventDefault();
}); });
var grid = renderer.grid;
var timeout = undefined;
var dirty = false;
var deadFrames = 0;
var requesting = -1; //frame that we are requesting at.
var frameCache = []; //Frames after our request.
//TODO: check if we can connect to server.
function connectServer() {
io.j = [];
io.sockets = [];
socket = io('http://' + window.location.hostname + ':8081', {
'forceNew': true,
upgrade: false,
transports: ['websocket']
});
socket.on('connect', function(){
console.info("Connected to server.");
});
socket.on('game', function(data) {
if (timeout != undefined)
clearTimeout(timeout);
//Initialize game.
//TODO: display data.gameid --- game id #
frame = data.frame;
renderer.reset();
//Load players.
data.players.forEach(function(p) {
var pl = new Player(grid, p);
renderer.addPlayer(pl);
});
user = renderer.getPlayerFromNum(data.num);
if (!user) throw new Error();
renderer.setUser(user);
//Load grid.
var gridData = new Uint8Array(data.grid);
for (var r = 0; r < grid.size; r++)
for (var c = 0; c < grid.size; c++)
{
var ind = gridData[r * grid.size + c] - 1;
grid.set(r, c, ind === -1 ? null : renderer.getPlayer(ind));
}
renderer.paint();
frame = data.frame;
if (requesting !== -1)
{
//Update those cache frames after we updated game.
var minFrame = requesting;
requesting = -1;
while (frameCache.length > frame - minFrame)
processFrame(frameCache[frame - minFrame]);
frameCache = [];
}
});
socket.on('notifyFrame', processFrame);
socket.on('dead', function() {
socket.disconnect(); //In case we didn't get the disconnect call.
});
socket.on('disconnect', function(){
if (!user)
return;
console.info("Server has disconnected. Creating new game.");
socket.disconnect();
user.die();
dirty = true;
paintLoop();
//TODO: Show score stats.
//Show score stats.
$("#stats").removeClass("hidden");
$("#stats").animate({
opacity: .9999
}, 3000, function() {
showStats();
});
//Then fade back into the login screen.
});
}
function showStats() {
$("#begin").removeClass("hidden");
$("#begin").animate({
opacity: .9999
}, 1000, function() {
$("#stats").addClass("hidden").css("opacity", 0);
norun = false;
});
}
function processFrame(data)
{
if (timeout != undefined)
clearTimeout(timeout);
if (requesting !== -1 && requesting < data.frame)
{
frameCache.push(data);
return;
}
if (data.frame - 1 !== frame)
{
console.error("Frames don't match up!");
socket.emit('requestFrame'); //Restore data.
requesting = data.frame;
frameCache.push(data);
return;
}
frame++;
if (data.newPlayers)
{
data.newPlayers.forEach(function(p) {
if (p.num === user.num)
return;
var pl = new Player(grid, p);
renderer.addPlayer(pl);
core.initPlayer(grid, pl);
});
}
var found = new Array(renderer.playerSize());
data.moves.forEach(function(val, i) {
var player = renderer.getPlayerFromNum(val.num);
if (!player) return;
if (val.left) player.die();
found[i] = true;
player.heading = val.heading;
});
for (var i = 0; i < renderer.playerSize(); i++)
{
//Implicitly leaving game.
if (!found[i])
{
var player = renderer.getPlayer();
player && player.die();
}
}
renderer.update();
var locs = {};
for (var i = 0; i < renderer.playerSize(); i++)
{
var p = renderer.getPlayer(i);
locs[p.num] = [p.posX, p.posY, p.waitLag];
}
socket.emit("verify", {
frame: frame,
locs: locs
}, function(frame, success, adviceFix, msg) {
if (!success && requesting === -1)
{
console.error(frame + ": " + msg);
if (adviceFix)
socket.emit('requestFrame');
}
}.bind(this, frame));
dirty = true;
requestAnimationFrame(function() {
paintLoop();
});
timeout = setTimeout(function() {
console.warn("Server has timed-out. Disconnecting.");
socket.disconnect();
}, 3000);
}
function paintLoop()
{
if (!dirty)
return;
renderer.paint();
dirty = false;
if (user.dead)
{
if (timeout)
clearTimeout(timeout);
if (deadFrames === 60) //One second of frame
{
var before = renderer.allowAnimation;
renderer.allowAnimation = false;
renderer.update();
renderer.paint();
renderer.allowAnimation = before;
user = null;
deadFrames = 0;
return;
}
socket.disconnect();
deadFrames++;
dirty = true;
renderer.update();
requestAnimationFrame(paintLoop);
}
}

View File

@ -3,7 +3,7 @@ var Rolling = require("./rolling.js");
var Color = require("./color.js"); var Color = require("./color.js");
var Grid = require("./grid.js"); var Grid = require("./grid.js");
var consts = require("./game-consts.js"); var consts = require("./game-consts.js");
var core = require("./game-core.js"); var client = require("./player-client.js");
var GRID_SIZE = consts.GRID_SIZE; var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH; var CELL_WIDTH = consts.CELL_WIDTH;
@ -33,28 +33,9 @@ $(function () {
}); });
var animateGrid, playerPortion, portionsRolling,
barProportionRolling, animateTo, offset, user, zoom, showedDead;
var allowAnimation = true; var grid = client.grid;
var animateGrid, players, allPlayers, playerPortion, portionsRolling,
barProportionRolling, grid, animateTo, offset, user, zoom, kills, showedDead;
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 || !allowAnimation)
return;
animateGrid.set(row, col, {
before: before,
after: after,
frame: 0
});
});
function updateSize() function updateSize()
{ {
@ -76,12 +57,9 @@ function updateSize()
centerOnPlayer(user, offset); centerOnPlayer(user, offset);
} }
function init() { function reset() {
animateGrid = new Grid(GRID_SIZE); animateGrid = new Grid(GRID_SIZE);
grid.reset();
players = [];
allPlayers = [];
playerPortion = []; playerPortion = [];
portionsRolling = []; portionsRolling = [];
barProportionRolling = []; barProportionRolling = [];
@ -91,11 +69,11 @@ function init() {
user = null; user = null;
zoom = 1; zoom = 1;
kills = 0;
showedDead = false; showedDead = false;
} }
init(); reset();
//Paint methods. //Paint methods.
function paintGridBorder(ctx) function paintGridBorder(ctx)
@ -136,7 +114,7 @@ function paintGrid(ctx)
var x = c * CELL_WIDTH, y = r * CELL_WIDTH, baseColor, shadowColor; var x = c * CELL_WIDTH, y = r * CELL_WIDTH, baseColor, shadowColor;
var animateSpec = animateGrid.get(r, c); var animateSpec = animateGrid.get(r, c);
if (allowAnimation && animateSpec) if (client.allowAnimation && animateSpec)
{ {
if (animateSpec.before) //fading animation if (animateSpec.before) //fading animation
{ {
@ -172,7 +150,7 @@ function paintGrid(ctx)
} }
} }
if (!allowAnimation) if (!client.allowAnimation)
return; return;
//Paint squares with drop in animation. //Paint squares with drop in animation.
@ -183,7 +161,7 @@ function paintGrid(ctx)
animateSpec = animateGrid.get(r, c); animateSpec = animateGrid.get(r, c);
x = c * CELL_WIDTH, y = r * CELL_WIDTH; x = c * CELL_WIDTH, y = r * CELL_WIDTH;
if (animateSpec && allowAnimation) if (animateSpec && client.allowAnimation)
{ {
var viewable = r >= minRow && r < maxRow && c >= minCol && c < maxCol; var viewable = r >= minRow && r < maxRow && c >= minCol && c < maxCol;
if (animateSpec.after && viewable) if (animateSpec.after && viewable)
@ -212,6 +190,7 @@ function paintGrid(ctx)
function paintUIBar(ctx) function paintUIBar(ctx)
{ {
//UI Bar background //UI Bar background
ctx.fillStyle = "#24422c"; ctx.fillStyle = "#24422c";
ctx.fillRect(0, 0, canvasWidth, BAR_HEIGHT); ctx.fillRect(0, 0, canvasWidth, BAR_HEIGHT);
@ -240,13 +219,13 @@ function paintUIBar(ctx)
ctx.fillText((userPortions * 100).toFixed(3) + "%", 5 + barOffset, CELL_WIDTH - 5); ctx.fillText((userPortions * 100).toFixed(3) + "%", 5 + barOffset, CELL_WIDTH - 5);
//Number of kills //Number of kills
var killsText = "Kills: " + kills; var killsText = "Kills: " + client.kills;
var killsOffset = 20 + BAR_WIDTH + barOffset; var killsOffset = 20 + BAR_WIDTH + barOffset;
ctx.fillText(killsText, killsOffset, CELL_WIDTH - 5); ctx.fillText(killsText, killsOffset, CELL_WIDTH - 5);
//Calcuate rank //Calcuate rank
var sorted = []; var sorted = [];
players.forEach(function(val) { client.getPlayers().forEach(function(val) {
sorted.push({player: val, portion: playerPortion[val.num]}); sorted.push({player: val, portion: playerPortion[val.num]});
}); });
sorted.sort(function(a, b) { sorted.sort(function(a, b) {
@ -262,12 +241,11 @@ function paintUIBar(ctx)
if (sorted.length > 0) if (sorted.length > 0)
{ {
var maxPortion = sorted[0].portion; var maxPortion = sorted[0].portion;
for (var i = 0; i < players.length; i++) client.getPlayers().forEach(function(player) {
{ var rolling = barProportionRolling[player.num];
var rolling = barProportionRolling[players[i].num]; rolling.value = playerPortion[player.num] / maxPortion;
rolling.value = playerPortion[players[i].num] / maxPortion;
rolling.update(); rolling.update();
} });
} }
//Show leaderboard. //Show leaderboard.
@ -303,6 +281,7 @@ function paintUIBar(ctx)
function paint(ctx) function paint(ctx)
{ {
ctx.fillStyle = '#e2ebf3'; //'whitesmoke'; ctx.fillStyle = '#e2ebf3'; //'whitesmoke';
ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.fillRect(0, 0, canvasWidth, canvasHeight);
@ -318,7 +297,7 @@ function paint(ctx)
ctx.translate(-offset[0] + BORDER_WIDTH, -offset[1] + BORDER_WIDTH); ctx.translate(-offset[0] + BORDER_WIDTH, -offset[1] + BORDER_WIDTH);
paintGrid(ctx); paintGrid(ctx);
players.forEach(function (p) { client.getPlayers().forEach(function (p) {
var fr = p.waitLag; var fr = p.waitLag;
if (fr < ANIMATE_FRAMES) if (fr < ANIMATE_FRAMES)
p.render(ctx, fr / ANIMATE_FRAMES); p.render(ctx, fr / ANIMATE_FRAMES);
@ -352,7 +331,7 @@ function update() {
{ {
if (animateTo[i] !== offset[i]) if (animateTo[i] !== offset[i])
{ {
if (allowAnimation) if (client.allowAnimation)
{ {
var delta = animateTo[i] - offset[i]; var delta = animateTo[i] - offset[i];
var dir = Math.sign(delta); var dir = Math.sign(delta);
@ -365,29 +344,16 @@ function update() {
} }
//Calculate player portions. //Calculate player portions.
for (var i = 0; i < players.length; i++) client.getPlayers().forEach(function(player) {
{ var roll = portionsRolling[player.num];
var roll = portionsRolling[players[i].num]; roll.value = playerPortion[player.num] / GRID_SIZE / GRID_SIZE;
roll.value = playerPortion[players[i].num] / GRID_SIZE / GRID_SIZE;
roll.update(); roll.update();
} });
//Zoom goes from 1 to .5, decreasing as portion goes up. TODO: maybe can modify this? //Zoom goes from 1 to .5, decreasing as portion goes up. TODO: maybe can modify this?
if (portionsRolling[user.num]) if (portionsRolling[user.num])
zoom = 1 / (portionsRolling[user.num].lag + 1); zoom = 1 / (portionsRolling[user.num].lag + 1);
var dead = [];
core.updateFrame(grid, players, dead, function addKill(killer, other)
{
if (players[killer] === user && killer !== other)
kills++;
});
dead.forEach(function(val) {
console.log(val.name || "Unnamed" + " is dead");
delete allPlayers[val.num];
delete portionsRolling[val.num];
});
//TODO: animate player is dead. (maybe explosion?), and tail rewinds itself. //TODO: animate player is dead. (maybe explosion?), and tail rewinds itself.
if (user) centerOnPlayer(user, animateTo); if (user) centerOnPlayer(user, animateTo);
} }
@ -428,51 +394,59 @@ function getBounceOffset(frame)
} }
} }
function showStats() {
//TODO: Show score stats.
$("#begin").removeClass("hidden");
$("#begin").animate({
opacity: .9999
}, 1000, function() {
$("#stats").addClass("hidden").css("opacity", 0);
});
}
module.exports = exports = { module.exports = exports = {
addPlayer: function(player) { addPlayer: function(player) {
if (allPlayers[player.num])
return; //Already added.
allPlayers[player.num] = players[players.length] = player;
playerPortion[player.num] = 0; playerPortion[player.num] = 0;
portionsRolling[player.num] = new Rolling(9 / GRID_SIZE / GRID_SIZE, ANIMATE_FRAMES); portionsRolling[player.num] = new Rolling(9 / GRID_SIZE / GRID_SIZE, ANIMATE_FRAMES);
barProportionRolling[player.num] = new Rolling(0, ANIMATE_FRAMES); barProportionRolling[player.num] = new Rolling(0, ANIMATE_FRAMES);
return players.length - 1;
}, },
getPlayer: function(ind) { disconnect: function() {
if (ind < 0 || ind >= players.length) //Show score stats.
throw new RangeError("Player index out of bounds (" + ind + ")."); $("#stats").removeClass("hidden");
return players[ind]; $("#stats").animate({
opacity: .9999
}, 3000, function() {
showStats();
//Then fade back into the login screen.
});
}, },
getPlayerFromNum: function(num) { removePlayer: function(player) {
return allPlayers[num]; delete playerPortion[player.num];
}, delete portionsRolling[player.num];
playerSize: function() { delete barProportionRolling[player.num];
return players.length;
}, },
setUser: function(player) { setUser: function(player) {
user = player; user = player;
centerOnPlayer(user, offset); centerOnPlayer(user, offset);
}, },
incrementKill: function() { reset: reset,
kills++; updateGrid: function(row, col, before, after) {
}, //Keep track of areas.
reset: function() { if (before)
init(); playerPortion[before.num]--;
if (after)
playerPortion[after.num]++;
//Queue animation
if (before === after || !client.allowAnimation)
return;
animateGrid.set(row, col, {
before: before,
after: after,
frame: 0
});
}, },
paint: paintDoubleBuff, paint: paintDoubleBuff,
update: update update: update
}; };
Object.defineProperties(exports, {
allowAnimation: {
get: function() { return allowAnimation; },
set: function(val) { allowAnimation = !!val; },
enumerable: true
},
grid: {
get: function() { return grid; },
enumerable: true
}
});

354
player-client.js Normal file
View File

@ -0,0 +1,354 @@
var Player = require('./player.js');
var Grid = require('./grid.js');
var consts = require('./game-consts.js');
var core = require('./game-core.js');
var io = require('socket.io-client');
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
var running = false;
var user, socket, frame;
var players, allPlayers;
var kills;
var timeout = undefined;
var dirty = false;
var deadFrames = 0;
var requesting = -1; //frame that we are requesting at.
var frameCache = []; //Frames after our request.
var allowAnimation = true;
var grid = new Grid(consts.GRID_SIZE, function(row, col, before, after) {
invokeRenderer('updateGrid', [row, col, before, after]);
});
/**
* Provides requestAnimationFrame in a cross browser way. (edited so that this is also compatible with node.)
* @author paulirish / http://paulirish.com/
*/
// window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
// window.setTimeout( callback, 1000 / 60 );
// };
var global;
if (!global)
global = window;
if ( !global.requestAnimationFrame ) {
global.requestAnimationFrame = ( function() {
return global.webkitRequestAnimationFrame ||
global.mozRequestAnimationFrame ||
global.oRequestAnimationFrame ||
global.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
global.setTimeout( callback, 1000 / 60 );
};
})();
}
//Public API
function connectGame(url, name, callback) {
if (running)
return; //Prevent multiple runs.
running = true;
user = null;
deadFrames = 0;
//Socket connection.
io.j = [];
io.sockets = [];
socket = io(url, {
'forceNew': true,
upgrade: false,
transports: ['websocket']
});
socket.on('connect', function(){
console.info('Connected to server.');
});
socket.on('game', function(data) {
if (timeout != undefined)
clearTimeout(timeout);
//Initialize game.
//TODO: display data.gameid --- game id #
frame = data.frame;
reset();
//Load players.
data.players.forEach(function(p) {
var pl = new Player(grid, p);
addPlayer(pl);
});
user = allPlayers[data.num];
if (!user)
throw new Error();
setUser(user);
//Load grid.
var gridData = new Uint8Array(data.grid);
for (var r = 0; r < grid.size; r++)
for (var c = 0; c < grid.size; c++)
{
var ind = gridData[r * grid.size + c] - 1;
grid.set(r, c, ind === -1 ? null : players[ind]);
}
invokeRenderer('paint', []);
frame = data.frame;
if (requesting !== -1)
{
//Update those cache frames after we updated game.
var minFrame = requesting;
requesting = -1;
while (frameCache.length > frame - minFrame)
processFrame(frameCache[frame - minFrame]);
frameCache = [];
}
});
socket.on('notifyFrame', processFrame);
socket.on('dead', function() {
socket.disconnect(); //In case we didn't get the disconnect call.
});
socket.on('disconnect', function(){
if (!user)
return;
console.info('Server has disconnected. Creating new game.');
socket.disconnect();
user.die();
dirty = true;
paintLoop();
running = false;
invokeRenderer('disconnect', []);
});
socket.emit('hello', {
name: name,
type: 0, //Free-for-all
gameid: -1 //Requested game-id, or -1 for anyone.
}, function(success, msg) {
if (success)
console.info('Connected to game!');
else {
console.error('Unable to connect to game: ' + msg);
running = false;
}
if (callback)
callback(success, msg);
});
}
function changeHeading(newHeading) {
if (!user || user.dead)
return;
if (newHeading === user.currentHeading || ((newHeading % 2 === 0) ^
(user.currentHeading % 2 === 0)))
{
//user.heading = newHeading;
if (socket) {
socket.emit('frame', {
frame: frame,
heading: newHeading
}, function(success, msg) {
if (!success)
console.error(msg);
});
}
}
}
function getPlayers() {
return players.slice();
}
//Private API
function addPlayer(player) {
if (allPlayers[player.num])
return; //Already added.
allPlayers[player.num] = players[players.length] = player;
invokeRenderer('addPlayer', [player]);
return players.length - 1;
}
function invokeRenderer(name, args) {
var renderer = exports.renderer;
if (renderer && typeof renderer[name] === 'function')
renderer[name].apply(exports, args);
}
function processFrame(data)
{
if (timeout != undefined)
clearTimeout(timeout);
if (requesting !== -1 && requesting < data.frame)
{
frameCache.push(data);
return;
}
if (data.frame - 1 !== frame)
{
console.error('Frames don\'t match up!');
socket.emit('requestFrame'); //Restore data.
requesting = data.frame;
frameCache.push(data);
return;
}
frame++;
if (data.newPlayers)
{
data.newPlayers.forEach(function(p) {
if (p.num === user.num)
return;
var pl = new Player(grid, p);
addPlayer(pl);
core.initPlayer(grid, pl);
});
}
var found = new Array(players.length);
data.moves.forEach(function(val, i) {
var player = allPlayers[val.num];
if (!player) return;
if (val.left) player.die();
found[i] = true;
player.heading = val.heading;
});
for (var i = 0; i < players.length; i++)
{
//Implicitly leaving game.
if (!found[i])
{
var player = players[i];
player && player.die();
}
}
update();
var locs = {};
for (var i = 0; i < players.length; i++)
{
var p = players[i];
locs[p.num] = [p.posX, p.posY, p.waitLag];
}
socket.emit('verify', {
frame: frame,
locs: locs
}, function(frame, success, adviceFix, msg) {
if (!success && requesting === -1)
{
console.error(frame + ': ' + msg);
if (adviceFix)
socket.emit('requestFrame');
}
}.bind(this, frame));
dirty = true;
requestAnimationFrame(function() {
paintLoop();
});
timeout = setTimeout(function() {
console.warn('Server has timed-out. Disconnecting.');
socket.disconnect();
}, 3000);
}
function paintLoop()
{
if (!dirty)
return;
invokeRenderer('paint', []);
dirty = false;
if (user.dead)
{
if (timeout)
clearTimeout(timeout);
if (deadFrames === 60) //One second of frame
{
var before =allowAnimation;
allowAnimation = false;
update();
invokeRenderer('paint', []);
allowAnimation = before;
user = null;
deadFrames = 0;
return;
}
socket.disconnect();
deadFrames++;
dirty = true;
update();
requestAnimationFrame(paintLoop);
}
}
function reset() {
user = null;
grid.reset();
players = [];
allPlayers = [];
kills = 0;
invokeRenderer('reset');
}
function setUser(player) {
user = player;
invokeRenderer('setUser', [player]);
}
function update() {
var dead = [];
core.updateFrame(grid, players, dead, function addKill(killer, other)
{
if (players[killer] === user && killer !== other)
kills++;
});
dead.forEach(function(val) {
console.log((val.name || 'Unnamed') + ' is dead');
delete allPlayers[val.num];
invokeRenderer('removePlayer', [val]);
});
invokeRenderer('update', []);
}
//Export stuff
var funcs = [connectGame, changeHeading, getPlayers];
funcs.forEach(function (f) {
exports[f.name] = f;
});
exports.renderer = null;
Object.defineProperties(exports, {
allowAnimation: {
get: function() { return allowAnimation; },
set: function(val) { allowAnimation = !!val; },
enumerable: true
},
grid: {
get: function() { return grid; },
enumerable: true
},
kills: {
get: function() { return kills; },
enumerable: true
}
});

File diff suppressed because it is too large Load Diff