I am creating a simple 2D canvas game engine in JavaScript. Are there any optimizations that I could make, or obvious issues (performance, semantics or otherwise) that you can see?
var GameCanvas = {
// GameCanvas Variables
animation: {
requestAnimationFrame: null,
halt: false
},
canvas: {
element: null,
context: null,
width: 500,
height: 500,
backgroundColor: '#000000'
},
objects: [
],
baseObject: function(){
return {
// Custom internal name of object (Mostly for debugging)
name: '',
position: {
width: 0,
height: 0,
x: 0,
y: 0
},
// Any custom data for this object
data: {
},
// the draw method
draw: function(GameCanvas){
},
criticalObj: true
};
},
addObject: function(obj){
this.objects.unshift(obj);
},
init: function(CanvasID){
// Get Canvas by ID
this.canvas.element = document.getElementById(CanvasID);
if(this.canvas.element===null){
this.console.error("No valid canvas with ID \""+CanvasID+"\" found.");
return false;
}
// Get Canvas dimensions
this.canvas.width = this.canvas.element.width || this.canvas.width;
this.canvas.height = this.canvas.element.height || this.canvas.height;
// Get the context
this.canvas.context = this.canvas.element.getContext('2d');
if(this.canvas.context===null){
this.console.error("Failed to get context.");
return false;
}
// Setup Request Animation Frame
// RequestAnimationFrame Shim
this.animation.requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
//hack for RequestAnimationFrame not being there
this.console.log('No support for RequestAnimationFrame.');
window.setTimeout(callback, 1000 / 60);
};
})();
this.console.log("Initialized Successfully.");
return true;
},
console: {
data: '',
// Allows for custom error output
error: function(data){
if(console.error!==undefined){
console.error('GameCanvas: '+String(data));
}
this.data += data+"\n";
},
log: function(data){
if(console.log!==undefined){
console.log('GameCanvas: '+String(data));
}
this.data += data+"\n";
}
},
run:function(){
this.console.log("Starting mainLoop().");
this.mainLoop();
},
mainLoop: function(){
// Fill Background
this.canvas.context.fillStyle = this.canvas.backgroundColor;
this.canvas.context.fillRect(0,0,this.canvas.width,this.canvas.height);
//Loop through objects
for(var obj in this.objects){
try{
this.objects[obj].draw(this);
}
catch(err){
this.console.log("Object "+this.objects[obj].name+":"+obj+" throws error:\n"+err);
if(this.objects[obj].criticalObj){
this.console.error("Critical Object "+this.objects[obj].name+":"+obj+" not drawn. Halting mainLoop().");
this.animation.halt = true;
}
}
}
// Looping call
if(!this.animation.halt){
this.animation.requestAnimationFrame.call(
window, // Call function in context of window
// Call the mainLoop() function in the context of the current object
this.mainLoop.bind(this)
);
}
else{
this.console.log("mainLoop() halted.");
this.animation.halt = false;
}
}
};
GameCanvas.init("canvas");
var box = GameCanvas.baseObject();
box.name = "Box";
box.draw = function(GameCanvas){
GameCanvas.canvas.context.fillStyle = "#00FF00";
GameCanvas.canvas.context.fillRect(this.position.x,this.position.y,this.position.width,this.position.height);
};
box.position.width = 50;
box.position.height = 50;
box.position.x = 10;
box.position.y = 10;
GameCanvas.addObject(box);
GameCanvas.run();