← Back to all projects

LEARN GAMEBOY DEVELOPMENT

Learn Game Boy Development from Scratch (with C and Assembly)

Goal: To understand the fundamentals of retro game development by building a complete, playable Game Boy game from the ground up, using both C (GBDK) for rapid development and Assembly for direct hardware control.


Why Learn Game Boy Development?

In an era of multi-gigabyte games and massive game engines, developing for the Game Boy is a refreshing and deeply educational experience. There is no operating system, no complex frameworks—just you, your code, and the bare metal hardware. It’s a programming challenge that teaches you efficiency, resource management, and the fundamental principles of how a computer turns code into a playable experience.

By learning both C and Assembly, you get the best of both worlds: the ability to quickly prototype ideas in C, and the power to drop down to assembly for performance-critical code and ultimate hardware control.

After completing these projects, you will:

  • Understand the 8-bit hardware architecture of the Game Boy.
  • Be proficient in low-level C and Game Boy assembly programming.
  • Know how to create and manipulate graphics using a tile-based rendering system.
  • Handle user input by reading directly from hardware registers.
  • Manage severe memory and CPU constraints.
  • Have a playable .gb ROM file of a game you built yourself.

Core Concept Analysis: The Game Boy’s Hardware

To program the Game Boy, you must understand its hardware. All “features” are just direct manipulations of its memory and registers.

1. The System Architecture

The Game Boy is a simple 8-bit system. The CPU can access a 64KB (65,536 bytes) address space. This space isn’t all RAM; it’s a map to every component in the system.

The Game Boy Memory Map:

0xFFFF ┌──────────────────┐ Interrupt Enable Register
       │       HRAM       │ High-speed RAM (127 bytes)
0xFF80 ├──────────────────┤
       │   I/O REGISTERS  │ Controls Graphics, Sound, Input
0xFF00 ├──────────────────┤
       │       ...        │ Unusable Space
0xFEA0 ├──────────────────┤
       │ OAM (Sprite RAM) │ Stores attributes for 40 sprites (160 bytes)
