Skip to content

Instantly share code, notes, and snippets.

@rBurgett
Last active August 4, 2016 19:16
Show Gist options
  • Save rBurgett/1f3067005d9dbed92bb91130718ab4af to your computer and use it in GitHub Desktop.
Save rBurgett/1f3067005d9dbed92bb91130718ab4af to your computer and use it in GitHub Desktop.
/**
* Here is another way to do the Game constructor. This uses a constructor function, but makes use of the function closure.
* You will notice that all the annoying .bind() calls are gone, because we are no longer using the `this` keyword to reference
* properties and methods. Rather than storing those as properties and methods on an object, I use shared variables inside
* the closure. The benefits of this design are that anything within the closure is private, so nobody can accidentally
* change those functions or values. Then, at the bottom we expose three items which can be accessed outside of the closure.
* If we were using ES6, we could also make many of the variable into constants, which would add another layer of protection
* and reduce the surface area for bugs. The downside is that this is not as fast as a traditional constructor, but when we
* are just talking about a couple milliseconds the speed difference is a non-issue! The only time it would mean anything is
* if you are calling these tens of thousands of times at once. In that case, using the prototype and a traditional constructor
* is definitely the way to go.
*
* This is by far my preferred way to build constructors.
*
* To run the constructor and instantiate the class:
* var game = new Game({
* levels: levels,
* ctx : canvas.getContext("2d"),
* tileSize : 16
* });
**/
var EventEmitter = require("events").EventEmitter;
var Game = function(options) {
// private variables and functions
var defaultGrid = options.levels;
var ctx = options.ctx;
var tileSize = options.tileSize;
var cloneLevels = function(levels) {
return levels.map(function(level) {
return level.map(function(row) {
return row.concat();
});
});
};
var grid = cloneLevels(options.levels);
var events = new EventEmitter();
var frozen = false;
var currentLevel = 0;
var charX = 1;
var charY = 1;
var moveQueue = [];
var tiles = {
0: "black",
1: "yellow",
2: "blue",
3: "red"
};
var draw = function() {
if(!frozen && moveQueue.length > 0) {
moveQueue[0]();
}
moveQueue = [];
make();
};
var make = function() {
var level = currentLevel;
grid[level][charX][charY] = 2;
var row, col;
for (var i = 0; i < grid[level].length; i++) {
row = tileSize * i;
for (var j = 0; j < grid[level][0].length; j++) {
col = tileSize * j;
ctx.beginPath();
ctx.rect(row, col, tileSize, tileSize);
ctx.fillStyle = tiles[grid[level][i][j]];
ctx.fill();
ctx.closePath();
}
}
};
var moveRight = function() {
var level = currentLevel;
if(charX < 19) {
if (grid[level][charX + 1][charY] === 0) {
grid[level][charX][charY] = 0;
charX += 1;
grid[level][charX][charY] = 2;
} else if (grid[level][charX + 1][charY] === 3) {
levelUp();
}
}
};
var moveLeft = function() {
var level = currentLevel;
if(charX > 0) {
if (grid[level][charX - 1][charY] === 0) {
grid[level][charX][charY] = 0;
charX -= 1;
grid[level][charX][charY] = 2;
} else if (grid[level][charX - 1][charY] === 3) {
levelUp();
}
}
};
var moveUp = function() {
var level = currentLevel;
if(charY > 0) {
if (grid[level][charX][charY -1] === 0) {
grid[level][charX][charY] = 0;
charY -= 1;
grid[level][charX][charY] = 2;
} else if (grid[level][charX][charY -1] === 3) {
levelUp();
}
}
};
var moveDown = function() {
var level = currentLevel;
if(charY < 19) {
if (grid[level][charX][charY + 1] === 0) {
grid[level][charX][charY] = 0;
charY += 1;
grid[level][charX][charY] = 2;
} else if (grid[level][charX][charY + 1] === 3) {
levelUp();
}
}
};
var levelUp = function() {
moveQueue = [];
if (currentLevel === grid.length - 1) {
frozen = true;
events.emit("gameOver");
} else {
frozen = true;
currentLevel++;
events.emit("leveledUp", {currentLevel: currentLevel + 1});
charX = 1;
charY = 1;
frozen = false;
}
};
var keyDownHandler = function(e) {
switch(e.keyCode) {
case 39:
moveQueue.push(moveRight);
break;
case 37:
moveQueue.push(moveLeft);
break;
case 38:
moveQueue.push(moveUp);
break;
case 40:
moveQueue.push(moveDown);
break;
}
};
// publicly exposed variables and functions
this.restart = function() {
events.emit("restart");
grid = cloneLevels(defaultGrid);
charX = 1;
charY = 1;
currentLevel = 0;
frozen = false;
moveQueue = 0;
make();
};
this.start = function() {
document.addEventListener("keydown", keyDownHandler);
setInterval(function() {
draw();
}, 90);
};
this.events = events;
};
module.exports = Game;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment