DEV Community

Cover image for Make a digital clock in Mini Micro
JoeStrout
JoeStrout

Posted on

Make a digital clock in Mini Micro

Today let's do a little project in Mini Micro that makes an old-school digital clock. This will illustrate pulling apart a sprite sheet, animation by drawing directly to a PixelDisplay (rather than using actual sprites), and the dateTime module to get the current time.

The digits image

Among the built-in images in Mini Micro is /sys/pics/digits.png. It looks like this:

/sys/pics/digits.png

Against a white background, this is pretty confusing, isn't it? If you view it against a black background — for example, by doing view "/sys/pics/digits.png" in Mini Micro — it looks like this:

/sys/pics/digits.png against a black background

OK, now we can see that it has the digits 0 through 9, plus the letters A-F (handy if we wanted to make a hexadecimal display). But why are there two apparently-identical rows of digits? The answer becomes clear if we view against a different background color, neither black nor white. Try this:

gfx.clear color.blue
gfx.drawImage file.loadImage("/sys/pics/digits.png")
gfx.scale = 4
Enter fullscreen mode Exit fullscreen mode

/sys/pics/digits.png, scaled up against a blue background

Aha! Now we can see why there are two rows. The top row has dark segments for the "off" bits of each digit, while in the bottom row, those areas are transparent. Which you use will depend on how you want it to look.

For today's project, we'll use the top row, which will have the subtle but realistic dark segments. This will allow us to simply overdraw a new digit on top of an old one, without having to erase first (and it also looks cool, if the background color is not pure black). We'll also be using only the first ten digits; we will ignore A through F today.

Pulling apart a sprite sheet

Even though we're not actually using sprites today, a big image that contains a bunch of smaller image is still called a "sprite sheet" (or sometimes an "atlas", but I prefer the former term). So let's begin by loading digits.png and then pulling out the ten digits we need, as we would with any other sprite sheet.

Launch Mini Micro, if you haven't already (or use the web version if you're OK with not saving your work at the end). Use the edit command to launch the editor, and type in this code:

digitImage = file.loadImage("/sys/pics/digits.png")
dw = 10; dh = 18  // digit width and height
digits = []
for i in range(0,9)
    digits.push digitImage.getImage(i * dw, dh, dw, dh)
end for
Enter fullscreen mode Exit fullscreen mode

This loads the image into a variable called digitImage, and then prepares a list (digits) with the individual digit images. Each of these is dw pixels wide, and dh pixels tall. We're getting the top row because the second parameter to getImage is dh rather than 0 — remember, coordinates in Mini Micro almost always count from the bottom up. So the bottom row starts at Y = 0, and the top row starts at Y = 18 (or dh).

Run this code, and then test it by entering view digits[4] on the command line. You should see a little digital 4 in the center of the screen.

Some helper functions

Our goal is to draw a time string like "08:22:45". We'll draw this one character at a time. So, let's make two helper functions: one to draw a digit, and one to draw a colon. edit your program again, and add the following.

drawDigit = function(value=0, col=0)
    x = col * dw
    y = 0
    gfx.drawImage digits[value], x, y, dw, dh,
      0, 0, dw, dh, gfx.color
end function

drawColon = function(col=0)
    x = col * dw
    y = 0
    gfx.fillEllipse x + dw/2 - 1, y+5, 2, 2
    gfx.fillEllipse x + dw/2 - 1, y+12, 2, 2
end function
Enter fullscreen mode Exit fullscreen mode

Both of these start by calculating the X and Y position to draw at, given the column position (col) where we want the character to appear. drawDigit calls gfx.drawImage to do its work. If we didn't care about tinting the digits, we could just do:

     gfx.drawImage digits[value], x, y
Enter fullscreen mode Exit fullscreen mode

But we want to support drawing colored digits, so it can look like old-school red or green LED clocks. So we have to supply all nine parameters to [drawImage](https://miniscript.org/wiki/PixelDisplay.drawImage), just to get to the last one, which is the tint color. (MiniScript does not support passing arguments by name, but only by position.)

The drawColon function starts by computing X and Y as well, and then just calls fillEllipse twice, once for each dot of the colon. (Feel free to play around with the size and position of these dots later to make it your own!)

If you run this code, and then do clear to clear the screen, you should be able to enter drawDigit to make a little 0 appear at the bottom of the screen. Also try drawColon 1 to make a colon appear next to it (in column 1).

Drawing the current time

To get the current time, go back to the top of your code and insert:

import "dateTime"
Enter fullscreen mode Exit fullscreen mode

This loads the dateTime module (found in /sys/lib), which gives us access to the current date and time. Then scroll to the bottom of your program, and add this function:

drawTime = function(time)
    if time == null then time = dateTime.now[-8:]
    for i in time.indexes
        if time[i] == ":" then
            drawColon i
        else
            drawDigit time[i].val, i
        end if
    end for
end function
Enter fullscreen mode Exit fullscreen mode

This draws the given time string, or if you don't give it one, it gets the current time as the last 8 digits of dateTime.now. Then it loops over that string, calling the drawColon and drawDigit functions we defined before.

Run this, clear the screen, and then enter drawTime. You should see the current time appear in the lower-left corner. Almost done!

The main program

Finally, with all these helper functions in hand, we are ready to create the main program. edit your code, and add this to the bottom:

clear
//gfx.scale = 8
gfx.scrollX = -150; gfx.scrollY = -350
gfx.color = color.red
while true
    drawTime
    wait
end while
Enter fullscreen mode Exit fullscreen mode

This starts by clearing the screen, and configuring the main PixelDisplay (aka gfx) with a red color, and a scroll position. (Instead of scrolling the display we could have also changed the calculation of X and Y in our draw methods — feel free to experiment!) There is also a commented out line, gfx.scale = 8. If you want to zoom in and have a closer look at your digits, feel free to uncomment that line.

After all that setup, the main loop is simple: it just loops forever, calling drawTime every second.

Animated GIF of clock display

When you run it, you should see a display like the above. (Press Control-C to break out of the program.)

Taking it further

This was a fun little exercise in pulling apart a sprite sheet, making some drawing helpers, and getting the current time. But the same digits and drawing method could be used for lots of other purposes. Some ideas:

• Make a countdown timer for a bomb in a bomb-defusing game
• Make a doomsday clock showing days, hours, and minutes to the next election
• Show game score in a retro digital display
• Make a CPU emulator (like CHIP-8) with digital hexadecimal displays for its internal state

These are just a few ideas. Do you have any others? Questions about anything presented here? Post them in the comments below. Happy coding!

Top comments (0)