6
\$\begingroup\$

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?

JS Bin here

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();
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Some optimization would be to stop using double quotes and just use single quotes. It looks a bit weird when you use double quotes and sometimes single quotes. The reasoning is that when you use javascript with html that has attributes normally they will use double quotes so you don't need to escape them. Another thing i would do is when you construct a string together with + you should add some space before and after the + it will just look easier to read. The same goes for things like console.error!==undefined Add some space between !== \$\endgroup\$
    – Marcio
    Jun 19, 2015 at 2:30

1 Answer 1

1
\$\begingroup\$

You have some weird spacing in places, like empty arrays and functions. For example, the below block of code, can be changed to objects: [].

objects: [

]

The same also applies to empty functions, like this:

draw: function(GameCanvas){

}

Quite a bit of your indentation as well is inconsistent. For example, the below block of code, and ones like it with inconsistent indentation:

function(callback){
          //hack for RequestAnimationFrame not being there
          this.console.log('No support for RequestAnimationFrame.');
  window.setTimeout(callback, 1000 / 60);
}

Should be changed to a more consistent style, like this:

function(callback){
    //hack for RequestAnimationFrame not being there
    this.console.log('No support for RequestAnimationFrame.');
    window.setTimeout(callback, 1000 / 60);
}

I'd personally recommend either four spaces, or one tab for indentation in Javascript.

In the line this.console.log("Object "+this.objects[obj].name+":"+obj+" throws error:\n"+err);, you prefix console.log with this. In this situation, this isn't needed, and can be removed.

Finally, you have many other style violations, so I'd recommend checking out a style guide, like this one for reference on how to properly style code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.