Article

Hacking JavaScript for Fun and Profit: Part I

Page: 1 2 3

Using Timers

Obviously, the render function is pretty useless if it doesn’t get called repeatedly for the whole game. To make sure it gets fired a couple of times a second, we need to employ JavaScript timers. There are two types of timers: one that will fire once after the timer has expired, and one that will repeatedly fire every t milliseconds until we tell it to stop. We’ll implement the latter, using setInterval function:

mario = new MarioSprite(document.getElementById('mario');  
var timer = setInterval(function() { mario.render() }, 500);

This will make Mario take a step twice per second (500 milliseconds is equal to half a second). Because setInterval requires a function as its first parameter, we need to create an anonymous function that calls the mario.render function.

It might be worthwhile explaining a limitation of JS that will come back to bite us later on: JavaScript is not multi-threaded. This means that there is no way of getting two blocks of code running at the same time. You can interrupt another piece of code by setting up a single-shot timer with an interval of one millisecond, which will force your browser to run the callback function at the next opportunity, but the piece of code that is interrupted will be stopped, and won’t continue execution until the interrupting function has completed. So setting a timer to fire every one millisecond doesn’t guarantee your function will be called that quickly. We will see the consequence of this when I talk about the loop.

Allowing User Input

Obviously, games require some sort of human input, be it via keyboard, mouse, or joystick. So for our game to become more than stationary sprites running on the spot, we will need to respond to inputs from the user; in JavaScript, this is called event listening.
There are two different event models depending on what flavor of browser you have (surprise, surprise), and even though Prototype does a fantastic job in encapsulating the nuances of the two, it is worth knowing what’s going on under the hood.

Bubble-bobble

You can select whether events move down through the DOM to the element that fired it (event capture), up from the element (event bubbling), or a combination of both (the official W3C model). Below is a graphical representation of what happens. Those of you in Internet Explorer land are stuck with event bubbling, while other browsers support both.

If you have been playing with the Web for a while, you may be familiar with inline event handling using attributes such as onmouseover or onclick. This technique is the equivalent to using the style attribute in CSS—it’s evil, don’t do it. Thankfully, there are several ways to dynamically bind events to elements in JavaScript. Consider the following code:

function clicked() {  
 alert('You clicked me!');  
}  
 
function doubleclicked() {  
 alert('You double clicked me!');  
}  
 
var mario = document.getElementById('mario');  
var luigi = document.getElementById('luigi');  
var yoshi = document.getElementById('yoshi');  
 
mario.addEventListener('click', clicked, true);  
mario.addEventListener('doubleclick', doubleclicked, false);  
 
luigi.attachEvent('onclick', clicked);  
 
yoshi.onclick = clicked;

Here we have three different methods for attaching events to elements in the DOM. The first—using addEventListener—is the W3C standard way of doing things; the first parameter is the name of the event, the second is the name of the callback function, and the third is a Boolean which indicates whether we are capturing (false) or bubbling (true). The second—using attachEvent—is the Internet Explorer way; it’s basically the same signature as the W3C version, without the third parameter because IE only supports event bubbling. The final one—using the element’s onclick property—is a method that works in all browsers.

Events like mouseover and mouseout are pretty simple, but keyboard events are a bit more complex because we need to know what key was pressed. In this case, we have to obtain the information from the JavaScript Event object; either an Event object is passed into the callback function, or if you are in IE land, a global Event object is created in the window object: window.event, which has the information that we need.

Here’s an example:

function keypressHandler(e) {  
 e = window.event || e;  
 alert("Keycode: " + e.keyCode);  
}  
 
window.onkeypress = keypressHandler;

keypressHandler is our event callback function that is called when a keypress event is triggered. The first line represents a cross-browser method for obtaining the Event object. Once we have the Event object we can query the keyCode property and find out which key was pressed.

As we’ve demonstrated, Prototype makes these kinds of jobs really easy. Prototype has added some methods to the Event object, that take care of all the cross-browser issues for us. We can reduce our code to the following:

function keypressHandler(e) {  
 alert("Keycode: " + e.keyCode);  
}  
 
Event.observe(window, 'keypress', keypressHandler);

Setting up our event handler using Event.observe allows us to drop the conditional test that checks whether we have an Event object via a function parameter, or from the window event. It’s all handled seamlessly for us by Prototype.

Conclusion

At this point, we have explored JavaScript objects and classes (including OOP concepts like inheritance), how to use JavaScript and CSS classes to give elements behaviors, how to use timers to allow us to repeatedly perform a task (such as animation), and the basics of listening to events. This gives us enough JavaScript in our toolbox to allow us to get to the core of building a platform game. In the next article, I will cover creating a basic collision engine—the animation loop—and show you a few tricks for scrolling the browser window to get that authentic 80s’ side-scrolling effect.

In the meantime, check out the demo that puts the above theory into practice (hint: press the arrow keys and see what happens) . You can download the code archive for this article—see if you can extend it yourself, as you are going to need to understand what is going on for the second article in this series. Until next time …

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links

Rate This Article

  • 1
    Poor
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    Great

Comment on This Article

Have something to say?

Post A Comment

You need to be a member of the SitePoint Forums to comment on this post. Sign Up

Already a member? Post using your SitePoint Forums account: