Server and client code completed (with bugs).

This commit is contained in:
theKidOfArcrania 2017-02-26 02:36:44 +00:00
parent 916c50e162
commit 88a6195fe8
10 changed files with 8383 additions and 283 deletions

View File

@ -3,6 +3,11 @@ var Player = require("./player.js");
var renderer = require("./game-renderer.js");
var consts = require("./game-consts.js");
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
renderer.allowAnimation = true;
/**
* Provides requestAnimationFrame in a cross browser way.
* @author paulirish / http://paulirish.com/
@ -22,81 +27,7 @@ if ( !window.requestAnimationFrame ) {
})();
}
$(function() {
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
var canvas = $("#main-ui")[0];
var ctx2 = canvas.getContext('2d');
var grid = renderer.grid;
renderer.allowAnimation = true;
//Load players.
for (var p = 0; p < 9; p++)
{
//TODO: socket loading.
var pRow = getRandomInt(0, GRID_SIZE);
var pCol = getRandomInt(0, GRID_SIZE);
var sdata = {
posX: pCol * CELL_WIDTH,
posY: pRow * CELL_WIDTH,
currentHeading: getRandomInt(0, 4),
//name: ...,
num: p
};
renderer.addPlayer(new Player(true, grid, sdata));
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, renderer.getPlayer(p));
}
//Load grid.
for (var r = 0; r < grid.size; r++)
{
for (var c = 0; c < grid.size; c++)
{
//TODO: load data.
//if (Math.random() > .9)
// grid.set(r, c, players[getRandomInt(0, players.length)]);
}
}
var frameCount = 0;
//TODO: current player index
var user = renderer.getPlayer(0);
renderer.initUser(user);
function update()
{
renderer.update();
}
//Thanks to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
function paintLoop(ctx)
{
renderer.paint(ctx); //TODO: pre-rendering.
//TODO: sync each loop with server. (server will give frame count.)
frameCount++;
update();
requestAnimationFrame(paintLoop);
}
paintLoop(ctx2);
var user, socket, frame;
//Event listeners
$(document).keydown(function(e) {
@ -115,9 +46,108 @@ $(function() {
if (newHeading === user.currentHeading || ((newHeading % 2 === 0) ^
(user.currentHeading % 2 === 0)))
{
//TODO: notify server.
user.heading = newHeading;
if (socket)
socket.emit("frame", {
frame: frame,
heading: newHeading
}, function(success, msg) {
if (!success)
{
//TODO: restore frames.
console.error(msg);
}
});
}
e.preventDefault();
});
$(function() {
var grid = renderer.grid;
//Socket connection.
socket = require('socket.io-client')('http://paper-io-thekidofarcrania.c9users.io:8081');
socket.on('connect', function(){
console.info("Connected to server.");
socket.emit('hello', {
name: 'Test player',
type: 0, //Free-for-all
gameid: -1 //Requested game-id, or -1 for anyone.
}, function(success) {
if (success) console.info("Connected to game!");
else console.error("Unable to connect to game.");
});
});
socket.on('game', function(data){
//Initialize game.
//TODO: display data.gameid --- game id #
renderer.reset();
//Load players.
data.players.forEach(function(p) {
renderer.addPlayer(new Player(true, grid, p));
});
user = renderer.getPlayerFromNum(data.num);
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));
}
frame = data.frame;
});
socket.on('notifyFrame', function(data) {
if (data.frame - 1 !== frame)
{
console.error("Frames don't match up!");
socket.emit('requestFrame'); //Restore data.
return;
}
frame++;
if (data.newPlayers)
{
data.newPlayers.forEach(function(p) {
renderer.addPlayer(new Player(true, grid, p));
});
}
data.moves.forEach(function(val, i) {
if (renderer.getPlayer(val) !== user)
renderer.getPlayer(i).heading = val.heading;
});
paintLoop();
});
socket.on('disconnect', function(){
console.info("Server has disconnected. Creating new game.");
});
var deadFrames = 0;
function paintLoop()
{
renderer.paint();
if (user.dead && deadFrames === 60) //One second of frames
{
//TODO: Show welcome screen.
deadFrames = 0;
return;
}
renderer.update();
if (user.dead)
{
socket.disconnect();
deadFrames++;
requestAnimationFrame(paintLoop);
}
}
});

View File

@ -10,7 +10,8 @@ var consts = {
GRID_SIZE: constant(80),
CELL_WIDTH: constant(40),
SPEED: constant(5),
BORDER_WIDTH: constant(20)
BORDER_WIDTH: constant(20),
MAX_PLAYERS: constant(255)
};
Object.defineProperties(module.exports, consts);

View File

@ -28,7 +28,9 @@ exports.updateFrame = function(grid, players, newPlayerFrames, dead, notifyKill)
if (newPlayerFrames[val.num] < ANIMATE_FRAMES)
newPlayerFrames[val.num]++;
else
{
val.move();
}
if (val.dead)
adead.push(val);

View File

@ -35,13 +35,12 @@ $(function () {
gameHeight = canvasHeight - BAR_HEIGHT;
});
var animateGrid = new Grid(GRID_SIZE);
var allowAnimation = true;
var players = [];
var allPlayers = [];
var newPlayerFrames = [];
var playerPortion = [];
var grid = new Grid(GRID_SIZE, function(row, col, before, after) {
var animateGrid, players, allPlayers, newPlayerFrames, playerPortion, grid,
animateTo, offset, user, lagPortion, portionSpeed, zoom, kills, showedDead;
grid = new Grid(GRID_SIZE, function(row, col, before, after) {
//Keep track of areas.
if (before)
playerPortion[before.num]--;
@ -58,16 +57,27 @@ var grid = new Grid(GRID_SIZE, function(row, col, before, after) {
});
});
var animateTo = [0, 0];
var offset = [0, 0];
function init() {
animateGrid = new Grid(GRID_SIZE);
grid.reset();
var user;
var lagPortion = 0;
var portionSpeed = 0;
var zoom = 1;
var kills = 0;
players = [];
allPlayers = [];
newPlayerFrames = [];
playerPortion = [];
var showedDead = false;
animateTo = [0, 0];
offset = [0, 0];
user = null;
lagPortion = 0;
portionSpeed = 0;
zoom = 1;
kills = 0;
showedDead = false;
}
init();
//Paint methods.
function paintGridBorder(ctx)
@ -207,17 +217,17 @@ function paintUIBar(ctx)
var barOffset;
ctx.fillStyle = "white";
ctx.font = "24px Changa";
barOffset = ctx.measureText(user.name).width + 20;
ctx.fillText(user.name, 5, CELL_WIDTH - 5);
barOffset = ctx.measureText(user ? user.name : "").width + 20;
ctx.fillText(user ? 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.fillStyle = user ? user.baseColor.rgbString() : "";
ctx.fillRect(barOffset, 0, barSize, CELL_WIDTH);
ctx.fillStyle = user.shadowColor.rgbString();
ctx.fillStyle = user ? user.shadowColor.rgbString() : "";
ctx.fillRect(barOffset, CELL_WIDTH, barSize, SHADOW_OFFSET);
//Percentage
@ -274,7 +284,7 @@ function paint(ctx)
ctx.restore();
paintUIBar(ctx);
if (user.dead && !showedDead)
if ((!user || user.dead) && !showedDead)
{
showedDead = true;
console.log("You died!");
@ -302,7 +312,10 @@ function update() {
}
//Change area percentage
var userPortion = playerPortion[user.num] / (GRID_SIZE * GRID_SIZE);
var userPortion;
if (user) userPortion = playerPortion[user.num] / (GRID_SIZE * GRID_SIZE);
else userPortion = 0;
if (lagPortion !== userPortion)
{
delta = userPortion - lagPortion;
@ -330,7 +343,7 @@ function update() {
//TODO: animate player is dead. (maybe explosion?), and tail rewinds itself.
//TODO: show when this player is dead
centerOnPlayer(user, animateTo);
if (user) centerOnPlayer(user, animateTo);
}
//Helper methods.
@ -381,6 +394,8 @@ function getBounceOffset(frame)
module.exports = exports = {
addPlayer: function(player) {
if (allPlayers[player.num])
return; //Already added.
allPlayers[player.num] = players[players.length] = player;
newPlayerFrames[player.num] = 0;
playerPortion[player.num] = 0;
@ -390,16 +405,22 @@ module.exports = exports = {
getPlayer: function(ind) {
return players[ind];
},
playerNum: function() {
getPlayerFromNum: function(num) {
return allPlayers[num];
},
playerSize: function() {
return players.length;
},
initUser: function(player) {
setUser: function(player) {
user = player;
centerOnPlayer(user, offset);
},
incrementKill: function() {
kills++;
},
reset: function() {
init();
},
paint: paintDoubleBuff,
update: update
};

View File

@ -1,10 +1,12 @@
var GRID_SIZE = 80;
var CELL_WIDTH = 40;
var MAX_PLAYERS = 255;
var Grid = require("./grid.js");
var Player = require("./player.js");
var core = require("./game-core.js");
var consts = require("./game-consts.js");
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
var MAX_PLAYERS = consts.MAX_PLAYERS;
function Game(id)
{
@ -50,7 +52,7 @@ function Game(id)
newPlayers.push(p);
newPlayerFrames.push(p);
nextInd++;
core.initPlayer(p);
core.initPlayer(grid, p);
var splayers = players.map(function(val) {return val.serialData();});
client.emit("game", {
@ -60,11 +62,12 @@ function Game(id)
"players": splayers,
"grid": gridSerialData(grid, players)
});
console.log(p.name + " joined.");
//TODO: limit number of requests per frame.
client.on("requestFrame", function (fn) {
client.on("requestFrame", function () {
var splayers = players.map(function(val) {return val.serialData();});
fn({
client.emit("game", {
"num": p.num,
"gameid": id,
"frame": frame,
@ -72,6 +75,7 @@ function Game(id)
"grid": gridSerialData(grid, players)
});
});
client.on("frame", function(data, errorHan){
if (typeof data === "function")
{
@ -86,8 +90,8 @@ function Game(id)
errorHan(false, "No data supplied.");
else if (!checkInt(data.frame, 0, Infinity))
errorHan(false, "Requires a valid non-negative frame integer.");
else if (data.frame < frame)
errorHan(false, "Late frame received.");
//else if (data.frame < frame)
// errorHan(false, "Late frame received.");
else if (data.frame > frame)
errorHan(false, "Invalid frame received.");
else
@ -109,10 +113,11 @@ function Game(id)
this.tickFrame = function() {
//TODO: notify those that drop out.
var snews = newPlayers.map(function(val) {return val.serialData();});
var moves = players.map(function(val) {return {heading: val.heading};});
var data = {moves: moves};
var data = {frame: frame + 1, moves: moves};
if (snews.length > 0)
{
data.newPlayers = snews;
@ -129,7 +134,10 @@ function Game(id)
{
var dead = [];
core.updateFrame(grid, players, newPlayerFrames, dead);
dead.forEach(function(val) { val.client.disconnect(true); });
dead.forEach(function(val) {
console.log(val.name + " died.");
val.client.disconnect(true);
});
}
}

10
grid.js
View File

@ -1,6 +1,7 @@
function Grid(size, changeCallback)
{
var grid = new Array(size);
var modified = false;
var data = {
grid: grid,
@ -26,8 +27,17 @@ function Grid(size, changeCallback)
if (typeof changeCallback === "function")
changeCallback(row, col, before, value);
modified = true;
return before;
}
this.reset = function() {
if (modified)
{
grid = new Array(size);
modified = false;
}
}
this.isOutOfBounds = isOutOfBounds.bind(this, data);

View File

@ -1,6 +1,10 @@
var Stack = require("./stack.js");
var Color = require("./color.js");
var Grid = require("./grid.js");
var consts = require("./game-consts.js");
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
function defineGetter(getter) {
return {
@ -24,9 +28,6 @@ function defineAccessorProperties(thisobj, data /*, names...*/)
Object.defineProperties(thisobj, descript);
}
var CELL_WIDTH = 40;
var GRID_SIZE = 80;
function TailMove(orientation)
{
this.move = 1;
@ -53,7 +54,7 @@ function Tail(player, sdata)
{
data.startRow = data.prevRow = sdata.startRow || 0;
data.startCol = data.prevCol = sdata.startCol || 0;
sdata.forEach(function(val) {
sdata.tail.forEach(function(val) {
addTail(data, val.orientation, val.move);
});
}
@ -68,11 +69,11 @@ function Tail(player, sdata)
//Instance methods.
function serialData(data) {
return JSON.serialize({
return {
tail: data.tail,
startRow: data.startRow,
startCol: data.startCol
});
};
}
function setTailGrid(data, tailGrid, r, c)
@ -430,7 +431,7 @@ Player.prototype.render = function(ctx, fade)
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().deriveAlpha(fade));
grd.addColorStop(0, this.baseColor.deriveAlpha(fade).rgbString());
grd.addColorStop(1, new Color(0, 0, 1, fade).rgbString());
ctx.fillStyle = grd;
ctx.fillRect(this.posX - 1, this.posY - SHADOW_OFFSET, CELL_WIDTH + 2, CELL_WIDTH);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -8,17 +8,24 @@ var serve = serveStatic('public/', {'cacheControl': false});
// Create server
var server = http.createServer(function onRequest (req, res) {
serve(req, res, finalhandler(req, res))
})
});
// Listen
server.listen(8080);
var server = http.createServer();
server = http.createServer();
var io = require('socket.io')(server);
var games = [];
var Game = require('./game-server.js');
var games = [new Game()];
io.on('connection', function(socket){
socket.emit('message', 'hello.'); // emit an event to the socket
io.emit('message', 'new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.new person.'); // emit an event to all connected sockets
socket.on('reply', function(){ /* */ }); // listen to the event
socket.on("hello", function(data, fn) {
//TODO: error checking.
fn(true);
games[0].addPlayer(socket, data.name);
});
});
server.listen(8081);
setInterval(function() {
games[0].tickFrame();
}, 1000 / 60);