Saturday, 10 August 2013

a java-script game: a Sound-Library and type-checking

Sound is essential in video games.  Luckily, sound is realy easy in java-script.  There is a thing called the Audio object.  Much the same as the Image object.  We can create an almost identical library to the image library we created before to play sounds in our game.

Here is little sample that'll play a sound when the page is loaded.  The sound load synchronously, as opposed to images that insist on loading asynchronously.  Making our job a little easier.

<html>
<body>

<script type="text/javascript">
<!--
  // create the object
  var sound1 = new Audio();
  // set the location of the sound
  sound1.src = "http://peter3125.freewebhost.co.nz/snd/drop.mp3";
  // if the object has the methods we expect it to have,
  // load it and play it
  if ( sound1.load && sound1.play )
  {
    sound1.load();
    sound1.play();
  }

//-->
</script>

</body>
</html>


Notice the if statement above.  Its actually not needed from a programmatic point of view.  It is an issue of style.  The "if" statement checks for the existence of a "load" and a "play" method on the sound1 instance of the Audio() object.  Strictly speaking the "if" statment isn't quite there yet.

Perhaps its time to quickly mention some of the java-script operators.  In a typical programming language like C# / C / C++ there are several operators you can use to compare things.

Typically in Java and C# you'd want to use a statement like

if ( obj != null ) ...

which reads "if object is not null", meaning "if the object exists" pragmatically.  "!=" is the "does not equal" operator.

similarly if we wanted to make sure an object didn't exist we'd write

if ( obj == null ) ...

where "==" is the equals operator (aka. the double equals operator).

Java-script's == operator is a little cleverer than the C# / Java operator of the same name.  Java-script's == operator will try and convert types to make them match.  In java-script

if ( "5" == 5 )
{
   alert("they're equal!");
}

will show a dialog box, in Java and C#, not so much.

If you want to use the equivalent operator to C# and Java there is the === (triple equals) operator.  That operator compares the values without doing any conversion.

if you want to check that something has been defined, you'd use

if ( typeof(myvar) === 'undefined' ) alert("myvar is not defined");

if you wanted to check if something is an existing function on an object you'd write:

var myAudio = new Audio();
if ( typeof(myAudio.play) === 'function' ) alert("myAudio.play is a function");

the "if" statements I used above are lazy versions of the same.  They basically read "if sound1 has something called play that isn't undefined".  That isn't strictly speaking the same as checking whether it is a function or not.  And since I then try to use it as a function.  You can already figure out that this shortcut could end up trying to use a "property" called "play" on the object as a function.  That would fail.  BUT, since Audio() is one of those well defined functions provided to you by java-script, you can (for now, until they change the standard) rely on the fact that if it has something called "play" on it, that play will be a "function".

So then you say: "well, so why do you check for it at all?".  Good point.  Best answer is "habit".  And its a good habit to have and to start using.  My rule is to always check for "null" in languages such as Java and C#.  If you do write those few extra lines, right from the start, you will always end up with better code (and more code, but thats not a plus necessarily).

So we might as well dig straight into a little sound library class.  I'll just take the image library we created before, and refactor it a little to deal with sounds.

<html>
<body>

<script type="text/javascript">
<!--
 
  // little sound library
  function AudioLibrary()
  {
    var self = this;
    var lookup = {};

    // no callback methods needed - just setup the sounds
    this.setup = function( callback )
    {
      // just to make this sampel work using my free website
      // remove base here and below to make it work for your own stuff
      var base = "http://peter3125.freewebhost.co.nz/";
      this.load( "fire-missile", base + "snd/drop.mp3");
      this.load( "land-ship", base + "snd/land.mp3");
      this.load( "explode", base + "snd/explosion.mp3");
      this.load( "shoot", base + "snd/shot.mp3");
    };

    // setup a loader with a wait function
    this.load = function( str, src )
    {
      var sound = new Audio();
      sound.src = src;
      if ( sound.load )
      {
        sound.load();
      }
      lookup[str] = sound;
    };

    this.play = function( str )
    {
      if ( lookup[str] && lookup[str].play )
      {
        lookup[str].play();
      }
    };

  }
 
  // the the library
  // create a new instance
  var sndLib = new AudioLibrary();
  // load all the sounds
  sndLib.setup();
  // play two sounds - pretty much at the same time
  sndLib.play( "fire-missile" );
  sndLib.play( "explode" );
 
 
//-->
</script>

</body>
</html>

Friday, 9 August 2013

JSON and other data in java-script

A game needs to load a variety of items/data.  What you need of course depends on what your games does/is.  We've discussed loading images.  Now its time to look at some data-structures.

What is a data-structure?  Its literally - just a bunch of information organised in a certain manner.  It is the structure of the data.  Gravity Force has levels that consists of caves with tiles in them.  The Gravity Force 'caves' can be modified at game time.  They can be damaged or changed by the players.

Java-script's most natural data-structures is the hashmap.  Turns out there is a popular outside representation for java-script called JSON (Java-Script Object Notation).  JOSN looks just like java-script without any of the code.  Its raw data.  Its fairly succinct too.  It is one of my personal favourites at this moment in time.  I've moved away from using xml and started using JSON all over my professional and personal projects.

Lets have a look at some JSON and how to consume it.