0xFE00 ├──────────────────┤
       │       ...        │ Echo RAM (Don't use)
0xE000 ├──────────────────┤
       │   WRAM (Work RAM)│ General purpose RAM (8 KB)
0xC000 ├──────────────────┤
       │ Cartridge RAM    │ For save games (if available)
0xA000 ├──────────────────┤
       │  VRAM (Video RAM)│ Tile and Map data for graphics (8 KB)
0x8000 ├──────────────────┤
       │                  │
       │   Cartridge ROM  │ Your game's code and data (32KB+)
       │                  │
0x0000 └──────────────────┘

2. The CPU and Assembly Language

The brain is a Sharp LR35902, an 8-bit CPU similar to the Z80. It has a small set of registers you’ll use constantly in assembly.

  • 8-bit Registers: A (The Accumulator, for most math), F (Flag register), B, C, D, E, H, L.
  • 16-bit Register Pairs: The 8-bit registers can be paired up to hold 16-bit values, mostly for memory addresses: AF, BC, DE, HL. The HL register pair is the most important, often used as a pointer to memory.
  • 16-bit Special Registers: SP (Stack Pointer), PC (Program Counter).

Key Assembly Instructions:

  • ld r1, r2 (LoaD): The workhorse instruction. It copies data.
    • ld a, 5 -> Put the number 5 into register A.
    • ld hl, 0x8000 -> Put the address of VRAM into the HL register pair.
    • ld [hl], a -> Copy the byte from register A into the memory location pointed to by HL. This is how you write to memory.
    • ld a, [hl] -> Copy the byte from the memory location pointed to by HL into register A. This is how you read from memory.
  • add a, b: Adds register B to register A, stores the result in A.
  • inc r / dec r: Increment or decrement a register.
  • jp 0x0150: Unconditionally jump execution to address 0x0150.
  • call MyFunction: call a subroutine.
  • ret: return from a subroutine.

3. The PPU (Picture Processing Unit) - The Graphics System

The Game Boy does not have a modern “framebuffer.” You cannot draw individual pixels wherever you want. The PPU is a tile-based renderer.

  • Tiles: The basic graphical unit is an 8x8 pixel tile. Each pixel can be one of four shades of gray. This tile data is stored in VRAM.
  • Background Layer: A 32x32 grid of tiles (256x256 pixels) that makes up your game world. You can scroll this layer around to create levels. A “map” in VRAM tells the PPU which tile to draw in each grid position.
  • Window Layer: An optional, non-scrolling layer drawn on top of the background. Perfect for a status bar or HUD.
  • Sprites (or OBJs): Up to 40 movable 8x8 or 8x16 objects that are drawn on top of the background and window layers. Their attributes (position, tile number, flags) are stored in a special, fast memory called OAM. The PPU has a limit of drawing only 10 sprites per scanline.

4. The Game Loop: V-Blank Synchronization

Your game’s main() function will be an infinite loop: while(1). However, you cannot update graphics whenever you want. Modifying VRAM or OAM while the PPU is drawing to the screen will cause graphical glitches. The solution is to wait for the Vertical Blank (V-Blank) interrupt, which is a safe window to update graphics.

Your main game loop will always look like this:

while(1) {
    // Handle user input
    // Update game logic
    
    // Wait for the V-Blank period to begin
    wait_vbl_done();

    // Now it's safe to update graphics
}

5. The Tools

  • GBDK-2020: The Game Boy Development Kit. This provides a C compiler (SDCC) and libraries (<gb/gb.h>) that give you C functions to interact with the hardware.
  • RGBDS: The Rednex Game Boy Development System. This is the standard assembler and linker for writing pure assembly language programs.
  • Emulator: Emulicious and BGB are highly recommended as they have excellent debuggers that let you inspect memory, registers, and step through code (both C and assembly).
  • Graphics Tools: GBTD (Tile Designer) and GBMB (Map Builder).

Project List

These projects will guide you from a blank C file to a complete, playable Game Boy game, with opportunities to dive into assembly along the way.


Project 1: “Hello, World!” in C

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: C (with GBDK-2020)
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Retro Development / Toolchain Setup
  • Software or Tool: GBDK-2020, Emulicious/BGB Emulator
  • Main Book: “Game Boy Coding Adventure” by Maximilien Dagois

What you’ll build: A .gb ROM that, when run, displays the text “Hello, World!” on the Game Boy screen.

Why it teaches Game Boy development: This project’s main challenge is setting up the development environment. You’ll learn how to compile C code into a ROM file and see the most basic use of the Game Boy’s background layer.

Core challenges you’ll face:

  • Installing GBDK-2020 → maps to setting up the compiler, libraries, and system environment variables
  • Writing a minimal C program → maps to using #include <gb/gb.h> and a main() function
  • Compiling with lcc → maps to using the command line to turn your .c file into a .gb ROM
  • Displaying text → maps to using GBDK’s printf() or set_bkg_tiles() to write to the background map in VRAM

Difficulty: Beginner (but the setup can be tricky) Time estimate: Weekend Prerequisites: Basic C programming knowledge and comfort with the command line.

Real world outcome: A hello.gb file. Dragging this file into an emulator will show the Game Boy boot logo, followed by a screen with your text.

Assembly Challenge: The GBDK function DISPLAY_ON is just a wrapper for *(UBYTE*)0xFF40 = 0x91;. This C code writes the value 0x91 to the LCD Control register at address 0xFF40. The assembly for this is ld a, 0x91 followed by ld [0xFF40], a. Try using GBDK’s inline assembly (__asm ... __endasm;) to replace the DISPLAY_ON call with these two assembly instructions.

Learning milestones:

  1. You can compile a .c file into a working .gb ROM → Your toolchain is set up correctly.
  2. The text “Hello, World!” appears → You understand how to write tile data to the background map.
  3. You successfully replace a C function with inline assembly → You have taken your first step into bare-metal programming.

Project 2: Handling Input in C

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: C (with GBDK-2020)
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Low-level I/O / Game Loop
  • Software or Tool: GBDK-2020
  • Main Book: N/A, rely on GBDK documentation and tutorials.

What you’ll build: A simple ROM where a single tile can be moved around the screen using the D-pad.

Why it teaches Game Boy development: This project introduces the main game loop and input handling. You’ll learn how to read the state of the buttons and how to use the V-Blank period to safely update graphics.

Assembly Challenge: The joypad() function is a C abstraction. The real hardware operation involves writing to the joypad register (0xFF00) to select which buttons you want to read (D-pad or Action buttons), and then reading back from that same address. Try to write a small assembly function that does this and returns the button state, then call it from your C code.

Learning milestones:

  1. A character appears on screen → You can place a tile on the background.
  2. The character moves when you press the D-pad → You are successfully reading and responding to input.
  3. The movement is smooth and doesn’t flicker → You are correctly using wait_vbl_done() to sync graphics updates.

Project 3: Sprites in C

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: C (with GBDK-2020)
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Graphics Hardware / VRAM vs OAM
  • Software or Tool: GBDK-2020
  • Main Book: Pan Docs - The ultimate Game Boy hardware reference.

What you’ll build: A program that displays a movable hardware sprite on top of the background. The sprite will move smoothly pixel by pixel.

Why it teaches Game Boy development: This teaches you about OAM (Object Attribute Memory) and how to manage the 40 available hardware sprites, which is how all characters and objects in Game Boy games are animated.

Core challenges you’ll face:

  • Loading sprite tile data → maps to using set_sprite_data() to copy your sprite’s pixel data into VRAM
  • Assigning a tile to a sprite → maps to using set_sprite_tile() to tell hardware sprite #0 which tile from VRAM it should use
  • Positioning a sprite → maps to using move_sprite() to set the X/Y pixel coordinates of your sprite in OAM

Learning milestones:

  1. A sprite appears on screen → You have successfully loaded tile data and configured an OAM entry.
  2. The sprite moves pixel-by-pixel, smoothly → You understand the difference between sprite coordinates and background tile coordinates.
  3. The sprite moves on top of the background layer → You can see the layering system in action.

Project 4: The Assembly Sprite Mover

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: Assembly (with RGBDS)
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Bare-Metal Programming / Assembly
  • Software or Tool: RGBDS, Emulator with a debugger
  • Main Book: “The Official Game Boy Programming Manual”

What you’ll build: A complete, working ROM written entirely in Game Boy assembly. It will initialize the hardware, load a single sprite tile into VRAM, and allow the player to move it with the D-pad.

Why it teaches Game Boy development: This project rips away all the C abstractions. You will talk to the hardware directly. You will write bytes to memory locations to make things happen. This is the ultimate test of understanding, and the foundation for all high-performance game code.

Core challenges you’ll face:

  • Setting up the RGBDS toolchain → maps to using rgbasm, rgblink, and rgbfix to create a valid ROM
  • Writing a valid ROM header → maps to defining the entry point, title, and checksum area of the cartridge
  • Manual V-Blank waiting → maps to writing a loop that polls the STAT register (0xFF41) until the V-Blank bit is set
  • Manual memory copies → maps to writing loops using ld instructions to copy tile data byte-by-byte into VRAM
  • Direct OAM manipulation → maps to calculating the memory address for a sprite in OAM (0xFE00 + sprite_index * 4) and writing its Y, X, Tile, and Attribute bytes directly

Difficulty: Expert Time estimate: 1-2 weeks Prerequisites: Project 3 (understanding the concepts in C makes this much easier).

Real world outcome: A tiny, efficient .gb file. When run, it will behave identically to the C-based sprite mover, but you will have written every single instruction that makes it happen.

Implementation Hints:

  1. Your main loop will start with the V-Blank wait.
  2. After the wait, read the joypad register 0xFF00.
  3. Use bitwise operations (and, jr nz) to check if a button is pressed.
  4. If a button is pressed, inc or dec the memory variables holding your sprite’s X/Y coordinates.
  5. Finally, write the new X/Y coordinates to the correct bytes in OAM. For sprite 0, this is 0xFE00 (Y) and 0xFE01 (X).
  6. Use an emulator’s debugger! Set breakpoints, watch memory, and inspect registers. It is your best friend.

Learning milestones:

  1. You can compile an assembly file into a bootable ROM → You have mastered the RGBDS toolchain.
  2. You can manually copy tile data to VRAM → You understand memory pointers (hl) and loops in assembly.
  3. A sprite appears and moves on screen → You have successfully manipulated OAM and I/O registers directly.
  4. You can look at a GBDK C function and have a good idea of the assembly it’s producing → You have achieved a true, low-level understanding of the machine.

Project 5: Creating Custom Graphics

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: C (with GBDK-2020)
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Asset Pipeline / Graphics Tools
  • Software or Tool: GBTD (GB Tile Designer), GBMB (GB Map Builder)
  • Main Book: N/A, focus on tool tutorials.

What you’ll build: You will create your own pixel art for a player sprite and background tiles using external tools and import them into your project.

Why it teaches Game Boy development: This project teaches the crucial asset pipeline. You’ll learn the workflow of creating art, exporting it as data (which can be used by C or Assembly), and loading that data into the Game Boy’s VRAM.

Core challenges you’ll face:

  • Using a tile designer → maps to learning the constraints of 8x8, 4-color pixel art
  • Exporting tile data to C arrays or binary files → maps to using the tool’s export function
  • Loading large amounts of data → maps to using set_bkg_data() and set_bkg_tiles() to load your custom level

Learning milestones:

  1. Your custom sprite appears in the game → You have a working sprite asset pipeline.
  2. Your custom background appears → You have a working background and map pipeline.
  3. You can edit the graphics, re-export, re-compile, and see the changes → You have a fast and efficient workflow for changing game art.

Project 6: A Simple Platformer in C

  • File: LEARN_GAMEBOY_DEVELOPMENT.md
  • Main Programming Language: C (with GBDK-2020)
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Game Logic / Collision Physics
  • Software or Tool: Your existing engine.
  • Main Book: N/A, this is about applying concepts.

What you’ll build: A basic platformer game. Your player sprite will be affected by gravity. Pressing ‘A’ will make them jump. They will be able to run and land on solid tiles in your background map.

Why it teaches Game Boy development: This project combines everything you’ve learned into a cohesive, interactive game. It forces you to implement game logic, physics, and more complex interactions between the player (a sprite) and the world (the background).

Core challenges you’ll face:

  • Implementing gravity and jumping → maps to simple physics simulation
  • Background collision detection → maps to checking the background map tile at the player’s future position to see if it’s “solid” before allowing the move
  • Implementing scrolling → maps to changing the PPU’s SCX and SCY registers to move the background layer

Assembly Challenge: A tile-based collision detection function is called many times per frame and needs to be fast. The C code might look something like is_solid(map, x, y). Try rewriting this function entirely in assembly. It will involve calculating an offset into the map array (y * map_width + x) and loading the tile ID from that address to check if it’s a solid tile. Calling this assembly function from your main C game loop is a realistic example of hybrid development.

Learning milestones:

  1. The player falls and stops when they hit the ground → Gravity and ground collision are working.
  2. The player can jump → You are manipulating velocity to create game mechanics.
  3. The world scrolls as the player moves left and right → You can manipulate the PPU’s scrolling registers.
  4. You have a playable character in a small, static level → You have built a true game!

Project Comparison Table

Project Difficulty Time Core Concept Fun Factor
1. “Hello, World!” in C Beginner Weekend C Toolchain Setup ★★☆☆☆
2. Handling Input in C Beginner Weekend Game Loop, I/O ★★★☆☆
3. Sprites in C Intermediate Weekend Graphics Hardware ★★★★☆
4. The Assembly Sprite Mover Expert 1-2 weeks Bare-Metal Assembly ★★★★★
5. Custom Graphics Intermediate 1-2 weeks Asset Pipeline ★★★★☆
6. A Simple Platformer Advanced 2-3 weeks Game Mechanics ★★★★★

Recommendation

I recommend a hybrid path for the deepest understanding:

  1. Start with Project 1, 2, and 3 in C. Use the GBDK libraries to quickly grasp the high-level concepts of backgrounds, input, and sprites without getting stuck on syntax. Your goal is to understand what you’re trying to do.

  2. Once you understand the concepts, tackle Project 4: The Assembly Sprite Mover. This will be challenging, but it will feel like pulling back the curtain. The C functions you used before, like move_sprite(), will suddenly make perfect sense because you will be implementing their logic yourself, byte by byte. Use an emulator with a good debugger!

  3. With that deep, low-level knowledge, return to C for Project 5 and 6. You can now build your game’s logic quickly in C, but you will have the confidence and ability to drop down into assembly to optimize any performance-critical parts, like collision detection, as suggested in the final project.

This approach gives you both the speed of C development and the power and understanding of assembly.


Summary

  • Project 1: “Hello, World!” in C: C (with GBDK-2020)
  • Project 2: Handling Input in C: C (with GBDK-2020)
  • Project 3: Sprites in C: C (with GBDK-2020)
  • Project 4: The Assembly Sprite Mover: Assembly (with RGBDS)
  • Project 5: Creating Custom Graphics: C (with GBDK-2020)
  • Project 6: A Simple Platformer in C: C (with GBDK-2020)