• Skip to main content
  • Skip to header right navigation
  • Skip to site footer
Retro Game Coders

Retro Game Coders

Retro computer/console game + dev community

  • About
    • Retro Computer Collection
    • Contact
  • Blog
  • Retro Resources
    • Retro Gaming Timeline
    • Online Retro IDE
    • Retro Pixel Art Editor
    • Dungeon Loom Map Editor
    • 6502 Programmer’s Reference
    • Emulators
      • Acorn Electron
      • Amstrad CPC Emulator
      • Online BBC Micro Emulator
      • Commodore PET Emulator
      • Browser C64 Emulator
      • DOSBox/DOS PC emulator
      • Tandy CoCo/Dragon
    • Best Retro YouTube Channels
    • New Retro Books
    • Raspberry Pi Amiga Emulation
    • MiSTer FPGA Tutorial
    • BMC64 C64 Pi
  • Community

Home » Retro Game Coders Blog » Programming

Programming the Amiga and Atari ST in C: Counter Loops and Game Ticks

LOOPS in Atari ST and Amiga C

Time to investigate how loops work in C as we develop a game for the ST and Amiga

Loops are one of the fundamental things that make computers useful. You give it a task, it iterates away until it’s done, and then out pops your answers. C has a few different loops to choose from, from loops that check a condition has changed, to loops that use counters.

Think of it as “keep doing this until“, and if you’re careful you won’t get trapped in an infinite loop.

In Hello World with vbcc we got one printf out of the compiler and onto both the AROS shell and the TOS console. Now is a good time to add a loop, because every game has one, and our multi-platform roguelike is going to need one too.

The good news is that the loop itself is identical on the Amiga and the Atari ST. The only platform-specific quirk is how the program exits, and we’ll deal with that in one place.

Join Retro Game Coders Community
Join the Retro Game Coders Community

Types of loops in C

A roguelike doesn’t need 50 frames per second, but it does need to respond well. We need to know that our loops are doing the right things and not trying to do so much that the game feels laggy.

For our game we’ll have a core inner game loop:

  • Read input
  • update game state
  • redraw screen
  • if not game over, then repeat.

For this we’ll normally use something like while(game_running) which will keep going while game_running is true. Each pass through this inner loop is a game turn or tick.

The C for loop is also a good building block, but rather than going until something tells it to stop, instead it works for a set number of iterations. You’ll see it appear multiple times later as our game progresses.

Trying out the for loop is a great first test when starting out on any new platform. If “Tick 1” through “Tick 20” all show up in order, you know that stdout is outputting and not storing up a buffer and that your C runtime is incrementing integers correctly.

The code

▶ Try this lesson in your browser

Run the same vbcc C counter loop on both 16-bit targets in our in-browser IDEs. Hit Run and watch twenty ticks scroll past:

  • Open counter.c on the Amiga 500 (AROS) →
  • Open counter.c on the Atari ST (EmuTOS) →
#include <stdio.h>

int main(void)
{
    int i;
    printf("Counter demo starting...\n");
    for (i = 1; i <= 20; i++) {
        printf("Tick %d\n", i);
    }
    printf("Done.\n");
#ifdef __ATARI__
    printf("Press Enter to exit...\n");
    getchar();
#endif
    return 0;
}

That’s the whole program. Most of the new ideas live in the loop, so let’s pick them apart.

Declaring int i;

C is a statically typed language: every variable has a type the compiler must know before the variable is used. int is the standard integer type, big enough for everyday counting on every platform we care about. We name the variable i for “index” or “iteration” because that’s the very old C convention for a loop counter (mathematicians use i, j, k for indices, and C borrowed it).

Declaring int i; on its own line at the top of the function is C89 style. C99 lets you declare the variable inside the loop header, like this:

for (int i = 1; i <= 20; i++) {
    ...
}

vbcc accepts both on the Amiga and the Atari ST. Classic 16-bit C code tends to stick with C89 because that’s what the older AmigaOS and TOS headers expect, and because mixed declarations weren’t always reliable in the period toolchains. You’ll see both styles in other people’s retro C and either is fine.

💬 Questions or comments? Head over to the community to discuss!

The for loop, expanded

for (init; condition; update) is the textbook three-part C loop. The compiler turns it into something like:

int i = 1;
while (i <= 20) {
    /* body */
    i++;
}

If we break that down:

  • i = 1 is the initialiser or starting state. It runs once before the loop body.
  • i <= 20 is the condition. It’s tested before every iteration and if/when it’s false the loop ends.
  • i++ is the update. It runs after every iteration, just before the condition is checked again.

The body inside the braces runs once per pass. Twenty passes outputs twenty Tick N lines.

Incrementing with i++

You might not be familiar with this math:i++. It simply adds 1 to i and is an easier way of saying i=i+1.

There’s also ++i which pre-increment aka does the addition first. Either form works here.

You can also do i-- to decrement, and so on.

Fancy printing: printf with format specifiers

We saw previously how printf has a fair amount of baggage, but it really earns its keep when you need to mix fixed text with variable values. The format string contains %d, a conversion specifier that says “substitute the next argument here as a signed decimal integer“. The matching value is the second argument, i.

Specifiers you’ll see often:

  • %d or %i: signed integer.
  • %u: unsigned integer.
  • %x: hexadecimal (lowercase). %X for uppercase.
  • %c: a single character.
  • %s: a C string (a char * with a terminating zero).
  • %f: floating point. Not all retro libcs include float support, so float-aware printf can be heavy or absent.
  • %%: a literal % sign.

Mismatching the specifier and the argument is one of the easiest C bugs to write. printf("%s\n", 42) won’t print “42”; it will treat 42 as a pointer and crash. Modern compilers warn about this, though, if you turn warnings on.

Done. and the platform-specific exit

The printf("Done.\n") is a guardrail. If the output ends after the last Tick 20, you have to trust the loop finished. If it ends with Done., you know it did. On retro hardware a glitch can leave a program quietly hung, so the confirmation is worth one line.

The next two lines are where the Amiga and the Atari ST differ:

  • On the Atari ST, GEM closes the TOS console window the moment main returns. Without the getchar() the output flashes away before you can read it. We saw this in part 1, and the same fix applies here.
  • On the Amiga, the AROS shell stays open after the program returns, so you can read the output without a getchar(). Leaving the call in does no harm, it just means you press Enter one extra time.

Who Are You?

Here is a good place to introduce a neat feature of many C compilers. The #ifdef __ATARI__ block is how we can introduce platform variations in a single source file.

ifdef is a C and C++ preprocessor directive that means “if defined“. vbcc defines __ATARI__ when targeting TOS, so the ST build pulls the keep-the-console-open code in and the Amiga, not having that defined, ignores it.

This wasn’t really necessary, just an opportunity to show how to keep both targets happy. If you’d rather keep the source minimal you can include getchar() unconditionally – it works on both platforms.

Things you can try in the IDE

Once it runs on both targets, try a couple of edits:

  • Change the upper bound to 200 and re-run to see how each console handles a larger burst of output.
  • Add an if (i % 5 == 0) block inside the loop to print a “Round done” line every five ticks.
  • Switch the declaration to the C99 in-header form, for (int i = 1; ...), and confirm vbcc still compiles it on both machines.

Next part

Next we look at every printable ASCII character on the Amiga and the Atari ST and decide which ones make good text-based dungeon tiles … make sure you’re subscribed so you don’t miss it!

Category: ProgrammingTag: Atari ST, Commodore Amiga, Retro C/C++ Programming, Roguelike Multiplatform, vbcc
Previous Post:Atari ST and Amiga Programming in CProgramming the Amiga and Atari ST in C: Hello World with VBCC
Next Post:C64 BASIC: Game Map Overhead “Camera View”C64 Viewport Map smaller

Retro Game Coders

Retro computer/console game + dev programming community by Chris Garrett

  • Bluesky
  • Threads
  • Facebook
  • Instagram
  • YouTube
  • Mastodon

Maker Hacks ・ D6Combat・chrisg.com

© Copyright 2026 Chris Garrett

Privacy ﹒ Terms of Service

Return to top