Table of Contents

Getting started with the GameTank C SDK

To start a new project you can use the template feature on github to create a new repository based on a snapshot of gametank_sdk.

Along with the SDK itself you'll need to install some other tools:

cc65

cc65 is an open source toolchain for cross-compiling C to 6502-based platforms. It includes a C compiler, an assembler, and a linker. It supports multiple variants of the 6502, including the 65C02 and the W65C02S used by the GameTank.

This should be built from source on a recent commit, or can be downloaded as a snapshot build for Windows. The last official release is currently quite dated, so you'll have trouble building the SDK if you install it with apt on Linux or use the “Releases” tab on github instead of the latest snapshot.

NodeJS

Node is used for the sprite and music conversion scripts as well as the build config generator. Version 20 or newer should be used.

Zopfli

Zopfli is the compression tool used by the SDK for sprites. It can be installed with apt or built from source. We'll be using its Deflate mode that corresponds to the Inflate algorithm provided as a library in cc65.

Make (and a few other Unix tools)

If you already installed any tools for compiling C then make is probably also installed. This command will handle the numerous other commands you'd need to convert your collection of code files and art assets into a GameTank ROM file.

Some other GNU tools such as find or sh will be required to build.

Emulator

Finally you'll need the GameTank Emulator to test your games on your PC.

First Build

A clean copy of the SDK will include the following folders:

src will be the home for your C code, and src/gt holds the library code provided to help with tasks like drawing images, reading controllers, or playing sounds.

assets is where you'll place files such as bitmaps and midis to be picked up by conversion scripts.

scripts is where the conversion and build config scripts live.

lib contains prebuilt helper binaries and doesn't need to be interacted with that much.

To check that dependencies are installed and the SDK was pulled cleanly, build the starter code with the following commands.

make import
make

The first command will check the assets folder and prepare generated code files as well as the linker config for your game.

The second command will start compiling all your code files and create a bin folder. Inside bin will be game.gtr, which can be opened in the GameTank Emulator.

You should see an orange square bouncing around on a gray background. This behavior is defined in main.c, which is the starting point of your program as far as C code is concerned.

Let's take a look at this file!

#include "gametank.h"
#include "drawing_funcs.h"
 
int main () {
    char col = 30, row = 20;
    int dx = 1, dy = 1;
 
    init_graphics();
 
    flip_pages();
    clear_border(0);
    await_draw_queue();
    flip_pages();
    await_draw_queue();
    clear_border(0);
 
    while (1) {                                     //  Run forever
        clear_screen(3);
        draw_box(col, row, 8, 8, 92);
        col += dx;
        row += dy;
        if(col == 1) {
            dx = 1;
        } else if(col == 119) {
            dx = -1;
        }
        if(row == 8) {
            dy = 1;
        } else if(row == 112) {
            dy = -1;
        }
 
        await_draw_queue();
        sleep(1);
        flip_pages();
 
    }
 
  return (0);                                     //  We should never get here!
}

init_graphics() takes care of some setup used for other drawing functions, and should be called pretty early on.

The GameTank has a double buffer, and typically you'll be drawing on one frame while the other is being presented to the television. flip_buffer() toggles both the render target and the output buffer. In the beginning it's used to clear the screen on both buffers, and then is used on every frame right after the beginning of the video sync period.

A notable feature of the SDK is a queued drawing API. The GameTank's blitter gives it the ability to continue executing code while pixels are being copied into the framebuffer. Making the most of this ability requires performing as much CPU computation as we can during a blit operation instead of simply waiting for a blit to finish. Eventually though there is nothing else to do but wait, and await_draw_queue() allows us to wait not just for the current draw but for all drawings we've requested that are still pending.

draw_box draws a box with a solid color at a given location. clear_screen and clear_border are essentially shortcuts for calling draw_box on the full screen or the screen edges. This is part of the queued drawing API, so if it is called multiple times consecutively the first box will begin drawing while the sucessive calls are added to a list to be automatically drawn when the previous box finishes.

sleep waits for a number of frames, but is also used for synchronizing with the television picture. sleep(1) doesn't wait for an entire 1/60s frame, but instead waits until the beginning of the next vertical sync period. This is when the electron beam will be approaching the top-left corner of the monitor, and soon begin to emit the next full frame.

Testing on hardware

See the Cartridge Flasher article for how to put your game onto a cartridge. The SDK generates a “game.gtr” file to use with the emulator and several “game.gtr.bankXX” files to use with the flasher.

./GTFO.exe -p COM3 ~/repos/fiend/bin/game.gtr.bank*