Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

EVADE!

Welcome to our first in-depth post on the programming of our Arduboy game, EVADE. This is a continuation of a series of posts. So, if you missed our introductory one: Creating EVADE, a Side Scrolling Shooter Game for Arduboy give it a quick read. There are a lot of great tips for getting your Arduboy development environment up and running.

In this post, we’re going to discuss how to use text in your game:

  • Text Basics
  • How to Create a Simple “Typing Effect”
  • How to Create a Custom Font

Basic Text

Out of the box, the Arduboy has no font or ability to display text characters. So, there’s no way to print text on the screen as such. Thankfully, the Arduboy library helps out here by providing a bitmap font where each individual character is represented in code as an array of pixels. The library also provides functions for using this font to display characters in a specific size at a specific location on screen.

For Evade, wherever we wanted to use this “default” font, we called a function that we created to wrap the lower level Arduboy library function calls as needed:

void printText(const char *message, byte x, byte y, byte textSize) {
  arduboy.setCursor(x, y);
  arduboy.setTextSize(textSize);
  arduboy.print(message);
}

This gave us a single function call to handle text display as a one liner throughout the game.

Typewriter Effect

However, as development progressed we realized we wanted to treat some of our text differently. To help with telling the story, we wanted to “print” our text to the screen one character at a time, using a different typeface and with a sound effect as each character appeared on the screen. This required us to design our own bitmap font, convert it to code, and develop a function to display characters one at a time.

As we only wanted to use this effect for “fixed” strings that would always be known at compile time (credits, menu items, introductory text etc), we could store all of these in the Arduboy’s flash memory (PROGMEM). This freed up precious SRAM (an area of memory where runtime variables are stored) but meant that we would have to read the strings that we wanted to display byte by byte (character by character). This suited our desire for a typewriter effect quite well, and is demonstrated in the video below.

 

EVADE Text Effects from Modus Create on Vimeo.

 

If you’re interested in other memory management tricks for Arduboy, be sure to check back for our upcoming post focusing on it.

Custom Font

We created our custom font as a series of bitmaps, one for each letter, numeral, and symbol we wanted to be able to display. Using the same method we employed to encode our bitmap graphics for the game, each letter was then turned into an array in a C header file, containing the height and width of the character plus the hex values for each column of pixels that form it.

For example, here’s “P”:

PROGMEM const unsigned char P[] = {
  5, 6,
  0x3F, 0x01, 0x09, 0x09, 0x0F
};

To make things easy on ourselves, we designed a fixed-width font, eliminating the need to space characters at variable intervals whilst displaying a string of text. We used a 5 pixel gap (the width of each of our characters) as the space character. In order to use the full font more easily in our code, we then created an “alphabet” array, with each array item mapping to a letter:

const unsigned char *alphabet[29];

alphabet[0] = A;
alphabet[1] = B;
alphabet[2] = C;
...

Getting Things Done

This gave us a 29 element array as our font using all 26 uppercase letters plus additional punctuation “: ! and .” . To “type” out characters from the font with a typewriter-like effect, we wrote the following code:

