Using your own, custom fonts in games and apps is essential to create the right GUI. Sometimes this can be done with a standard font asset drawn natively; however this doesn’t always provide you with enough artistic licence to create what you really need, and in some cases, ie Windows Phone, using native fonts has a huge impact on performance. There is a solution. Bitmap fonts. Although the idea of bitmaps fonts isn’t new, in fact its very old; using them in you Corona projects can typically be a pain. Many years ago, someone wrote bmf.lua, which worked a treat to draw your bitmap fonts onto your scene, however it had a few shortfalls. Corona SDK then released graphics 2.0, which broke bmf.lua completely.
The following article will walk you through my workflow for producing and using bitmap fonts in corona; including a version of bmf.lua that I have updated for the following functions:
- Corona Graphics 2.0 Compatible.
- Corona SDK image map format compatible.
- .fnt definition file compatible.
- Read the drawn width and height at run-time.
- Re-size the font at run-time, without having to destroy and reinitialise.
Creating/Obtaining Bitmap Fonts
Before we get started on the code, we need a bitmap font. Essentially a bitmap font is a sprite sheet that contains all the letters your game may need to render, almost always accompanying the sprite sheet is a definition file (eg, *.fnt) that holds the mapping data for each character.
Fortunately, there are programs out there that will generate these sprite sheets and definition files for us. The program I use in my workflow is bmGlyph (available on the mac app store). I find bmGlyph more than adequate for my needs at a reasonable price. There are other programs out there that you can use, including some that will run on Windows, but fear not, they will (should) all export to the same format.
If you didn’t want to create your own font, that’s fine; you will just need to obtain one. There are many fonts out there with a free to use licence; however you may end up having to generate the definition sheet yourself. I always tend to create my own fonts for this reason, and because i’m a control freak and want to do everything myself!
Here is a font sheet I created using bmGlyph for my PixelSprint game. Once your happy, you need to export this from your designer program to normally a .PNG image and the accompanying definition file. bmGlyph got updated last year so it now natively supports Corona SDK. It can export to a Corona SDK sprite sheet. This is great (and it will work with my bmf.lua module) however I tend to always export using the standard format. This will spit out the definition file as a *.FNT. I do this mainly for portability. If I want to use the font on another project, or I end up porting the project, its always better to go a standard way. Either way you go, it’s covered below.
Coding Bitmap Fonts
Now for the fun part; making them work! I like to dump all my font related files in a separate folder in my Corona project. This isn’t necessary, but for me it keeps it all neat and tidy. My projects will typically contain a folder called fonts, that will have the font sprite sheet, its corresponding .FNT definition file and the bmf.lua module.
Loading The Font
So the first thing we need to do is make sure the lua module is loaded in every script that will reference or use a bitmap font:
local fontLib = require("font.bmf")
Typically I will load all my fonts in the main.lua. This enables your game to pre-load the font texture before your game gets into anything heavy. This will off course take up a bit of texture memory, but if you plan on using the font throughout then it makes a lot of sense to load it once on startup.
To keep all my run-time globals, I have a lua file called data.lua that holds an empty table. I can then call and populate this table throughout the project. This is where I will load the font file into.
So let’s start. The following snippet will load the font texture into memmory ready for use later:
.FNT defintion format:
-- Attach game global file local gameGlobalData = require( "code.data" ) --Set the fonts gameGlobalData.fontDIR = "font/"; gameGlobalData.fontOrigSize = 75; gameGlobalData.font = fontLib.loadfntFont( "titleFont.fnt",gameGlobalData.fontDIR);
Corona SDK Sprite Sheet version:
-- Attach game global file local gameGlobalData = require( "code.data" ) --Set the fonts gameGlobalData.fontDIR = "font/"; gameGlobalData.fontOrigSize = 75; gameGlobalData.font = fontLib.loadluaFont( "titleFont.lua",gameGlobalData.fontDIR);
I’m doing a couple of things here. First I declare my global’s file. I then save the path to my fonts directory for ease of use later, I also save the original font size of the bitmap font. This should be the same size that was used to create the font. This value will be used to scale the font on draw. The last thing that is happening, is to load the actual font texture to memory. Make sure you use the correct function, ie, loadfntFont() if your using a .fnt definition, or loadluaFont() if your using a corona sprite sheet.
Next, we need to draw the text using our font:
.FNT definition format:
local txtTitle = fontLib.newfntString(gameGlobalData.font,"My Text",gameGlobalData.fontOrigSize, 75);
Corona SDK Sprite Sheet version:
local txtTitle = fontLib.<span class="nf">newluaString</span>(gameGlobalData.font,"My Text");
There’s a slight difference here. When we draw a .Fnt format font, we need to specify the original font size (that the font was created to) and the required size of the font; this is so we can scale the font correctly.
Once drawn we can manipulate the text as we would a normal text object, eg:
--change the text txtTitle.text = "New Text String"; --Change the alignment; txtTitle.align = "right"; --Change the font txtTitle.font = <a different font file>; --Change the size txtTitle.size = 10;
These are all self explanatory properties that I really don’t need to go into.
The way the bmf module scales the font for graphics 2.0 means that you can’t just get the objects size properties. This will read back the unscaled values. Not very useful for positioning you text where you need it. So I wrote two small functions that will return the correct width and height of the text item as drawn on the screen:
--The following properties will return the incorrect values local w,h = txtTitle.width, txtTitle.height; --To get the correct values call: local w = txtTitle:getWidth(); local h = txtTitle:getHeight();
So that’s the basics of using my modified bmf.lua module to draw bitmap fonts in Corona, with a little bit more extra control. There are a few other functions in the module, such as paragraphs. The paragraph function can be used to draw justified blocks of texts, which can be very useful.
You can find my bmf.lua in my bitbucket snippets, here. Feel free to use it, and feed back where necessary.