{
  "player1":
    {
       "ship": "ship1",
       "base": 0,
       "maxSpeed": 4,
       "maxAmmo": 200,
       "numMissiles": 5,
       "guidedMissiles": true,
       "acceleration": 0.05,
       "fuelUsage": 0.05,
       "refuelSpeed": 0.1,
       "repairSpeed": 0.1,
       "rearmSpeed": 0.1,
       "exampleArray": [1,2,3,4],
       "rotationSpeed": 5,
       "bulletColour": "#ffffaa",
       "bulletShipDamage": 8,
       "bulletSpeed": 5,
       "keys": { "left": 37, "right": 39, "down": 40, "up": 38 }
    }
}

This is one of the player's definitions for one of the levels in the game.  What the exact fields mean isn't that important at this time.  You can see a mixture of arrays [], Boolean values (true/false), string, numbers etc.  The curly brackets { } indicate collections.  I've indented them so I can see what data goes where.

JSON is always of the format "name": value.  The "name" field can be any label you wish.  It is the hashmap's key.  The value field can be any of java-script's data-types (strings, numbers, Booleans, arrays, other collections in {}, null).

The important thing about JSON is that it starts and ends inside a set of curly brackets {} at the top level.

the JSON data can be really easily turned into actual java-script data using jQuery.

You can create whatever JSON you like and 'load' it (use HTTP-GET in java-script) from anywhere on the Internet you like as follows;

var urlStr = 'data/myjson.json';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open( "GET", urlStr, false );
xmlhttp.send();
var jsonStr = xmlhttp.response;

// turn the json string into an actual
// java-script object
var result = jQuery.parseJSON(jsonStr);
if ( result )
{
  alert('got it!');
}

The thing I wanted to do with Gravity Force is turn images of levels (i.e. user designed caves) into java-script JSON.  I wrote a little Java program (as I am a professional commercial Java developer) to do just this.  The following java program loads an image from wherever you point it to.  (it assumes a black and white image, where white is a tile, and black is a space in the cave).  This is a screenshot of some of the output of the program and the original bitmap image I converted so you can see what I'm trying to achieve.



the original bitmap I created using the GIMP, a black and white 256 x 256 pixel PNG file

the top left corner the same image as a JSON data structure, created using the little Java program below



import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;

/*
 * Created by Peter
 *
 * load a bitmap and convert it to a two dimensional javascript array
 *
 */
public class Main
{
    // runs with one cmd line parameter - the image to convert to JSON
    public static void main(String[] args)
    {
        BufferedImage img = null;
        try
        {
            img = ImageIO.read(new File( args[0] ));            if ( img != null )
            {
                StringBuffer sb = new StringBuffer();
                sb.append("{\n");
                sb.append("  \"data\": [\n");

                int[] array = new int[4];
                Raster raster = img.getData();
                for ( int y = 0; y < raster.getHeight(); y++ )
                {
                    sb.append("        [");
                    for ( int x = 0; x < raster.getWidth(); x++ )
                    {
                        raster.getPixel( x, y, array );                        if ( x > 0 )
                        {
                            sb.append(",");
                        }
                        if ( array[0] > 0 )
                        {
                            sb.append( "5" );
                        }
                        else
                        {
                            sb.append( "0" );
                        }                    }
                    sb.append("]");

                    if ( y + 1 < raster.getHeight() )
                    {
                        sb.append(",");
                    }                    sb.append("\n");
                }

                sb.append("    ]\n");
                sb.append("}\n");
                System.out.println( sb.toString() );               }
        }
        catch (IOException e)
        {
            System.out.println( e.toString() );
        }

    }
}

Tuesday, 6 August 2013

a java-script game, Loading Images and Asynchronous vs. Synchronous

Web Browsers in general are inherently parallel entities.  They like to do things in parallel.  It makes web pages load a lot faster.  It makes perfect sense.  It does have implications on how things work.  Our neat model of doing things in steps doesn't fit that model quite as well.

There are several ways you could deal with this.  You could start loading the images you need, and start your game with an incomplete set of images and wait for the rest to arrive as they do.  Not very neat - but - possible.

The other way would be to wait for all the images to load.  The "please wait, loading..." approach.

For the purposes of our game, we assume we're loading a fixed set of images, and we load them 'up-front', before the game starts that is.  We will create a little library for doing just that.

We create an instance of the ImageLibrary class show below.  We call 'setup()' on the library which starts it loading the images in parallel.  Once all the images have loaded, the library calls us back.

Whats this callback stuff I keep talking about?  Well, in Computer-Science there are two ways of communicating with systems (with that I mean entities other than your own pogram).  Synchronous and Asynchronous.  Synchronous should be most familiar to you.  Suppose I want to load a file from disc, and there is a function provided by the Operating System called "loadFile( filename )".

In synchronous mode, I'd call / invoke loadFile("my file") and the program would what we call "block" until the loading of the file had completed.  In most cases, that block would be really short, almost unnoticeable.  The "blocking" means my program will be stopped until the loading (or whatever the remote entity needs to do) has completed.  We call it a "block" because we're passing control to another part of the system and effectively go to sleep ourselves until it is all done.  The trick is, you never really aware that you've been put to sleep.  As far as you're concerned, its just another step in the program.

In asynchronous mode you'd have to give "loadFile" one additional piece of information.  You'd have to tell "loadFile" who to notify of the completion of the task (in a lot of cases the system callback could also include information on what happened (e.g. successfully loaded the file, could not find the file, etc).  It is asynchronous because it doesn't block our program.  But at the same time, our program doesn't get what it needs immediately either.  The advantage of asynchronous is that we can start doing other things while we wait.  Sometimes that isn't an option.  It could be that we need whatever it is right here and now.  You can use "asynchronous mode" in a synchronous fashion (Don't fret.  Most of the time, computer programs behave in a synchronous fashion).