void drawChrs(byte cPos, byte yPos, const uint8_t *letters, unsigned long delayTimer) {
  byte curs = cPos,
       strLen = pgm_read_byte(letters),
       letter;

  for (byte i = 0; i <  strLen; i++) {
    letter = pgm_read_byte(++letters);
    
    // Space chr
    if (letter == 255) {
       curs += 5;
    }
    else {
        drawBitmap(curs,yPos, alphabet[letter], 0);
        curs += pgm_read_byte(alphabet[letter]) + 1;
    }
    
    display();

    if (delayTimer) {
      playTone(100, delayTimer - 10);
      delay(delayTimer);
    }
  }
  ... 

Here, we read a string of letters to display from the program memory starting at the location represented by letters. An example message that this function can display looks like this:

//YOU SURVIVED BUT
PROGMEM const uint8_t playerWon0[] = {
  16, // Number characters
  24, 14, 20, 255, 18, 20, 17, 21, 8, 21, 4, 3, 255, 1, 20, 19
};

The first value tells us how many characters are in the string to display (16), subsequent values are array offsets into our alphabet array. For example alphabet[4] contains the encoded data for the bitmap for the letter E.

Having read the byte at letters[0], we use that as a length byte which tells us how many times to execute the loop that reads characters from the program memory at an incrementing offset from the original start location. In the example above, letters[0] is 16 so the code would then read the next 16 byte sized memory locations and interpret the value contained in each as an offset into the alphabet array (24 = Y, 14 = O and so on). We then use the drawBitmap function to display the encoded bitmap for that letter at the specified x, y location on screen. curs (the x coordinate) is then updated to the position for the next character. If the code sees a character with array index 255, we treat that as a space, and simply add 5 to curs as there is no bitmap image to draw in this case.

Before drawing the next character we first play a tone (we will cover generating sound and music in a separate post), then wait a short while, which creates the typewriter effect. We also call display() which is our function that updates the Arduboy’s screen.

Rather than create every encoded string that we needed for the game by hand, we wrote a small utility in Javascript to do it. This translates an array of source strings (credits) to the format that the drawChrs function expects, using a mapping object to get the array offset into the alphabet array for each character in the string being translated. The utility looks like this:

var map = {
  'A' :  0, 'B' :  1, 'C' :  2, 'D' :   3, 'E' :  4,
  'F' :  5, 'G' :  6, 'H' :  7, 'I' :   8, 'J' :  9,
  'K' : 10, 'L' : 11, 'M' : 12, 'N' :  13, 'O' : 14,
  'P' : 15, 'Q' : 16, 'R' : 17, 'S' :  18, 'T' : 19,
  'U' : 20, 'V' : 21, 'W' : 22, 'X' :  23, 'Y' : 24,
  'Z' : 25, ':' : 26, '.' : 27, ' ' : 255
}

var credits = [
  "CREDITS", "Jay Garcia", "Simon Prickett",
  "Stan Bershadskiy", "Andrew Owen", "Andy Dennis", 
  "Tim Eagan", "Drew Griffith", "JD Jones", 
  "Jon Van Dalen", "Lucas Still", "Matt McCants",
  "Play", "Settings", "Credits"
]

var x = 0,
    endStr = '\n\n';

credits.forEach(function(creditStr, index) {
  creditStr = creditStr.toUpperCase();
  var header = `\n\n//${creditStr}\nPROGMEM const uint8_t credits${index}[] = {\n`,
      outStr = '';
  
  creditStr = creditStr.split('');
    
  creditStr.forEach(function(str) {
    if (outStr.length > 0) {
      outStr += ', '; 
    }
      outStr += map[str];
  });
    
  outStr = creditStr.length +',// Number characters\n' + outStr + '\n};';
  endStr += (header + outStr);  
})

console.log(endStr);

If you’d like to play with this, feel free to try it out on JSFiddle: open up the console in your browser to see the output, which should look like:

//CREDITS
PROGMEM const uint8_t credits0[] = {
7,// Number characters
2, 17, 4, 3, 8, 19, 18
};

//JAY GARCIA
PROGMEM const uint8_t credits1[] = {
10,// Number characters
9, 0, 24, 255, 6, 0, 17, 2, 8, 0
};
...

Game Over

Adding text to your game is one of the fundamental things you will need for your project. Although the Arduboy does come with some basic functions, you may find yourself needing something custom to help give your game that “polished” look.

Making a custom font and adding a simple font effect are two of the easiest things you can do to make your game shine.

Play Evade!

If you’d like to play our game yourself, you’ll need:

  • An Arduboy device ($49) from arduboy.com or Adafruit
  • The Arduino IDE (free), works on Mac, Windows and Linux, required to install our code
  • Our code, which is open source and downloadable from GitHub where you will also find instructions on compiling and installing it using the Arduino IDE

Let Us Know What You Think

We hope you enjoy playing our game as much as we enjoyed writing it. We’d love to see pictures of your high scores, tag us on Instagram or tweet us a photo of your high scores using the hashtag #evadehighscore.

Also, stay tuned for our next in-depth post on the programming of EVADE – Handling User Input.

Posted in Application Development
Share this

Timothy Eagan

Timothy Eagan was a Senior Engineer at Modus Create, and is an accomplished software developer with over 20 years of experience in creating customized business solutions. He can be found in Providence, RI. Tim is also an OIF veteran, former paperboy and part-time comedian.
Follow

Related Posts

  • Evade Annoucement, our first Arduboy Game
    Announcing EVADE, our first Arduboy Game

    EVADE is Modus's very first game for the Arduboy platform. Learn how a highly performing…

  • EVADE featured in Arduboy Magazine Volume 1
    EVADE featured in Arduboy Magazine

    On Friday February 24, 2017, we were excited to learn that our game, EVADE, was…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
IT modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Careers
  • Let’s talk
  • EN
  • FR