devxlogo

An Introduction to Game Programming with JavaScript

An Introduction to Game Programming with JavaScript

ost game programs follow the same recipe?the game must gather input from the user, process that input and any other data, and render objects to the screen. Usually, the program creates event handlers that listen for user input via the mouse, keyboard, or other input device, and a game loop that manages data processing and rendering the display. Once launched, the game loop continues until it encounters some end condition.

In this article, I’ll create a simple demo called Rebound that should get you started with game programming in JavaScript. Rebound is a simple ball and paddle game where the user controls a paddle with the keyboard and must keep a moving ball from getting beyond the paddle. You can view the demo here.


How do you create JavaScript Game Programs?


Use keyboard events to gather input from users and animation techniques to create games in JavaScript.

Create the Game Elements
Open your favorite text editor and enter the following HTML to create the screen objects for the game:

      Rebound      

Rebound

Score: 0

Note that the playingArea

is a container for all the other screen objects. As you’ll see, I’ll position the playingArea absolutely and then do the same for the paddle, ball, and score. The result is that the paddle, ball, and score are positioned relatively to the location of the playingArea.

Next, create the CSS that formats and positions the HTML objects by adding the following

Scripting the Game
Add a

Next, you'll need to provide initial positions for the ball, paddle, and score variables visible on the screen. This init() function initializes the objects. Add the following to your script:

function init(){//instantiate HTML object instance vars   ball = document.getElementById('ball');   paddle = document.getElementById('paddle');   score = document.getElementById('score');}

Then, call the init() function from the tag's onLoad event:

 

Write and Register a Keyboard Event Handler
You'll need to gather keypress information from the user. To do that, create an event listener and register it with the document object's onkeydown event. After registering the listener, the document executes the listener code each time the specified event occurs. Create the event listener by adding the following to the script:

function keyListener(e){   if(!e){      //for IE      e = window.event;   }   if(e.keyCode==37 && paddleLeft > 0){      //keyCode 37 is left arrow      paddleLeft -= 4;      paddle.style.left = paddleLeft + 'px';   }   if(e.keyCode==39 && paddleLeft < 436){      //keyCode 39 is right arrow      paddleLeft += 4;      paddle.style.left = paddleLeft + 'px';   }   // FYI - keyCode 38 is up arrow,    //       keyCode 40 is down arrow}

The preceding code uses object detection to distinguish between Mozilla and IE. Mozilla automatically creates the event object and passes it to the listener. IE creates the event object as a property of the window object. So, if the keyListener() function receives a null argument, it knows that the browser is IE and it assigns the correct event object to the e variable.

Next, the event listener determines if either the left or right arrow has been pressed. If the left arrow is pressed, it moves the paddle to the left by 4 pixels. If the right arrow is pressed, it moves the paddle to the right. Both Mozilla and IE correctly interpret a repeated key and produce continuous movement. Since this is a simple demo, it only listens for these two keys, but a more complex game might need to respond to keypresses from other keys as well. If so, you can simply add conditional tests for each of the keys.

Registering the event listener with the document object is simple. Just add the following lines at the bottom of the init() function:

//register key listener with document object   document.onkeydown = keyListener; 

Executing the Main Loop
The next task is to create the game's main loop and start it. Add the start() function to the script:

function start(){   //game loop   detectCollisions();   render();   difficulty();               //end conditions   if(ballTop < 470){      //still in play - keep the loop going      timer = setTimeout('start()',50);   }   else{      gameOver();   }}

The game continues until the user misses the ball. At that point, the ballTop variable will be larger than 470 (just over the height of the gameplay surface minus the height of the paddle plus the height of the ball). Call the start() function at the end of the init() function:

//start the game loop   start();

The main game loop does all the work. It makes calls to detect whether the ball has collided with a boundary, renders objects to the screen, adjusts the difficulty of the game, and determines if the ball is still in play. If the ball is still within the acceptable playing area, it calls setTimeout(). The start() function is quasi-recursive; setTimeout() returns immediately so start() isn't "classically" recursive?but the effect is the same. Using setTimeout() has the added benefit of allowing control over the frame rate of the game. I used a delay of 50 ms. You can adjust the overall speed of the game by manipulating that parameter.

The Game Loop Details
Obviously, the main game loop calls functions that still need to be written. The functions are relatively straightforward so here they are all at once:

function detectCollisions(){   //just reflect the ball on a collision   //a more robust engine could change trajectory of    //the ball based on where the ball hits the paddle   if(collisionX())      dx = dx * -1;   if(collisionY())      dy = dy * -1;}        function collisionX(){   //check left and right boundaries   if(ballLeft < 4 || ballLeft > 480)      return true;   return false;}        function collisionY(){   //check if at top of playing area   if(ballTop < 4)      return true;   //check to see if ball collided with paddle   if(ballTop > 450){      if(ballLeft > paddleLeft && ballLeft <          paddleLeft + 64)        return true;   }   return false;}        function render(){   moveBall();   updateScore();}        function moveBall(){   ballLeft += dx;   ballTop += dy;   ball.style.left = ballLeft;   ball.style.top = ballTop;}        function updateScore(){   currentScore += 5;   score.innerHTML = 'Score: ' + currentScore;}        function difficulty(){   //as the game progresses, increase magnitude of the    //vertical speed   if(currentScore % 1000 == 0){      if(dy > 0)         dy += 1;      else         dy -= 1;   }}        function gameOver(){   //end the game by clearing the timer and modifying    //the score label   clearTimeout(timer);   score.innerHTML += "   Game Over";   score.style.backgroundColor = 'rgb(128,0,0)';}

There are some interesting things going on. First, note that any collision simply reverses the dependent direction of the ball. So, if the ball hits a side or the top boundary, it moves in the opposite direction after the collision. If the ball gets near the paddle, the collision detection routine determines if the ball hits the paddle. If so, collisionY() returns true.

Second, the render() function updates the two dynamic objects of the game?the ball and the score. The ball is moved using some simple animation techniques I described in an earlier article. The game updates the score label by simply writing some new text to its innerHTML property.

Next, the difficulty() function increases the magnitude of the dy variable. That is, it increases the absolute value of the number stored in the variable regardless of the sign. So, if dy is currently negative, it subtracts 1. And if dy is positive, it adds 1.

Finally, the gameOver() function terminates the game loop and provides some visual cues that the game has, in fact, ended.

I tested Rebound with Mozilla Firefox 1.0, Internet Explorer 6.0, and Opera 7.11. Rebound works beautifully in Firefox and IE but fails under Opera. Opera has extensive keyboard shortcuts registered so that Opera users can surf easily using only the keyboard. This includes bindings for the arrow keys and I suspect this is the reason for the failure in Opera. A more robust implementation would sniff for Opera and use different keys?a requirement you should be aware of if you're writing keyhandler routines for people that may be using Opera. In the interest of focusing on the game programming aspects of the script, I've omitted that fix.

I hope this article demonstrates the fundamental principles of game programming using JavaScript.

See also  Types of Custom Web Applications to Consider
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist