Learning Go by examples: part 5 - Create a Game Boy Advance (GBA) game in Go
Tags: go, beginners, game, tutorial
Published: 2021-08-11 05:58:45

---
title: Learning Go by examples: part 5 - Create a Game Boy Advance (GBA) game in Go
published: true
description: Serie of article in order to learn Golang language by concrete applications as example
series: Learning Go by examples
tags: Golang, beginners, game, tutorial
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvuxkc7wvrm5r1951mqa.png
---

After created an [HTTP REST API server](https://dev.to/aurelievache/learning-go-by-examples-part-2-create-an-http-rest-api-server-in-go-1cdm), our [first CLI (Command Line Interface) application in Go](https://dev.to/aurelievache/learning-go-by-examples-part-3-create-a-cli-app-in-go-1h43) and our [Bot for Discord](https://dev.to/aurelievache/learning-go-by-examples-part-4-create-a-bot-for-discord-in-go-43cf), what can we do now?

What about coding your own Game Boy Advance game?!

## Why a Game Boy Advance app/game?

As you may have already noticed in my ["Understanding Kubernetes in a visual way"](https://www.youtube.com/c/AurelieVache) video serie on YouTube (in the background) I am a retrogamer fan.

![Understanding Kubernetes in a visual wa](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oslecltinyyompk9jctc.png)

I am a Developer (and Ops) for more than 15 years, I love retrogaming and I love to play with Go.

But we can only code a game for GBA in C, isn't it? Well, it's not perfectly true, with **TinyGo** we can code in Go and build for a lot of microcontrollers, WebAssembly... and Game Boy Advance (GBA) machine! Go is really cool, we can do many things with this language!

And, for fun!

So what about creating a game for one of my favorite portable console?

## Game Boy Advance

![Game Boy Advance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yqug66ekx7ldkd6lbil.png)

The Game Boy Advance (GBA) was one of the handheld video games console produced by Nintendo released in 2001. In this console you can find a 240x160 (3:2 aspect ratio) 15-bit color LCD display, a multidirectional pad ([D-pad](https://en.wikipedia.org/wiki/D-pad)), "A", "B", "L", "R", "START" & "SELECT" buttons for actions.

The GBA CPU is based on a 32-bit ARM7TDMI core with embedded memory.

One of the strength of this console is to be backward compatible with Game Boy and Game Boy Color games.

GBA games are loaded in a game cartridge:

![GBA game](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3nclkp61yqyk78od13m9.png)

If you are interested about the technical specification of this console, you can find a lot of useful information in this [article](https://www.reinterpretcast.com/writing-a-game-boy-advance-game).

## Initialization

We created our [Git repository](https://github.com/scraly/learning-go-by-examples) in the previous article, so now we just have to retrieve it locally:

```
$ git clone https://github.com/scraly/learning-go-by-examples.git
$ cd learning-go-by-examples
```

We will create a folder `go-gopher-gba` for our CLI application and go into it:

```
$ mkdir go-gopher-gba
$ cd go-gopher-gba
```

Now, we have to initialize Go modules (dependency management):

```
$ go mod init github.com/scraly/learning-go-by-examples/go-gopher-gba
go: creating new go.mod: module github.com/scraly/learning-go-by-examples/go-gopher-gba
```

This will create a `go.mod` file like this:

```golang
module github.com/scraly/learning-go-by-examples/go-gopher-gba

go 1.16
```

Before to start our super Game Boy Advance (GBA) application, as good practice, we will create a simple code organization.

Create the following folders organization:

```
.
├── README.md
├── bin
├── go.mod
```

That's it? Yes, the rest of our code organization will be created shortly ;-).

## TinyGo

![TinyGo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qf7fbx866zfcb6zuaeiw.png)
 
[TinyGo](https://tinygo.org/) is a Go compiler for embedded systems and to the modern web.
You can compile and run TinyGo programs on a lot of microcontroller boards such as the BBC micro:bit, the Arduino Uno, the Nintendo Switch and the [Game Boy Advance](
https://tinygo.org/docs/reference/microcontrollers/gameboy-advance/) ;-).

TinyGo can also produce WebAssembly (WASM) code which is very compact in size. You can compile programs for web browsers, as well as for server and edge computing environments that support the WebAssembly System Interface (WASI) family of interfaces.

When I discovered TinyGo in the begining of 2020 I was just: WoW, it's awesome!!!!

First, we will [install TinyGo](https://tinygo.org/getting-started/install/). If you have a MacOS:

```
$ brew tap tinygo-org/tools
$ brew install tinygo
```

Check TinyGo is correctly installed:

```
$ tinygo version
tinygo version 0.19.0 darwin/amd64 (using go version go1.16.5 and LLVM version 11.0.0)
```

## Let's create our app!

![Gopher Park](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgot0q55htadv3kd8jsr.png)

What do we want?

This simple Game Boy Advance app/game should:
* Display a screen with "Gopher" text and "Press START button"
* Display two gophers
* When you press **START** button: your Gopher player just appear
* With multidirectional arrows you can move your Gopher at left, right, top or bottom
* When you press **A** button: your Gopher jump :-D 
* When you press **SELECT** button, you go back to "Start" screen

It seems to be cool for a first start, let's do it!

OK, so let's start!

As we can see in the [TinyGo website](https://tinygo.org/docs/reference/microcontrollers/gameboy-advance/), the Game Boy Advance is a handheld videogame platform based on the **ARM7TDMI** microcontroller. It's a useful information and we can find in this page the link to the `machine` package for GBA... and that's all, we will talk about the lack of real documentation later :-).

Nevertheless, a lack of documentation and up-to-date working example will not stop us. So I will show you the code and explain to you step by step.

As we will display text messages in our app, we will create a `fonts` folder and put inside the fonts in Go that we want to use:

```
fonts
├── freesansbold24pt7b.go
└── gophers58pt.go
```

You can find theses fonts in my [GitHub repository](https://github.com/scraly/learning-go-by-examples/tree/main/go-gopher-gba).

After this prerequisite, we will create the code of our app. In order to do this, we will create a `gopher.go` file and copy/paste the following code into it.

First, Go code is organized into packages. So, we initialize the package, called main, and all dependencies/librairies we need to import and use in our main file:

```golang
package main

import (
	"image/color"
	"machine"
	"runtime/interrupt"
	"runtime/volatile"
	"unsafe"

	"github.com/scraly/learning-go-by-examples/go-gopher-gba/fonts"
	"tinygo.org/x/tinydraw"
	"tinygo.org/x/tinyfont"
)
```

Then, we initialize a list of variables: 

```golang
var (
	//KeyCodes / Buttons
	keyDOWN      = uint16(895)
	keyUP        = uint16(959)
	keyLEFT      = uint16(991)
	keyRIGHT     = uint16(1007)
	keyLSHOULDER = uint16(511)
	keyRSHOULDER = uint16(767)
	keyA         = uint16(1022)
	keyB         = uint16(1021)
	keySTART     = uint16(1015)
	keySELECT    = uint16(1019)

	// Register display
	regDISPSTAT = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000004)))

	// Register keypad
	regKEYPAD = (*volatile.Register16)(unsafe.Pointer(uintptr(0x04000130)))

	// Display from machine
	display = machine.Display

	// Screen resolution
	screenWidth, screenHeight = display.Size()

	// Colors
	black = color.RGBA{}
	white = color.RGBA{255, 255, 255, 255}
	green = color.RGBA{0, 255, 0, 255}
	red   = color.RGBA{255, 0, 0, 255}

	// Google colors
	gBlue   = color.RGBA{66, 163, 244, 255}
	gRed    = color.RGBA{219, 68, 55, 255}
	gYellow = color.RGBA{244, 160, 0, 255}
	gGreen  = color.RGBA{15, 157, 88, 255}

	// Coordinates
	x int16 = 100 //TODO: horizontally center
	y int16 = 100 //TODO: vertically center
)
```

As you can see, we define several variables that we will use in our code, in order to avoid a code complex to read and in order to not copy/paste RGB colors code in several pieces of code.

Then, we define our `main()` function that:
* configure and register the display (the console's screen)
* call the function that will draw our texts and Gophers
* plug an `update()` function in an interrupt signal
* define an infinite loop to avoid exiting the application

```golang
func main() {
	// Set up the display
	display.Configure()

	// Register display status
	regDISPSTAT.SetBits(1<<3 | 1<<4)

	// Display Gopher text message and draw our Gophers
	drawGophers()

	// Creates an interrupt that will call the "update" fonction below, hardware way to display things on the screen
	interrupt.New(machine.IRQ_VBLANK, update).Enable()

	// Infinite loop to avoid exiting the application
	for {
	}
}
```

Let's implement our `drawGophers()` function:

```golang
func drawGophers() {

	// Display a textual message "Gopher" with Google colors
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 36, 60, 'G', gBlue)
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 71, 60, 'o', gRed)
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 98, 60, 'p', gYellow)
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 126, 60, 'h', gGreen)
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 154, 60, 'e', gBlue)
	tinyfont.DrawChar(display, &fonts.Bold24pt7b, 180, 60, 'r', gRed)

	// Display a "press START button" message - center
	tinyfont.WriteLine(display, &tinyfont.TomThumb, 85, 90, "Press START button", white)

	// Display two gophers
	tinyfont.DrawChar(display, &fonts.Regular58pt, 5, 140, 'B', green)
	tinyfont.DrawChar(display, &fonts.Regular58pt, 195, 140, 'X', red)
}
```

As I want to display text messages, I used **TinyFont** package with fonts we put in `fonts` folder... and I used it to display our Gophers too!
For the moment we can't display an image and load a sprite so I had to find a way to display our cute Gophers ;-).

Then, we need to implement our `update()` function:

```golang
func update(interrupt.Interrupt) {

	// Read uint16 from register regKEYPAD that represents the state of current buttons pressed
	// and compares it against the defined values for each button on the Gameboy Advance
	switch keyValue := regKEYPAD.Get(); keyValue {
	// Start the "game"
	case keySTART:
		// Clear display
		clearScreen()
		// Display gopher
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	// Go back to Menu
	case keySELECT:
		clearScreen()
		drawGophers()
	// Gopher go to the right
	case keyRIGHT:
		// Clear display
		clearScreen()
		x = x + 10
		// display gopher at right
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	// Gopher go to the left
	case keyLEFT:
		// Clear display
		clearScreen()
		x = x - 10
		// display gopher at right
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	// Gopher go to the down
	case keyDOWN:
		// Clear display
		clearScreen()
		y = y + 10
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	// Gopher go to the up
	case keyUP:
		// Clear display
		clearScreen()
		y = y - 10
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	// Gopher jump
	case keyA:
		// Clear display
		clearScreen()
		// Display the gopher up
		y = y - 20
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
		// Clear the display
		clearScreen()
		// Display the gopher down
		y = y + 20
		tinyfont.DrawChar(display, &fonts.Regular58pt, x, y, 'B', green)
	}
}
```

Hum... Aurélie, is it possible to explain to us what you have done in this function?

In fact, previously we registered to KeyPad so everytime a button and/or a multidirectional arrow is pressed, the `update()` function is called so into it. Then I create a `switch case` that allow me to execute code depending on the button pressed.

And, finally, I don't find any existing method that clear screen, or that fill a color in the entire screen, GBA machine TinyGo implementation don't have the needed function. So I use a trick: I create a small function that draw a rectangle with the full size of the screen in black (as black is the background color of the display screen).

```golang
func clearScreen() {
	tinydraw.FilledRectangle(
		display,
		int16(0), int16(0),
		screenWidth, screenHeight,
		black,
	)
}
```

## Install needed dependencies

We use external packages/dependencies in `gopher.go` file, so we have to install them:

```
$ go get tinygo.org/x/tinydraw
$ go get tinygo.org/x/tinyfont
```

## TinyFont

TinyGo is not a standalone way to build Go app for microcontrollers and lightweight hardware but the main GitHub repository contains also several useful tools like [TinyFont](https://github.com/tinygo-org/tinyfont).

![TinyFont](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mq0cnpwq9famofen5azh.png)
 
TinyFont is afont/text package for TinyGo displays (based on Adafruit's GFX library).

TinyFont repository contains several [fonts](https://github.com/tinygo-org/tinyfont) you can use in your apps and import like this:

```golang
import (
	"tinygo.org/x/tinyfont/freemono"
	"tinygo.org/x/tinyfont/freesans"
	"tinygo.org/x/tinyfont/freeserif"
)
```

If you want to use your personal fonts, you can convert it from BDF format to "TinyGo" compatible format with [tinyfontgen](https://github.com/tinygo-org/tinyfont/tree/release/cmd/tinyfontgen) tool.

Usage example:
```
$ tinyfontgen --package my-font --fontname MyFontRegular12pt MyFont-Regular-12pt.bdf --output MyFont-Regular-12pt.go --all
```

## TinyDraw

[TinyDraw](https://github.com/tinygo-org/tinydraw) is an useful tool that allow you to draw geometrics figures (based on  Adafruit GFX library).

![TinyDraw](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgutmx73jinoe24yngd5.png)
 
Thanks to TinyDraw you can easily draw geometrics forms:

```golang
	white = color.RGBA{255, 255, 255, 255}
	green = color.RGBA{0, 255, 0, 255}
	red   = color.RGBA{255, 0, 0, 255}

	// ...

	tinydraw.Line(&display, 100, 100, 40, 100, red)

	tinydraw.Rectangle(&display, 30, 106, 120, 20, white)
	tinydraw.FilledRectangle(&display, 34, 110, 112, 12, green)

	tinydraw.Circle(&display, 120, 30, 20, white)
	tinydraw.FilledCircle(&display, 120, 30, 16, red)

	tinydraw.Triangle(&display, 120, 102, 100, 80, 152, 46, white)
	tinydraw.FilledTriangle(&display, 120, 98, 104, 80, 144, 54, green)
```

## Gopher font

As we can't display images and sprites for the moment in GBA hardware with TinyFont, I needed to find a way to display our favorite Gophers, the trick is to use an awesome existing [Gopher font](http://2ttf.com/HCQ3PvcaQ4U) created by [Jaana Dogan (@rakyll)](https://twitter.com/rakyll), thanks!!

![Gopher font](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e03a21krkk59klhrxnx6.png)

And you can even play with this font in the [2ttf playground](http://2ttf.com/typetest.php?id=HCQ3PvcaQ4U).

![2ttf playground](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31cx5b0ikvn6iuzq1wh9.png)

## GBA emulator

It's time to test our app, but if you don't have a real Game Boy Advance (GBA) retro portable videogame console, it's not a problem because several emulator exists.

TinyGo recommend, and use, [mGBA](https://mgba.io), a Game Boy Advance software emulator so we will install it to test our apps.

First, [download mGBA](https://mgba.io/downloads.html), untar it and then copy it in your PATH:

```
$ cp ./bin/mgba /usr/local/bin/mgba
```

As usual, check the executable is working correctly:

```
$ mgba --version
mgba 0.9.2 (f6d5f51d231053cc8a1778b7a139096d2bcf7324)
```

Cool!

You can run mGBA with the command line tool `mgba`, (located in `bin` folder), but you have also the possibility to run the visual application (located in `Applications`):

![mGBA app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0x82o8h2ivinw17isvc0.png)
 
By default, controls are mapped to the keyboard like this:
```
    A: X
    B: Z
    L: A
    R: S
    Start: Enter
    Select: Backspace
```

## Test it!

It's time to test our little game!

```
$ tinygo run -target=gameboy-advance gopher.go
tinygo:ld.lld: warning: lld uses blx instruction, no object with architecture supporting feature detected
```

This command will compile the code, execute mGBA emulator and load your app.

![Start menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ltxyl6lato4jckwwpl9.png)
 
Awesome! 

Now, press the "**START**" button (the **ENTER** touch in your keyboard), you should see a green Gopher appear at the center of the screen.

![green Gopher](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7pchaux6yorgjjiqofe.png)
 
With multidirectional arrows you can move the Gopher at left, right, bottom and top.

And if you press the "**A**" button (X in the keyboard by default), Gopher should do a jump :-).

You can watch the following video with the demo:
 
{% youtube V-VnFMijaI8 %}

## Build it!

Your application is ready, you can build it.
For that, like the previous articles, we will use [Taskfile](https://taskfile.dev/#/) in order to automate our common tasks.

So, for this app too, I created a `Taskfile.yml` file with this content:

```yaml
version: "3"
    
tasks:

    run: 
        desc: Run the app
        cmds:
        - GOFLAGS=-mod=mod tinygo run -target=gameboy-advance gopher.go

    build:
        desc: Build the GBA app
        cmds:
        - GOFLAGS=-mod=mod tinygo build -size short -o bin/gopher.gba -target=gameboy-advance gopher.go

    build-mgba:
        desc: Build the GBA app for mGBA
        cmds:
        - GOFLAGS=-mod=mod tinygo build -size short -o bin/gopher.elf -target=gameboy-advance gopher.go
        - mv bin/gopher.elf bin/gopher.gba

    mgba:
        desc: Load the game
        cmds:
        - mgba bin/gopher.gba
```

Thanks to this, we can build our app easily:

```
$ task build
task: [build] GOFLAGS=-mod=mod tinygo build -size short -o bin/gopher.gba -target=gameboy-advance gopher.go
tinygo:ld.lld: warning: lld uses blx instruction, no object with architecture supporting feature detected
   code    data     bss |   flash     ram
   4128   28536    3116 |   32664   31652

$ ll bin/gopher.gba
-rwxr-xr-x  1 aurelievache  staff   229K  7 aoû 18:53 bin/gopher.gba
```

## Tips and tricks

```yaml
    build-mgba:
        desc: Build the GBA app for mGBA
        cmds:
        - GOFLAGS=-mod=mod tinygo build -size short -o bin/gopher.elf -target=gameboy-advance gopher.go
        - mv bin/gopher.elf bin/gopher.gba
```

Wait a minute, what is this strange tricks in the `build-mgba` task?

Currently, there is a bug with mGBA: `tinygo build` command don't build a correct GBA ROM that mGBA can load and run correctly.

```
$ tinygo build -target=gameboy-advance -o bin/gba-display.gba gba-display.go 
tinygo:ld.lld: warning: lld uses blx instruction, no object with architecture supporting feature detected

$ file bin/gba-display.gba
bin/gba-display.gba: data
```

When you run it through mGBA emulator, the game crash:
```
$ mgba bin/gba-display.gba
The game crashed!
```

![Game crashed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gw9z6ijozmzhqq5z0op8.png)
 
So after having a discussion with TinyGo contributors, if I build to an `.elf` file and then copy it to a `.gba` file, it should working... and it's true.

So if you have the same bug like me, you know the trick ;-).

If you want to load it through **VisualBoyAdvance** app, another GBA emulator, you don't need the trick, the following command will run a working format:

```
$ tinygo build -size short -o bin/gopher.gba -target=gameboy-advance gopher.go
```

## Test on a real handset!

I don't like emulator, I prefer "physical" retrogaming console so I wanted to test with a real handset. I've got the chance to have one GBA and one GBA SP console in working condition, but how can I transfer my `gopher.gba` file into my console?

In order to do that you can use a "linker", like the ["EZ Flash Omega"](https://www.ezflash.cn/product/omega/) I bought. It allow you to copy your `.gba` files into a microSD card you put in this particular GBA cartridge.

It's time to test ... crossed fingers!

![Gopher on GBA SP](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8klywi8x6yaepgam5nij.jpg)

The little Gopher app is working in the Game Boy Advance SP! :-)

## Easy! Isn't it?

Well ... If I tell you it was very easy to create this game (this simple app with cute Gophers), it's a lie ^^.

TinyGo is a really good tool but one of the pain point is the documentation and concrete up-to-date and working examples :-(.

I will be totally honest to you. I knew & know nothing about microcontrollers, electronics and hardware so without concrete examples, without tutorials, without a good documentation, it was not easy to create this app but I'm very happy to created it and I hope with this article will motivate you to test TinyGo in your side :-).

If you want to test TinyGo, you can play with it through the existing [playground](https://play.tinygo.org/).

Moreover, with [TitiMoby](https://twitter.com/titimoby), we created a fresh new GitLab repository [tinygo-examples](https://gitlab.com/TitiMoby/tinygo-examples) containing several working and concrete examples in TinyGo with Adafruit PyGamer, GBA... and soon WebAssembly.
Don't hesitate to add your own TinyGo examples! :-)

![TinyGo examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3lz7u4g4iphll9tk6j6.png)
 
## Conclusion

As you have seen in this article and previous articles, it's possible to create applications in Go: CLI, REST API, Bot for Discord... and also apps for microcontrollers and retro consoles! :-)

All the code of our little Gopher GBA app in Go is available in: [https://github.com/scraly/learning-go-by-examples/tree/main/go-gopher-gba](https://github.com/scraly/learning-go-by-examples/tree/main/go-gopher-gba)

In the following articles we will create others kind/types of applications in Go.

Hope you'll like it.