Whether something is synchronous or asynchronous is not up to us.  It is part of whatever library / function  you're using at the time.

You could do the following for instance to turn something inherently asynchronous into a synchronous step.

// a variable for waiting
var stillWaiting = true; // we start 'waiting'

// the callback function
function notificationDone()
{
  stillWaiting = false; // no longer waiting
}

// a function to go to sleep or a second
function sleepForASecond()
{
  var date = new Date();  // get current date/time
  var curDate = null;
  // wait for 1000 milli seconds
  do
  {
    curDate = new Date(); // update the time
  }
  while ( (curDate - date) < 1000 ); // 1 second = 1000 milliseconds
}

// some asynchronous load that calls 'notificationDone'
// when finished
loadFile( "some file", notificationDone );

// a little loop that repeats forever until
// loadFile calls back
while ( stillWaiting )
{
  sleepForASecond(); // wait for a second
}

There is always a danger with asynchronous callbacks that you never get the callback.  This can happen if something goes terribly wrong.  Worse, the thing you're waiting for takes a long time to complete due to unforeseen circumstances.  I've seen web-servers return a byte every few seconds.  Technically that isn't considered a time-out.  It however results in pages taking hours to complete.  I'm sure you've experienced it yourself in your own web-browser.  The only thing you can do is to 'stop' the page loading, and restart ('refresh') the page starting from scratch.

You could change the while loop above to include a time limit.

// get the current time in milliseconds and add 5 seconds to it
var counter = 0;
while ( stillWaiting && counter < 5 )
{
  sleepForASecond();
  counter = counter + 1;
}

if ( stillWaiting )
{
  alert("we didn't get what we were waiting for, time-out!");
}

This is the same while loop we had before, but it will only ever wait for five seconds (unless the callback completes before then).

In general - I wouldn't recommend you use the "while () { sleep }" approach in java-script.  It works well in other languages like Java or C# where you have more control over the process itself, but isn't that elegant in java-script.

