4
\$\begingroup\$

I've just completed reading the game tutorial of w3schools and wrote a piece of code from scratch.

This program basically creates a canvas element with a ball bouncing off the walls of the canvas. The user can also control the ball using arrow keys. I'm planning to make this into a small game by creating some obstacles etc

var gameRun;
var ball;

function startGame() {
    gameObj.start();

    ball = new component(100, 100, 0, 0, "http://www.bit-101.com/blog/wp-content/uploads/2009/05/ball.png");

    gameRun = setInterval(updateStuff, 10);

    window.addEventListener("keydown", function(e) {
        gameObj.key = e.keyCode;
    });
    window.addEventListener("keyup", function(e) {
        gameObj.key = false;
    });
}

var gameObj = {
    canvas : document.createElement("canvas"),
    /*ctx : this.canvas.getContext("2d"),*/
    start : function() {
        document.body.appendChild(this.canvas);

        this.canvas.width = document.body.clientWidth;
        this.canvas.height = document.body.clientHeight;
    },
    clear : function() {
        var ctx = this.canvas.getContext("2d");
        ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }
};

var UR = 1, /* Up-Right   */
    DR = 2, /* Down-Right */
    DL = 3, /* Down-Left  */
    UL = 4; /* Up-Left    */

function component(x, y, width, height, img) {
    this.x = x;
    this.y = y;

    this.direction = getRandomInt(1, 4); /* At the start, choose a random direction */

    if(img != undefined) {
        this.width = width;
        this.height = height;
    }

    this.update = function() {
        var ctx = gameObj.canvas.getContext("2d");
        if(img != undefined) {
            this.image = new Image();
            this.image.src = img;

            this.width = this.image.width;
            this.height = this.image.height;

            ctx.drawImage(this.image, this.x, this.y);
        }
        else {
            /* TODO: Obstacle creation */
        }
    };

    this.newPos = function() {
        if(img != undefined) {
            if(this.x == 0) {
                if(this.direction == UL) {
                    this.direction = UR;
                }
                else if(this.direction == DL) {
                    this.direction = DR;
                }
            }
            else if(this.x + this.width == gameObj.canvas.width)
            {
                if(this.direction == UR) {
                    this.direction = UL;
                }
                else if(this.direction == DR) {
                    this.direction = DL;
                }
            }
            if(this.y == 0) {
                if(this.direction == UL) {
                    this.direction = DL;
                }
                else if(this.direction == UR) {
                    this.direction = DR;
                }
            }
            else if(this.y + this.height == gameObj.canvas.height)
            {
                if(this.direction == DR) {
                    this.direction = UR;
                }
                else if(this.direction == DL) {
                    this.direction = UL;
                }
            }

            if(this.direction == UL) {
                this.x--;
                this.y--;
            }
            else if(this.direction == UR) {
                this.x++;
                this.y--;
            }
            else if(this.direction == DL) {
                this.x--;
                this.y++;
            }
            else /* this.direction == DR */{
                this.x++;
                this.y++;
            } 
        }
        else {
            /* TODO: Obstacle creation */
        } 
    }
}

function updateStuff() {
    gameObj.clear();
    if      (gameObj.key && gameObj.key == 37) {  /* LEFT  */
        if     (ball.direction == UR) { ball.direction = UL; }
        else if(ball.direction == DR) { ball.direction = DL; }
    }
    else if (gameObj.key && gameObj.key == 39) {  /* RIGHT */
        if     (ball.direction == UL) { ball.direction = UR; }
        else if(ball.direction == DL) { ball.direction = DR; }
    }
    else if (gameObj.key && gameObj.key == 38) {  /* UP    */
        if     (ball.direction == DL) { ball.direction = UL; }
        else if(ball.direction == DR) { ball.direction = UR; }
    }
    else if (gameObj.key && gameObj.key == 40) {  /* DOWN  */
        if     (ball.direction == UR) { ball.direction = DR; }
        else if(ball.direction == UL) { ball.direction = DL; }
    }
    ball.newPos();
    ball.update();
}

/**
 * Returns a random integer between min (inclusive) and max (inclusive)
 */
function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
* {
  margin: 0;
  padding: 0;
}
body {
  width: 100%;
  height: 100%;
}
<body onLoad="startGame()"></body>

Before I proceed for further development of the game, I want to get a review of my code.


Side note:

Why can't I use

ctx : this.canvas.getContext("2d")

in gameObj? It gives me

TypeError: this.canvas is undefined

\$\endgroup\$
  • \$\begingroup\$ On the last note, you can't use it because, when defining your object, this.canvas is undefined, being a property of this, the window \$\endgroup\$ – Conor O'Brien Apr 20 '16 at 11:21
  • \$\begingroup\$ So, this refers to the window object, and not the gameObj object? That explains the error? What about the fix? Wrap it in a function like: ctx : function() { return this.canvas.getContext("2d"); }? \$\endgroup\$ – Spikatrix Apr 21 '16 at 6:27
  • \$\begingroup\$ that should work if you want ctx as a function; wrapping the entire code in a window listener (window.addEventListener("load", function(){...}) should do the trick. \$\endgroup\$ – Conor O'Brien Apr 21 '16 at 11:01
1
\$\begingroup\$

First of all, I personally would avoid hard-coding all the directions and if-statements to check for them. Instead, what is more efficient is to use just 2 variables, x-velocity and y-velocity. This makes collisions much easier:

// I'm using <= and >= just in case you decide to
// make the ball move faster later
if(this.x <= 0 || this.x + this.width >= gameObj.canvas.width)
{
    this.xvel *= -1;
}
if(this.y <= 0 || this.y + this.height >= gameObj.canvas.height)
{
    this.yvel *= -1;
}

And movement as well:

this.x += xvel;
this.y += yvel;

And input is nothing more than setting the value:

if      (gameObj.key && gameObj.key == 37) {  /* LEFT  */
    ball.xvel = -1;
}
else if (gameObj.key && gameObj.key == 39) {  /* RIGHT */
    ball.xvel = 1;
}
else if (gameObj.key && gameObj.key == 38) {  /* UP    */
    ball.yvel = -1;
}
else if (gameObj.key && gameObj.key == 40) {  /* DOWN  */
    ball.yvel = 1;
}

Good luck with your game!

\$\endgroup\$
  • \$\begingroup\$ Awesome! This would make the code much easier to read and also shortens the code! Thanks! \$\endgroup\$ – Spikatrix Apr 21 '16 at 6:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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