Bitmap Font Support for CreateJS

SNK Metal Slug

I tend to think that fonts are as important in video games as they are for print or for web design. However, monochromatic fonts tend to look absolutely horrendous in games. As a player, I much prefer reading colored font which are both more readable and more consistent with the rest of the game aesthetics.

Oddly enough, Bitmap Fonts are only rarely supported out of the box in most game libraries, and CreateJS is no exception. I'm not sure if this is because the implementation of such a feature is considered trivial or for any other (valid) reason.

Bottom line is, if you want to have beautiful bitmap fonts in your game, you'll have to do it all by yourself. I faced this issue recently for a demo I'm working on, and I thought I could share what I came up with. Keep in mind that it's still a work in progress -- which I may publish later in my CreateJS utils github repo.

But first here's the result:

Font format

As you can guess, there are various bitmap font formats available out there, but, since all characters will eventually be treated as an image blitted on screen, we can just stick with spritesheets,

alt text

In this example, I used one of the font spritesheet provided with the royalty free bitmap fonts FontPack available at SpicyPixel.net.

In this case, this is what my font sheet looks like: a simple PNG file in which each glyph is drawn next to the other.

alt text

Since CreateJS comes with a SpriteSheetUtils class which can extract extract frames from such sheets, it's fairly easy to create a basic implementation for a BitmapFont class which will eventually be used by a BitmapText object

The BitmapFont class

The BitmapFont class main job is to be able to return a bitmap from a given character string.

To do so, it must accept a spritesheet and a character map as a parameter.

The spritesheet object is a typical EaselJS SpriteSheetinstance. Note that, in this case, all character have the same size, which allows us to use a simplified syntax.

var fontSheet = new createjs.SpriteSheet(
{
    images: [spritesheetPath], 
    frames:{width:16, height:16, count:59}

});

lib.fontSheet = fontSheet;

A character map is simply a string representing all glyphs drawn in the spritesheet, in order to map a given char index to a bitmap coordinate. For instance, it could look like this:

var charMap = "abcdefghijklmnopqrstuvwxyz1234567890";

So our constructor will look like this:

function BitmapFont(pSheet, pCharMap) {
    this.charMap = pCharMap;
    this.sheet = pSheet;
    this.charWidth = pSheet._frameWidth;
}

Now all we have to do is use the SpriteSheetUtils class to extract the bitmap corresponding to a char.

BitmapFont.prototype.getCharImg = function (pChar) {
    var index = this.charMap.indexOf(pChar);        
    return createjs.SpriteSheetUtils.extractFrame(this.sheet, index);
};

The BitmapText class

Now, onto the class which will display the text. First, we have to choose a DisplayObject class to inherent from in order to be able to draw something on the screen. I chose to inherit from Container and simply treat each character as a separate Bitmap object.

I'm not sure this is the best way to go, but at least it has the advantage of keeping control on individual characters if needed (since it is not "flattened"), and my understanding is that EaselJS is capable of caching its display objects, which should hopefully limit the impact in terms of performance.

So, the constructor takes our BitmapFont instance as a parameter and an optional text string.

function BitmapText(pBFont, pText) {
    this.font = pBFont;
    this.setText(pText);
}
BitmapText.prototype = new createjs.Container();

On a side note, I'm not a fan of such implementation of inheritence, but Object.create() gave me results, so I decided to stick with the way createJS does it for now. I hope to investigate this further later.

The heart of this very simple class is of course in its setText()method which actually draws the characters bitmaps.

BitmapText.prototype.setText = function (pText) {
    this.removeAllChildren();
    var i;
    var count = pText.length;
    for (i = 0; i < count ; i++) {
        var char = pText.charAt(i);
        var chatImg = this.font.getCharImg(char);
        var bmp = new createjs.Bitmap(chatImg);
        this.addChild(bmp);
        bmp.x = i * this.font.charWidth;
    }        
};

As you can see, this is a single line text, which is often, but not always, enough for most basic game needs.

So again, this is very experimental and probably needs a lot more work before being production ready. But hopefully this may help some of you get started with bitmap fonts in createJS!