Lets look at our image library inside an html page.  You might have guessed by now that java-scripts Image() load function is asynchronous (Setting an image's .src to a url starts it loading an image).  The library is designed to call us back when its done.  Don't forget our new friend jQuery, loaded right at the beginning.

<html>
<head>
  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
</head>
<body>
  <div id="divPleaseWait">please wait, loading...</div>

  <script language="javascript">

  function ImageLibrary()
  {
    var self = this;
    var lookup = {}; // hashmap for name -> image
    var available = {}; // hashmap for name -> loaded (true/false)
    var parentCallback = null;

    // callback must implement a ready() method
    // and will be called from the image library
    // once all images have been loaded
    this.setup = function( callback )
    {
      var base = "http://peter3125.freewebhost.co.nz/";
      parentCallback = callback;
      // this is a list of all the images we want to load
      // I've given each image a "friendly" name and a filename
      this.load( "ship1", base + "img/gf5/ship1.png");
      this.load( "ship2", base + "img/gf5/ship2.png");
      this.load( "ship3", base + "img/gf5/ship3.png");
      this.load( "ship4", base + "img/gf5/ship4.png");
      this.load( "background", base + "img/gf5/background.png");
      this.load( "base", base + "img/gf5/base.png");
      this.load( "smallbase", base + "img/gf5/smallbase.png" );
      this.load( "explosion", base + "img/gf5/explosion.png");
      this.load( "turret", base + "img/gf5/turret.png");
      this.load( "exhaust", base + "img/gf5/exhaust2.png");
      this.load( "missile", base + "img/gf5/missile.png");
    };

    // setup a loader with a wait function
    this.load = function( str, src )
    {
        var img = new Image();
        // setup the internal callback function of the library
        img.onload = function() { self.loaded(str, src); };
        img.src = src; // do the loading
        lookup[str] = img;
        available[str] = false;
    };

    // get an image by name (for later)
    this.get = function( str )
    {
        return lookup[str];
    };

    // callback from the img.onload function
    this.loaded = function( str, src )
    {
        // note that this image
        // has now been loaded
        available[str] = true;

        // all images loaded?
        var allAvailable = true;
        $.each( available, function(i, item)
        {
            if ( !item )
            {
                // nope - found an image not yet loaded
                allAvailable = false;
            }
        });

        // callback the parent when we're done
        if ( allAvailable && parentCallback )
        {
            parentCallback();
        }
    };
  }

  // the callback function
  function callbackNotification()
  {
    $("#divPleaseWait").hide(); // hide the message
    // start the game, or something - we're ready!
    alert('all images have been loaded, we can start our game');
  }

  // create an instance of the image library
  var library = new ImageLibrary();
  // start the loading and give it a callback function
  library.setup( callbackNotification );
  </script>
</body>
</html>

The library just illustrates a point.  But its powerful enough for you to use in your own games.  We'll take a look later at how to use this library exactly in the game.

Monday, 5 August 2013

User Input and Hashmaps

There is only one beginners trick to user-input.  That trick is not to rely on the system's own primary input but to buffer it.

Let me explain.  We will only be dealing with the keyboard for our games.  Phone/slider input is possible, but a different ball-game at present.  There are two events we are interested in.  A key-down event, and a key-up event.

If we were to solely rely on the key-status itself without capturing it properly, we'd get input that would resemble the typo-matic rate of your keyboard.  You can try it for yourself.  Open up notepad if you're using windows and hold down the 'A' key.  At first there is a pause, and then the letter repeats until you let go.  We don't want our game to behave like that, its unnatural and looks bad.

Let me introduce your new best friend first, before we go into any more detail.  Its about time we met jQuery.  jQuery is an incredible library (free too) that is used by just about everyone writing java-script.  All we need to do is download (if you're that way inclined) and host it on your own web-site, or, given the power of the Internet, link to the library from your own web-page.

You will need to get used to jQuery, as you would with any new library.  For now, all you need to know is that anything to do with jQuery starts with the dollar symbol ($).

Typically, jQuery is used to reference objects in your DOM.  Supposed you have the following html;

<html>
<body>
<div id='div1'></div>
</body>
</html>

Nothing very exciting I'm afraid, but this is just to give you the initial basics of jQuery.  There are plenty of tutorials on how to use it.  jQuery would refer to the <div> inside this html page using its id like so;

$('#div1').html('hi there!');

This statement means, put the string "hi there!" inside the html of the DOM object with id 'div1'.  Takes a little getting used to.  The hash (#) tells jQuery that the thing followig it is a DOM element id.

jQuery can refer to other aspects of the DOM too.  This is what we're interested in right now.

function KeyboardMapper()
{
  var self = this;
  var keymap = { "left": false, "right": false, "up": false, "down": false };

  this.left = function( isDown )
  {
    keymap["left"] = isDown;
  };

  this.right = function( isDown )
  {
    keymap["right"] = isDown;
  };

  this.up = function( isDown )
  {
    keymap["up"] = isDown;
  };

  this.down = function( isDown )
  {
    keymap["down"] = isDown;
  };

  this.showKeys = function( context )
  {
    context.fillStyle = "#ffffff"; // white colour for text
    context.font = "12px Tahoma"; // font-size and name

    if ( keymap["left"] )
      context.fillText( "left-arrow key is down", 10, 10 );
    else
      context.fillText( "left-arrow key is up", 10, 10 );

    if ( keymap["right"] )
      context.fillText( "right-arrow key is down", 10, 30 );
    else
      context.fillText( "right-arrow key is up", 10, 30 );

    if ( keymap["up"] )
      context.fillText( "up-arrow key is down", 10, 50 );
    else
      context.fillText( "up-arrow key is up", 10, 50 );

    if ( keymap["down"] )
      context.fillText( "down-arrow key is down", 10, 70 );
    else
      context.fillText( "down-arrow key is up", 10, 70 );
  };
}

// create the object
var keyObject = new KeyboardMapper();

$(document.body).on('keydown', function(e)
{
  switch (e.which)
  {
    case 37:
      keyObject.left(true); break;
    case 39:
      keyObject.right(true); break;
    case 40:
      keyObject.down(true); break;
    case 38:
      keyObject.up(true); break;
  }
});

$(document.body).on('keyup', function(e)
{
  switch (e.which)
  {
    case 37:
      keyObject.left(false); break;
    case 39:
      keyObject.right(false); break;
    case 40:
      keyObject.down(false); break;
    case 38:
      keyObject.up(false); break;
  }
});

The statements above use jQuery to hook into the document's (the html page's) key-down and key-up events.  These are special functions that are called by the system when a key goes... down... and... up again.  Don't ask why, but the arrows keys are represented by the following numbers on the keyboard.

left arrow = 37
right arrow = 39
down arrow = 40
up arrow = 38

Each key on the keyboard has a number.  Just Google "java-script event keycode" or go to http://www.asquare.net/javascript/tests/KeyCode.html for a good demonstration of key-codes.

Our little sample again uses a canvas to draw things (get used to it).  The code showing a working sample on how to use the keyboard and how it reacts to your keys can be downloaded here.  The canvas below is a live sample of the code we've been discussing.  Click on it (just to give this page input focus in case it hasn't got it already) and use the arrow keys on your keyboard to see how it works.


Hashmaps

Lets talk about hashmaps.  We've just used our first hashmap in anger.  Hashmaps are wonderful things.  Java-script uses them all the time, and if you're the clever person you are (for reading this blog) you should get used to them as fast as you can.  It seems that these hashmaps are rather central to java-script.

A hashmap is what we in computer science call a data-structure.  A hashmap is a name-value store.  You can put things into a hashmap by name, and retrieve them again by name really efficiently.  There is no need to know how a hashmap works internally.  A hashmap is a data-structure that uses a little bit more memory (usually around 30% more than you're actually storing) for an incredibly fast retrieval speed.

Lets look at an example;

var myHashmap = {};

This creates an empty hashmap called "myHasmap".  We can now put some stuff into it;

myHashmap["peter"] = "this is a hashmap";

This inserts a value string "this is a hashmap" and stores it under the name "peter".  To retrieve the string you put in, just go like

var myValue = myHashmap["peter"];

"myValue" will be "null" if there is nothing stored under "peter".  But in our example, "myValue" will be the string "this is a hashmap".

You could also create a hashmap with a set of values in it from the start, when you create it, as we did in the keyboard example above.

var keymap = { "left": false, "right": false, "up": false, "down": false };

This hashmap hash four values in it with the names "left", "right", "up", and "down".  All their values are initially set to the boolean value false.

A hashmap does not use strings alone.  It can use numbers, and strings for its names, and its values can be anything that java-script can create.  Booleans, numbers, strings, classes (aka. functions in java-script).  I suspect that java-script itself is rather one big hashmap.  For our purposes, and for most purposes to be honest, we tend to use strings for the name/key of a hashmap.

Saturday, 3 August 2013

Double Buffering

Games never draw directly to the screen.  It doesn't matter how fast your computer is, or how good your video card.  Any direct drawing the 'live' or real video buffer will make for an unpleasant viewing experience.

The solution is called a double buffer.  If you like, a second copy of the screen that isn't visible.  The screen is just a large block of memory with bytes representing RGB values.  Modern video cards too have special fast memory for this very purpose.

So, one does all ones drawing to the off-screen buffer, and then in one foul swoop copy the contents of that invisible buffer to the visible buffer.

Creating the off-screen buffer is simple in java-script.  We just create another canvas (but not one that lives inside the DOM, the visible HTML if you like).

// create a second off-screen buffer
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 1024;
offscreenCanvas.height = 768;
offscreenContext = offscreenCanvas.getContext('2d');

As you can see, this is completely compatible with the drawing routines we looked at before.  I've made the "offscreenCanvas" in this example 1024 pixels wide and 768 pixels high.  Usually your double buffer would be exactly the same size as the visible canvas we will be copying it to.  You can however have more than one offscreen buffer.  The reason you'd do this is to perhaps draw something like a split screen (e.g. two players on one screen in their own seperate areas).  You could make the offscreenCanvas smaller than the destination buffer and leave some room on the destination buffer for status displays etc.

How do we copy the contents of this offscreen buffer to the real one?  Simple: given that "screenContext" is the 2d context of the canvas on the screen, we use yet another variant of drawImage.  This one takes the offscreen CANVAS as a parameter, and the location of this buffer inside the other one.  (0,0) is the top left corner.  It is important to not get confused between the CANVAS and the CONTEXT.

The CONTEXT is the thing that gets drawn into.  The CANVAS is the thing that is displayed.  The first parameter in the double buffer copy is the offscreen CANVAS, NOT its CONTEXT.  A CANVAS also has a "width" and a "height" (dimensions).  The CONTEXT doesn't!

screenContext.drawImage( offscreenCanvas, 0, 0);

So lets create a simple sample using this.  We need to use a timer, because we want to have something move around.

Each frame/timer event we:

1.  Clear the offscreen buffer with fillRect()
2.  Draw whatever we need to inside the offscreen buffer
3.  Copy the offscreen buffer to the screen buffer (if they are the same size we won't need to do any cleaning of the screen buffer since it will be cleared by the content of the offscreen buffer.

In this sample I will make red "balls" move around the screen.  To do this we need to introduce a new drawing function for drawing circles.  Its called "arc".  "arc" takes 5 parameters, they are:

context.arc( x, y, startAngle, endAngle, counterClockwise );

where: x, y,  is the center of the circle
startAngle  the start angle in radians
endAngle  tne end angle in radians
counterClockwise a boolean variable requesting the circle be drawn counter clockwise (or clockwise if false)

"arc" is actually a very versatile function that can draw many different kind of shapes.  In particular it is good at drawing pac-man.  We only need it to draw a circle though (sorry to spoil the fun, the fun comes later!)

We introduce two classes.  The first class is our BouncyBall class, shown below.

// a bouncy ball   
function BouncyBall( x, y, colour, speed, size, width, height, canvas )
{
  var self = this;
  var myX = x;
  var myY = y;
  var myCanvas = canvas;
  var ballColour = colour;
  var mySize = size;

  var directionX = speed;
  var directionY = speed;

  var myWidth = width;
  var myHeight = height;

  // draw the ball
  this.draw = function()
  {
    //draw a circle
    myCanvas.beginPath();
    myCanvas.fillStyle = ballColour;
    myCanvas.arc( myX, myY, mySize, 0, Math.PI*2, true);
    myCanvas.closePath();
    myCanvas.fill();
  };

  this.move = function()
  {
    myX = myX + directionX;
    myY = myY + directionY;

    if ( directionX < 0 )
    {
        if ( myX < 0 )
     {
          directionX = speed;
        }
    }
    else
    {
        if ( myX > myWidth )
        {
          directionX = -speed;
        }
    }

    if ( directionY < 0 )
    {
        if ( myY < 0 )
     {
       directionY = speed;
     }
    }
    else
    {
        if ( myY > myHeight )
     {
       directionY = -speed;
     }
    }
  };

}

Now you're going to get another lecture in object oriented programming.  The class above is a self contained class that can both move, and draw a ball.  Nothing too complex.  It is always important to seperate the MOVING (the logic) from the DRAWING (the rendering).  The real power of the object oriented-ness of this class will come about through the Controller class below.

Creating the ball takes the following parameters (x, y, colour, speed, size, width, height, canvas).  The x,y is its starting position on the screen.  The colour is its colour.  The speed how fast it moves.  The size, how big it is.  The width and height are the CONTEXT's size - so that the ball knows when its hit the edges of the screen.  Canvas, the last parameter, is where to draw the ball (the offscreen buffer in this case.

The second class is the "controller" (or scene) class.  It draws the balls and moves the balls.  It coordinates everything and is the thing that is called by the timer.

// the glue/logic for this little demo 
function Controller( numBalls, screenCtx, offscreenCanvas, offscreenCtx )
{
  // store the two buffers
  var offscreenCtx = offscreenCtx;
  var offscreenCanvas = offscreenCanvas;
  var screenBuf = screenCtx;
  var myWidth = offscreenCanvas.width;
  var myHeight = offscreenCanvas.height;

  // a list of balls (empty initially, setup() populates it)
  var ballList = [];

  this.setup = function()
  {
    for ( var i = 0; i < numBalls; i++ )
    {
      // create balls at different positions of different sizes and speeds
      ballList.push( new BouncyBall( 2 * i, 2 * i, "#ff0000", 2 + i / 10,
                            25 + i / 2, myWidth, myHeight, offscreenCtx ) );
    }
  };

  this.drawAndMove = function()
  {
    // clear the offscreen canvas
    offscreenContext.fillStyle = "#000000"; // colour black
    offscreenContext.fillRect( 0, 0, myWidth, myHeight );

    // draw and move the balls all in one go
    for ( var i = 0; i < ballList.length; i++ )
    {
     ballList[i].draw();
     ballList[i].move();
    }

    // do the double buffering
    // scene complete - copy offscreen buffer
    screenBuf.drawImage( offscreenCanvas, 0, 0);
  };

};

I mentioned "object oriented" and "power" in the same sentence.  This wasn't an oxymoron!  The controller class with just a few lines of code can control 100s of balls all at once.  Our example only uses 25 balls.  I'd encourage you to download the sample below and play with it. Finally - the "scene" and the timer are created

// create a controller with 25 balls moving all at once
var ctrl = new Controller( 25, screenContext,
                           offscreenCanvas, offscreenContext );
// initialise the balls (only needed once)
ctrl.setup();

// callback the controller's drawAndMove() function
// 20 times per second (20 x 50 = 1000 ms = 1 second)
window.setInterval( ctrl.drawAndMove, 50 );

The java-script and html for this sample can be downloaded here.
The final little ball demo is quite mesmerizing.  Different sized balls moving at different speeds and all moving in different directions.

Thursday, 1 August 2013

more java-script drawing

In 2d games, animation is changing images, much like frames in a movie.  The problem for programmers like myself is... creating them.  I've been lucky that the graphics I will present here were created for me years and years ago by some very talented 2d artists.

So how does it work?  First of all, you need to create an "animation strip".  Basically a series of images the same size (preferably) that form your mini movie.  First thing to take into account is image transparency.

This is because 2d games are layered.  Whatever you draw last goes over the top of things already drawn.  So typically we construct scenes in layers.  Backgrounds first, then the player's and all things around us, and finally, usually last, display items such as health-bars, scores etc.

Images are always rectangular.  In the old days images used to have to be powers of 2 in size (e.g. their sizes had to be one of 2, 4, 8, 16, 32, et.etc) for hardware limitation reasons.  That limit doesn't exist in java-script.

I use a program called the Gimp (GNU Image Manipulation Program) for changing images and adding transparencies.  Its free and its fairly easy to use.

Drawing in General

First we need to load an image.  You can load any image from the Internet quite easily and hold on to it in java-script.  Here is a little class I used to load an image

function ImageLibrary()
{
    this.images = {};

    // setup a loader with a wait function
    this.load = function( imageUrl )
    {
        this.images[imageUrl] = null;
        var img = new Image();
        img.src = imageUrl;
        img.onload = function() { this.loaded(img, imageUrl); };
    };

    this.loaded = function( img, imageUrl )
    {
        this.images[imageUrl] = img;
    };
}

to use this little class it you would use the following java-script;

// create the library instance
var imgLibrary = new ImageLibrary();
// load an image
imgLibrary.load( 'img/image.jpg' );

There is only one problem with java-script images.  They load "asynchronously".  You tell java-script to download it (the img.src = imageUrl line does that) and java-script will go away in parallel, and tell you when its done.  The img.onload = function() takes care of that.  Its what we call a "callback".  The system will do its thing and we redirect it to "this.loaded" when it has done its thing.

Lets not worry about how to deal with that for now.  I will show you a complete sample now that loads three images and draws them onto your canvas in order of loading.

<html>
<body>
  <canvas id="gameCanvas" width="200" height="200"
    style="border:1px solid #000000;">
  </canvas>

  <script language="javascript">
  
 function ImageLibrary( context2d )
 {
     var self = this;
     var context = context2d;

     // load an image and draw it when its ready
     this.loadAndDraw = function( imageUrl, x, y )
     {
         var img = new Image();
         img.src = imageUrl;
         img.onload = function() { self.drawImage(img, x, y); };
     };

     // draw an image @ x,y rotated around its center by rot in degrees
     this.drawImage = function( img, x, y )
     {
            context.drawImage( img, x, y ); // adjust drawing
     };
 }

 // get canvas
    var screenCanvas = document.getElementById("gameCanvas");
    var screenContext = screenCanvas.getContext("2d");

 // create new library
 var lib = new ImageLibrary( screenContext );
 lib.loadAndDraw( "img/ship1.png", 10, 10);
 lib.loadAndDraw( "img/ship2.png", 20, 20);
 lib.loadAndDraw( "img/ship3.png", 30, 30);
  
  </script>

</body>
</html>

One little thing I need to make you aware of is a very important line in the java-script.

var self = this;

Here "self" is local private variable.  I called it "self" and it has no significance beyond that.  "self" is assigned "this".  "this" is a very special variable if you recall.  It is the object you're inside if you like.  It allows a thing to refer to itself.  The important part here is that "this" will change depending on where you are.  If you look at the code above for the "img.onload = function" part above, you'll see that I used "self" instead of "this".  This is because at that point inside the new "function() { ...", our "this" object will have changed and refer to another entity.  This is where "self" comes to the rescue.  The same problems occur if you use a library called jQuery.  I do use jQuery later on.  So remember "var self = this;"   :)

There, a start.  You can download that sample here.  The output of this program is as follows:



Drawing Animations

Lets do something more exciting, something grander.  Lets do something that moves.  There are two things we need to do to make an animation.  We already have an animation strip, shown here.


Now we need to write the code to display it after its loaded - and change it.  We're still keeping it simple at this point.  The code I'm showing you isn't ready for a game yet.  It does however form the foundations for one.

The image shown has 16 different animations in it.  The image goes across (i.e. the changes in the animation are horizontal.  The image is 2560 pixels wide by 120 pixels high.  Given it is a combination of 16 different images, this means that each individual image is 160 pixels across and 120 pixels high.

There is a function in java-script for drawing smaller parts of an image.  This is exactly what we'll use to draw the image.

That function is a variant of the draw-image we used above.  It takes a lot more parameters.

.drawImage( img, offsetX, offsetY, singleWidth, singleHeight,
     screenx, screeny, singleWidth, singleHeight );

Thats a lot of parameters.  "img" is of course the image itself.  This can be drawn after its loaded.  "offsetX" and "offsetY" are offsets inside the image we've loaded.  The first singleWidth and singleHeight parameter are how much to draw from the image strip.  "screenx" and "screeny" are the screen location/destination of where the image is to go.  The second "singleWidth" and "singleHeight" are the same as the first and are how big the image is to appear on the screen.

The only other thing we need is time.  A timer to be more exact.  We need to change the image (because it is an animation) over time.  What we need to do is the following about 20 times a second

1. each time, we clear the screen for a new "scene"
2. we draw the correct animation of the graphic
3. thats it - the timer will come around again and start at 1.

function ImageLibrary( context2d )
{
  var self = this;
  var context = context2d;
  var index = 0;
  var numAnimations = 16;
  var animationImage = null;

  // load an image and draw it when its ready
  this.loadAndDraw = function( imageUrl )
  {
    var img = new Image();
    img.src = imageUrl;
    img.onload = function()
    {
      animationImage = img;
      window.setInterval( self.drawImage, 50);
    };
  };

  this.drawImage = function()
  {
    if ( animationImage != null )
    {
      context.fillStyle = "#555555";
      context.fillRect(0, 0, 200, 200);
      var singleWidth = animationImage.width / numAnimations;
      var singleHeight = animationImage.height;
      var offsetX = singleWidth * index;
      var offsetY = 0;
      context.drawImage( animationImage, offsetX, offsetY, singleWidth,
   singleHeight, 10, 10, singleWidth, singleHeight
                        ); // adjust drawing
      index = index + 1;
      if ( index >= numAnimations )
      {
        index = 0;
      }
    }
  };
}

The code has changed considerably.  First there are three new variables.

    var index = 0;
    var numAnimations = 16;
    var animationImage = null;

The "numAnimations" is a hardwired value that works with the image I provided.  It means there are 16 images to display.  The first image is image 0 (zero).  This is what "index" is for.  It becomes the "pointer" to the current image we're looking at.  "index" changes every frame and will always be between 0 and 16 (it actually will go as high as 15, because we start at 0 and then return to 0).  "animationImage" is a place-holder for the image after it has been loaded.  This value isn't set until the image has been loaded.  This gives us a sure way to tell whether we're reading for drawing the animation or not.

The second set of changes is to the "onload" function.

  animationImage = img;
  window.setInterval( self.drawImage, 50);

The most important of these two is the "window.setInterval()" method.  It is a built in method of the browser that sets up a periodic timer.  I've set its value to "50" which means "wait 50 milliseconds before calling the function you have specified".  There are 20 lots of 50 milliseconds in a second, meaning this drawing will run at 20 frames per second (if your computer/phone can keep up with that).

This is the function that is being called 20 times per second.

  this.drawImage = function()
  {
    if ( animationImage != null )
    {
      context.fillStyle = "#555555";
      context.fillRect(0, 0, 200, 200);
      var singleWidth = animationImage.width / numAnimations;
      var singleHeight = animationImage.height;
      var offsetX = singleWidth * index;
      var offsetY = 0;
      context.drawImage( animationImage, offsetX, offsetY, singleWidth,
   singleHeight, 10, 10, singleWidth, singleHeight
                        ); // adjust drawing
      index = index + 1;
      if ( index >= numAnimations )
      {
        index = 0;
      }
    }
  };

It first checks if the image has been loaded ( animationImage != null ).  I then clears the canvas using "fillRect" with a darkish grey colour (#555555).  When then work out the size of the image by asking the image "how big are you" using "animationImage.width" and "animationImage.height".  We divide the width of the image by "numAnimations" because the image isn't a single image but 16 different images combined together.

Final step - we use "index" to show a different image each time.  We draw part of the image, and add "1" to index.  We then check if index has arrived at the end of the 16 animations, and if it has, we re-set it back to zero.  The output of this program is shown below.



  // get canvas
  var screenCanvas = document.getElementById("gameCanvas");
  var screenContext = screenCanvas.getContext("2d");

  // create new library
  var lib = new ImageLibrary( screenContext );
  lib.loadAndDraw( "img/base.png", 10, 10);


The rest of the program is as before.  We get the canvas, we create the "ImageLibrary" and load the animation graphic.  I've had to move a few things around to make it work.  Don't be put-off by that.  From a pure programming point of view, I've change the "ImageLibrary" too much and hijacked its function.  It no longer is a pure image library - it draws things too.  Here is something you need to get familiar with called "refactoring".  It means that your code has come to a point where it no longer fits its original design and needs to be cleaned up.

The above sample can be downloaded for personal viewing here.

Wednesday, 31 July 2013

A Peaceful Interlude

Before we continue with the drawing - I've been thinking about the structure of this blog.  I think it is important first that we talk about how we write code in java-script.  Java-script is powerful.  Java-script can easily become a big mess.  A lot of programmers don't understand object-oriented programming.

I will try and explain it.  It takes a lot of experience to really, really get it.  So the sooner we start, the better.

First of all, there is a reason why object-oriented programming has supplanted procedural programming.  If you're new to this all, procedural programming and modular programming (excuse the grouping together) is what people used to do.  It is what comes most natural to all of us.

A procedural program typically looks like.

step 1.  do something
step 2.  do something else
step 3.  go to step 5
step 4.  show some output
step 5.  go to step 4

They are instructions, commands for the computer to do.  It comes natural, and kids love it because "they" get to give the commands.  So whats wrong with that?  The problem is one of scale.  The first computers were small compared to modern computers.  People found out fast that as computers grew so did their programs.  The problem with procedural programs is usually called "spaghetti-mess".  The more you need to do, the more instructions you need to add, and at some point, you lose control.

Same happened with my first big Indy game.  I ended up with a situation where whenever I made one small change to one part of the program, another part would break unintentionally.  I had lost control over the code.

Don't despair, there is a solution.  Quite a nice one.  Its called object-oriented programming.  Object-oriented actually means "data-oriented".  But since data already meant so many other things, the inventors decided to name it object-oriented instead.

The main difference between the two styles is that you focus on the data first, not the instructions.  The WHAT, not the HOW.  To do that you need to figure out what it is you're "modelling".  In a game typically, you have objects like "people", "vehicles", "weapons", "buildings" etc.  All these things become their own "objects".  In business applications you might have "invoices", "people", "addresses", and "bank accounts" as your objects.

Java-script is an object-oriented language (as well as a procedural language if you wish to use it that way).  Therein lies the danger.  If you decide not to use it in an object-oriented manner, you run the danger of creating spaghetti-mess.  My advice, be disciplined, and don't be lazy.  It will save you from going insane in the end.

Java-script is simple in what it contains as a language.  Its main data-types (different kinds of items) are:

strings (things within single or double quotes like "Peter" or 'the mouse')
numbers (integers and floating point like 1, 2, 0, -10, 1.5, 3.14159265)
null    (a special word meaning 'no value')
true, false (Boolean logic values)
undefined (a special word meaning 'not defined' / 'unknown')
function (a thing that groups instructions on what to do)
this (a very special word in java-script that refers to an object itself)

Furthermore we have collections called arrays e.g.  [1,2,3,4] is a set of four numbers grouped into an array. Finally we have hash-maps and collections inside curly brackets - but they are for later.

So suppose we wanted to model a space-ship, as we will be doing in this game, we'd first need to think of what defines it.  Here is my first attempt.

// this is a comment - it starts with "//" and anything after it
// is completely ignored by java-script
function Ship()
{
  var x = 0;
  var y = 0;

  this.playerName = "Peter";

  this.draw = function()
  {
    // do some drawing
  };
}

We've defined our first "object" (called a "Class" in the object-oriented world).  The object is called "Ship".  The word "function" in front of it defines the "class" in java-script.  This class has three variables in it called "x", "y", and "playerName".  "x" and "y" are both "initialised" to 0 (the number zero).

this.draw is defined as a "function".  This makes java-script a little confusing in my opinion.  The "this" makes the "draw" visible to things outside the "Ship" class.  Its a java-script convention.  "draw" is a grouping of instructions.  At the moment "draw" is empty - it just contains one comment.

Note as well that every "instruction" or "statement" ends with a semi-colon ( ; ).  This is important to java-script it marks where things end (like a full-stop in an English sentence).

It might help too, in your mind, to replace { with the English word "begin" and } with the English word "end".

Any instruction inside the "Ship" curly brackets "{" and "}" can access the "x" , "y" and "playerName" variables.  However, both "x" and "y" are private (because of the "var" keyword) to "Ship", and the outside world will be unaware of "x" and "y".  "this.playerName" is a different story and can be changed by any other part of the program.

You don't need to write java-script like this, you can write it procedurally like a lot of people do.  However, you get massive advantages writing it as a "class".

The "ship" class becomes a blue-print for all "ships" in the game.  You can have a 100 ships all acting independently using the one class as a template.  Doing that in a procedural language is a lot more difficult and requires a lot more effort.

Furthermore, the "x" and "y" variables inside the "ship" are hidden from outside code.  This is called "encapsulation".  The advantage of that particular little trick is that things outside ship can't just change these values - they're protected.  It makes ship more "robust" and controllable.  It makes the ship a black box too in certain respects.  As you grow as a developer you can make use of this.  You can hide a lot of complexity and make things look a lot simpler.

Is object-oriented programming the end-all of things?  Short answer, "NO".  Object-oriented has weaknesses too.  As programs continue to grow, and as things are getting more "parallel", object-oriented programming too is starting to show cracks.  There are attempts at the moment to mix object-oriented with functional programming (e.g. the Scala language).  Functional programming on its own is very weak and suffers from procedural flaws.  However, functional programming is great for writing code that can be used in parallel.  The Scala language is a very good attempt at mixing object-oriented with functional and shows promise.  Scala's main weakness is that it is a complex language, possibly too complex for mass-adaptation.

The main object-oriented languages of today are (in no particular order) Java, C#, C++, Perl, Python, Scala, Ruby, and Java-script.

It is also important to note that "Java" is not related to "java-script".  They are two completely different languages.

peace-out

NB. Peter's maxim;

          "code should be no more complex than what it needs 
            to express succinctly and clearly."
                                                                                        -- pmgdv