Build a game using the DOM – Part 1

January 29th, 2012

When I first became interested in building games using the browser and not Flash, I saw the examples people had made using HTML5’s canvas element so I started learning to build things with that. But every once in a while I’d see someone saying, “Canvas is cool but I prefer using the DOM to build my game.” Use the DOM? The DOM is for displaying pictures and text, not for guys to jump on monsters or space ships to shoot lasers at giant octopus aliens. But then I noticed something, jQuery animations look pretty smooth, especially in Chrome and Firefox, so why couldn’t the browser render a ship flying around in space? So, let’s give it a shot. I’m going to use pretty much the same code as I used in my canvas game tutorial but adapt it for the DOM.

For the first part, we’re going to get a box that will eventually become a ship to move around a playing area. If you’re following this tutorial, I’m going to guess you’ve had a bit of experience with HTML and you’re thinking that we’ll be starting with some divs and go from there. We’re actually going to create everything using JavaScript and style it with CSS which I think will give us more control over what we’re displaying. First off, our CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
body {
    margin:0;
    padding:0;
    background:#888;
}
.playArea {
    width:800px;
    height:500px;
    background:#000;
    border:10px solid #333;
    margin:30px auto 0;
    box-shadow:5px 5px 10px #444;
}
.ship {
    width:50px;
    height:50px;
    background:blue;
    position:absolute;
}

Nothing special here, this just creates am 800 by 600 playing area and our ship will be a 50 by 50 blue box, just like a real space ship. Don’t worry, we’ll change it in a later part, this is to just get things going and prove it can work. Enough with boring CSS, let’s see some JavaScript! Here’s our variables:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function () {
    var playArea = document.createElement('div'),
          ship = document.createElement('div'),
          shipPos = {
              x: 0,
              y: 0
          },
          shipSpeed = 4,
          key = {
              right: false,
              left: false,
              up: false,
              down: false
          },
          shipWidth = ship.offsetWidth,
          shipHeight = ship.offsetHeight;

})();

First off, all our JS is going to be inside an anonymous self calling function because that’s just a good practice. This way our variables won’t affect any other code that might be on the page. Our first variable is playArea which is a div that we’ve created using the createElement method. The same goes for ship. We’ve created these elements but we haven’t added them to the document yet, so if you run just this code, nothing will show up. Next is shipPos, which is an object that we’ll use to keep track of our ship’s x and y position. shipSpeed should be pretty obvious, it’s the speed our ship is set at. The key object is used to check which arrow key is being pressed so we can tell the code to move the ship around. Finally, shipWidth and shipHeight are there to help us keep the ship in the play area boundry and we’ll use it later to see if our ship has been hit by an enemy. offsetWidth and offsetHeight gives us the height of ship that was set in the CSS, so if we want to change it, we just change the CSS and it will update in the JS. Place this next block of code right after the variables:

1
2
3
4
5
6
7
8
9
10
document.body.appendChild(playArea);
playArea.classList.add('playArea');
document.body.appendChild(ship);
ship.classList.add('ship');
shipPos.x = (playArea.offsetWidth / 2 + playArea.offsetLeft) - (ship.offsetWidth / 2);
shipPos.y = (playArea.offsetHeight + playArea.offsetTop) - (ship.offsetHeight * 2);
playArea.leftBoundary = playArea.offsetLeft + 10;
playArea.rightBoundary = (playArea.offsetLeft + playArea.offsetWidth - 10) - ship.offsetWidth;
playArea.topBoundary = playArea.offsetTop + 10;
playArea.bottomBoundary = (playArea.offsetTop + playArea.offsetHeight - 10) - ship.offsetHeight;

What is going on here? The first line adds our playArea div to the document and the next line gives it the class of ‘playArea’. The next two lines do the same thing for ship. Then the ship’s position is figured out using the position and width of playArea. And the last four lines calculate the sides of playArea so we can check when our ship touches it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function keyDown(e) {
    if (e.keyCode === 39) {
        key.right = true;
    } else if (e.keyCode === 37) {
        key.left = true;
    }
    if (e.keyCode === 38) {
        key.up = true;
    } else if (e.keyCode === 40) {
        key.down = true;
    }
}

function keyUp(e) {
    if (e.keyCode === 39) {
        key.right = false;
    } else if (e.keyCode === 37) {
        key.left = false;
    }
    if (e.keyCode === 38) {
        key.up = false;
    } else if (e.keyCode === 40) {
        key.down = false;
    }
}

The function keyUp checks to see if one of the arrow keys has been pressed and changes the corresponding key boolean to true. keyUp checks for when that key is released and sets the value back to false. Now we have to move our ship:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function moveShip() {
    if (key.right === true) {
        shipPos.x += shipSpeed;
    } else if (key.left === true) {
        shipPos.x -= shipSpeed;
    }
    if (key.up === true) {
        shipPos.y -= shipSpeed;
    } else if (key.down === true) {
        shipPos.y += shipSpeed;
    }
    if (shipPos.x < playArea.leftBoundary) {
        shipPos.x = playArea.leftBoundary;
    }
    if (shipPos.x > playArea.rightBoundary) {
        shipPos.x = playArea.rightBoundary;
    }
    if (shipPos.y < playArea.topBoundary) {
        shipPos.y = playArea.topBoundary;
    }
    if (shipPos.y > playArea.bottomBoundary) {
        shipPos.y = playArea.bottomBoundary;
    }
    ship.style.left = shipPos.x + 'px';
    ship.style.top = shipPos.y + 'px';
}

The first part of moveShip checks to see if one of the direction values is true and then moves the ship in that direction at whatever value we’ve set shipSpeed to. The next part of the function checks to see if the ship has reached one of the edges of the playArea div, if it does then the ship is kept inside the div. Finally, the actual updated position of the ship is set on the ship div.

1
2
3
4
5
6
7
8
9
document.addEventListener('keydown', keyDown, false);
document.addEventListener('keyup', keyUp, false);

function loop() {
    moveShip();
    setTimeout(loop, 1000 / 60);
}

loop();

Finally, we add a couple of event listeners so that our game will register when a key is pressed or released and the right function is called. Next we have a function called loop which calls our moveShip function and then has a setTimeout to call loop 60 times a second. And then to get it all started, we call loop for the first time.

You can check out the demo here.

One thing, this doesn’t work in any version of Internet Explorer because classList isn’t in IE yet. Maybe in a later part, we’ll add some compatibility but for now, I think it’s fine if this just works in the other major browsers.

4 Responses to Build a game using the DOM – Part 1

  1. BHL says:

    Hey Mike, were you trying to do this without using any jquery? (Or would that be cheating) If not couldn’t you just replace .classList with .addClass

    Great tutorials!

  2. Mike says:

    jQuery is great but I don’t think I’d use it for game development. There’s other frameworks for that, like EaselJS.

    This is more of an intro into how you’d build something like this and if it doesn’t work in IE, I think that’s on them for not implementing classList in their browser. If this was going to be a game that would be released, then I’d use a hack to make sure it worked in IR too.

  3. Steve says:

    Great site and tutorials. I’m going to learn a lot here.

    when trying to run the dom game thought I get this error message. Even tried copy/pasting your code and still get same. Confusing as it obviously works on your site.

    Uncaught TypeError: Cannot call method ‘appendChild’ of null

    any pointers greatly appreciated.

    Thanks

  4. Mike says:

    Steve,

    What browser are you using?

Leave a Reply

Your email address will not be published. Required fields are marked *