Javascript Game Foundations - DOM

Sat, Dec 7, 2013

Ten Essential Foundations of Javascript Game Development

  1. A Web Server and a Module Strategy
  2. Loading Assets
  3. The Game Loop
  4. Player Input
  5. Math
  6. DOM
  7. Rendering
  8. Sound
  9. State Management
  10. Juiciness

The Browser DOM

If you are making a javascript game for the browser, its quite likely that most of your game lives within an HTML5 <canvas> element. However it still makes sense to take advantage of the strengths of the browser DOM - displaying styled text and images - for example:

Positioning, Rendering, and interacting with text in a canvas requires a lot of effort, so taking advantage of DOM layout, CSS, and event handling can save us a fair amount of work.

Simple DOM Manipulation Without jQuery

If you are going to be doing a lot of complex work with the DOM then you are probably going to want to embrace a fully featured library such as jQuery.

However, for simple games, you can get quite far with just a few key features

If you are targetting modern browsers, you can provide these features easily.

var Dom = {

  get: function(id) {
    return document.getElementById(id);
  },

  set: function(ele, html) {
    ele.innerHTML = html;
  },

  ...

Attaching event handlers:

  on: function(ele, type, fn, capture) {
    ele.addEventListener(type, fn, capture);
  },

  un: function(ele, type, fn, capture) {
    ele.removeEventListener(type, fn, capture);
  },

Showing and hiding elements:

  hide: function(ele) {
    ele.style.display = 'none';
  },

  show: function(ele) {
    ele.style.display = '';
  },

Adding and Removing class names:

  hasClassName: function(ele, name) {
    return (new RegExp("(^|\s*)" + name + "(\s*|$)")).test(ele.className)
  },

  addClassName: function(ele, name) {
    ele.toggleClassName(name, true);
  },

  removeClassName: function(ele, name) {
    ele.toggleClassName(name, false);
  },

  toggleClassName: function(ele, name, on) {
    var classes = ele.className.split(' ');
    var n = classes.indexOf(name);
    on = (typeof on == 'undefined') ? (n < 0) : on;
    if (on && (n < 0))
      classes.push(name);
    else if (!on && (n >= 0))
      classes.splice(n, 1);
    ele.className = classes.join(' ');
  },

NOTE: classname manipulation can be a lot easier if your target browsers all support the classlist api

Get DOM Elements By Selector

The previous example allowed you to locate DOM elements by ID using getElementById. If you want to be able to locate DOM elements using advanced CSS selectors, then you can use querySelectorAll:

query: function(selector, context) {
  return (context || document).querySelectorAll(selector);
},

Just be wary of the potential confusion around using a root context.

If you need a more robust solution, you can include the same Sizzle library that is used by jQuery…

query: function(selector, context) {
  return Sizzle(selector, context);
},

… or you could always just use jQuery directly :-)

Animating DOM Elements

When we show and hide DOM elements we might want to include an animated transition.

The modern way to do this would be with CSS Transitions and CSS Animations, but you can also use a more traditional javascript animation library like Bernie Sumptions animator.js

fade: function(ele, amount) {
  ele.style.opacity = amount;
},

fadeout: function(ele, duration) {
  Animator.apply(ele, 'opacity: 0', { duration: duration, onComplete: function() {
    Dom.hide(ele);
    Dom.fade(ele, null); // remove opacity attribute when finished
  }}).play();
},

fadein: function(ele, duration) {
  Dom.fade(ele, 0)
  Dom.show(ele);
  Animator.apply(ele, 'opacity: 1', { duration: duration, onComplete: function() {
    Dom.fade(ele, null); // remove opacity attribute when finished
  }}).play();
},

… of course, you could always use jQuery animations :-)

Ok, Lets Just Use jQuery Already!

Using jQuery can be overkill for small, simple, games. If all we need to do is show and hide some elements then the techniques described here will be more than adequate…

… however, once we reach a certain level of complexity, usually once we need to start creating and destroying DOM elements, or performing complex animations, then the trade off no longer makes sense and it’s time to embrace a quality library, such as jQuery.