GameMaker: Optimal text shadows

Time to time people come up with strange, slow-ish methods for drawing text with shadows in GameMaker. This is a tutorial about how to achieve the best effect without any of those struggles.

For this tutorial, aside of GameMaker, you'll need two programs:

  • BmFont: A free and open-source bitmap font generator.
  • BmFontToGMX: A tool of mine for converting BMFont' fonts into GMS-compatible formats.

Once both are installed, open BMFont, and configure the font settings as per guide on BmFontToGMX page (or import settings from the file provided in BmFontToGMX.gmx/fonts/fnt_test.bmfc).

Then, you'll want to change font settings for your case.

On "Font Settings", set the font, size, style, and "rasterization options". The later affect how font will be output, and you can tweak this until the font looks as crisp/smooth as you want (accept changes and press V to preview the font).

On "Export Options", you need two things:

  • Tweak "padding" to extend far enough for your desired shadow settings.
    For example, if you want shadow to extend 5 pixels outwards and be shown at offset (1, 2), you'd want to set top=(5-2)=3, left=(5-1)=4, right=(5+1)=6, bottom=(5+2)=7.
    Here I'm doing a 5px shadow at 1,1 offset so the padding is set to left=4,top=4,right=6,bottom=6.
  • Tweak the "Width" and "Height" to be 2N (128, 256, 512, 1024, ...) values that are large enough for you font to fit onto a single "page" when previewing (title showing "1/1").

Once all is done and your font fits into one page on preview, export two copies of it - one is going to be the font' color, and other is going to be the font' shadow. I'm going to name them fnt_test0 (shadow) and fnt_test1 (color) accordingly.

Now, it's time to add the shadow. If you are using Paint.NET, you can use this plugin for "Filters - Object - Drop Shadow". Most other editors have a built-in effect for shadows. In worst case, you can simply apply "guassian blur" for shadow blurring and move the image around for shadow offset.

If you are using the linked PDN plugin, you would change the settings as intended, before finally changing the color to white and unticking "keep original image".

The result should look like following:

Next, you would convert both fonts to GMS fonts by dragging the .fnt files onto BmFontToGMX executable inside the "bin" directory.

Then, you would import both fonts into your GMS projects by dragging .font.gmx files onto the GameMaker: Studio window with the project open.

So now to the actual trick - to draw text with a shadow, you set the font to blurry/shadowy one and color to shadow' color, draw the text once (producing a shadow), then set the font to regular one and color to text' color, and draw it at the same location to produce text on top of shadow.

For example, for the post' demo I made this simple script:

/// test_text_shadow(x, y, text)
var _x = argument0;
var _y = argument1;
var s = argument2;
var c = draw_get_color();
// draw shadow:
draw_set_color(c_black);
draw_set_font(fnt_test0);
draw_text(_x, _y, s);
// draw color:
draw_set_color(c);
draw_set_font(fnt_test1);
draw_text(_x, _y, s);

Allowing to do

draw_set_halign(fa_center);
draw_set_valign(fa_middle);
test_text_shadow(room_width/2, room_height/2, "Hello World!");

To produce the text with a fancy shadow as shown in the beggining of the post:

Additional notes:

  • If you are calculating/applying the shadow' offset programmatically, you can keep even padding on all sides of the font when exporting.
  • The same approach can be used for outlines, glow, and numerous other text effects.
  • You can use Littera (with fnt export format) instead of BMFont, but only with pack methods 6/7.

You can also download the Sample GMZ with the resulting fonts and script from this tutorial if you like.

Related posts:

5 thoughts on “GameMaker: Optimal text shadows

  1. unless i’ve gotten something wrong, it looks like bmfont only converts existing fonts into usable textures. is there any way to create a new [pixel] font from scratch?

    • Indeed, it is for rendering generally-vector fonts.

      If you have a pixel font, you could just add it as a sprite and use font_add_sprite\font_add_sprite_ext to convert it to a font when the game’s running.

  2. Just to be clear, the file that you edit with your image editor is the .png file, and the file you drag an drop into BmFontToGMX.exe is the .fnt file, right?

    After we generate the .gmx file, are we supposed to drop any other file besides the generated .gmx? Trying to open the resource in GMS shows the following error:

    “The original font cannot be found. Editing this font may cause issues when running, do you wish to continue editing?”

    Any ideas?
    Thanks for this awesome tutorial!

    • You do not open the font from GMS after importing it; can replace an existing .font.gmx in a project with a generated one.

      • I tried opening a blank project, adding the generated .gmx file into it and drawing some text. Despite setting the font with draw_set_font, it used Arial instead. It also complained that “null is not a valid integer value” when dropping the .gmx file into the IDE.

        .gmx for reference: https://my.mixtape.moe/ribhpu.gmx

        Am I supposed to import the .png file into the project to? If so, should I add it as an included file or as a sprite?

        Thanks for the help!

Leave a Reply

Your email address will not be published. Required fields are marked *