Introduction to the Pulse Engine

One interesting corner of HTML5 development is web-based games. With a few well placed canvases and a healthy dose of Javascript, you can create just about any game you can dream. However, the complex nature of Javascript has created the need for a few companies to release game engines built entirely in Javascript and HTML5. This is where Pulse comes in.

Pulse is a game engine built in Javascript. It utilizes HTML5 canvases to display and animate various elements and offers features like event handling, audio, and sprite sheet animations. With the recent release of the developer preview, I would like to take a few minutes and go over some of the neat features that Pulse has to offer.

Lets’s start with a simple sample. Note that all our game-specific code is bundled in the mygame.js file.

<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Paddle Game</title>
    <script src="pulse.js" type="text/javascript"></script>
    <script src="mygame.js" type="text/javascript"></script>
  </head>
  <body>
    <div style="width: 760px; height: 480px;" id="gameWindow"></div>
  </body>
</html>

Pulse comes as a single Javascript file and including it is as easy as adding a reference to that file. Now that Pulse is included, let’s take a look at our myGame.js Javascript file.

// Hook the ready event.  This will fire
// when the DOM and Pulse are both ready for use
pulse.ready(function() {

  // Create the engine, scene, and layer.
  var engine = new pulse.Engine({ gameWindow: 'gameWindow', width: 760, height: 480 });
  var scene = new pulse.Scene(); 
  var layer = new pulse.Layer();

  // Create a Score object.  The Score class extends pulse.CanvasLabel.
  var score = new Score( { text: "0 | 0" } );
  score.position.x = 300;
  score.position.y = 200;

  // Create a ball, position it, and set a few properties.
  var ball = new Ball({ src: 'ball.png', size: {width: 16, height: 16} });
  ball.position.x = 300;
  ball.position.y = 200;
  ball.velocity.x = .25;
  ball.velocity.y = .25;
  ball.score = score;
  layer.addNode(ball);

  //Create the paddles and position them.
  var paddle = new Paddle({ src: 'paddle.png' });
  paddle.ball = ball;
  paddle.position.x = 20;
  paddle.position.y = 150;

  var aiPaddle = new Paddle( { src: 'paddle.png' });
  aiPaddle.ball = ball;
  aiPaddle.position.x = 730;
  aiPaddle.position.y = 150;
  aiPaddle.auto = true;

  // Add the paddles and the score object to the layer.
  layer.addNode(paddle);
  layer.addNode(aiPaddle);
  layer.addNode(score);

  // Make the layer's origin 0,0. The origin defines how objects
  // are positioned - by default objects are positioned by their centers.
  // (0,0) represents the top-left corner.
  layer.anchor.x = 0;
  layer.anchor.y = 0;

  // Add the layer to the scene, then add the scene to the engine.
  scene.addLayer(layer);
  engine.scenes.addScene(scene);

  // Activate the scene.
  engine.scenes.activateScene(scene);

  // Start the game loop and provide a callback, loop, 
  // that will be invoked on each update loop.
  engine.go(20, loop);
});

This example is the start of a pong game, with a few things stripped out for simplicity. All the basic Pulse elements are there though. You create some game objects, in this case paddles and a ball, then add them to a layer. This layer then gets added to a scene. Finally the scene is added to the game.

Once all the objects, layers, and scenes are setup, you just create a main logic loop (which is empty here), then call engine.go(). All of this is wrapped in a ready call so the game is started when the browser is finished loading Pulse and the rest of the website.

Most engines follow this paradigm, but Pulse makes it extremely easy. With a few lines, you can have game objects loaded and update logic running. You just have to set up a few layers and a scene or two, and you are good to go. However, ease of use is not the only strong point of Pulse.

One of the more advanced features Pulse has is a very structured object hierarchy, all built to be extensible. Any, and I do mean any, Pulse object can be extended and added to. Not only is it possible to extend an object, it is extremely easy. In the example above the Paddle, Ball, and even the Score object are actually extensions of a base Pulse object. Here are the classes in full, take a look:

var Paddle = pulse.Sprite.extend({
  init: function(params) {

    // Call the base constructor.
    this._super(params);

    // Add properties to determine what arrow key has been pressed.
    this.arrowUp = false;
    this.arrowDown = false;

    this.size.width = 50;
    this.size.height = 200;

    // Bind the key events to set the arrow up/down properties.
    this.events.bind('keydown', 
      function(e) {
        if(e.keyCode == 38) {
          e.sender.arrowUp = true;
        }  
        else if(e.keyCode == 40) {
          e.sender.arrowDown = true;
        }
      });

    this.events.bind('keyup',
      function(e) {
        if(e.keyCode == 38) {
          e.sender.arrowUp = false;
        }  
        else if(e.keyCode == 40) {
          e.sender.arrowDown = false;
        }
      });
  },

  /* The update function runs every game "tick." This update function
     will move the paddle based on what key is currently down, as long
     as it is in the bounds of the game canvas. */
  update: function(elapsed) {
    this._super(elapsed);

    if(this.auto) {
      if(this.ball.position.y < this.position.y) {
        this.position.y -= .15 * elapsed;
      }
      else if(this.ball.position.y > this.position.y) {
        this.position.y += .15 * elapsed;
      }
    }
    else {
      if(this.arrowUp) {
        this.position.y -= .15 * elapsed;
      }
      else if(this.arrowDown) {
        this.position.y += .15 * elapsed;
      } 
    }
  }  
});

var Ball = pulse.Sprite.extend({

  init: function(params) {

    // Call the base constructor.
    this._super(params);

    // Setup a few velocities, which determine the ball's speed.
    this.velocity = { };
    this.velocity.x = .25;
    this.velocity.y = .25;

    // The bounds of the area in which the ball can go.
    this.maxX = 760;
    this.maxY = 480;
  },

  /* Bounces the ball if it has made it to any of the bounds,
     at a 45 degree angle. Also increments the score if it has
     reached a horizontal bounds, IE has made it to a players side. */
  update: function(elapsed) {
    this._super(elapsed);

    this.position.x += elapsed * this.velocity.x;
    this.position.y += elapsed * this.velocity.y;

    var xMax = this.maxX - (this.size.width / 2);
    var yMax = this.maxY - (this.size.height / 2);
    var xMin = this.size.width / 2;
    var yMin = this.size.height / 2;

    if(this.position.x > xMax) {
      this.position.x = xMax;
      this.velocity.x *= -1;
      this.score.playerScore();
    }

    if(this.position.x < xMin) {
      this.position.x = xMin;
      this.velocity.x *= -1;
      this.score.aiScore();
    }

    if(this.position.y < yMin) {
      this.position.y = yMin;
      this.velocity.y *= -1;
    }

    if(this.position.y > yMax) {
      this.position.y = yMax;
      this.velocity.y *= -1;
    }
  },
});

// This class keeps track of the score and draws it to the canvas.
var Score = pulse.CanvasLabel.extend({
  init: function(params) {
    this._super(params);

    this.scoreA = 0;
    this.scoreB = 0;
  },

  playerScore : function() {
    this.scoreA++;
    this.text = this.scoreA + " | " + this.scoreB;
  },

  aiScore : function() {
    this.scoreB++;
    this.text = this.scoreA + " | " + this.scoreB;
  }
});

As you can see, all that it takes is a simple call to the extend method one any object and you have the ability to make your own subclass. In this case we are just overriding the update function, but the possibilities are endless.

Put all this together and you get a simple pong game that looks like so:

Pulse offers a lot to any web developer, whether they are building a game or an application. With this just being the developer preview, who knows what may be in store for the future.

Comments 0

Leave a Reply