tutorial · gerla.cc
The life cycle of a game
A video game, underneath everything else, is a loop that spins: it boots, waits for the button, gives three lives, takes them away one by one, says game over, saves the record and starts again. Let's see how that loop is built, phase by phase, on the two environments at play: Commodore 64 (6502) and Mega Drive (68000). All in assembler, with the code explained line by line by the comments.
Note: in the real game, on the Mega Drive I write the logic in C. Here, though, I show the skeleton in 68000 assembly, because a tutorial on the loop reads better bare: it's exactly what the compiler produces, and what the machine actually runs.
power on, set everything up
waits for FIRE / START
Powering on
At power-on the machine runs the first address we point it to. Before anything, we silence the interrupts, set up the screen and video registers, and zero the variables: how many lives, what score. Then we jump to the title screen. It's the opening move, done exactly once.
C64 · 6502
Mega Drive · 68000
Same idea, two dialects: silence the noise, prepare the video, set lives and score, go to the title.
Waiting for the button
The title screen does one thing: it waits. It draws "PRESS FIRE" and then spins in a small loop reading the joystick every frame, until you press. The trick is patience: one turn of the loop per video frame, so the control stays responsive without hogging the machine. The moment the button arrives, it jumps to the game.
C64 · 6502
Mega Drive · 68000
A loop that does nothing but listen. The real game begins only when you decide.
The heart: one frame at a time
This is where the game lives. Every turn of the loop is a frame: you wait for the start of the frame (the vblank, the moment the video beam returns to the top), read the inputs, move the player, move the enemies, check collisions. If you're still alive, the loop restarts. Sixty times a second, always the same. All the action you see is this loop spinning fast.
C64 · 6502
Mega Drive · 68000
The wait_vblank is the metronome: without it, the game would run at different speeds on different machines. With it, everything flows in time.
Dying, and counting lives
When you die, the game loop breaks and you land here. The rule is simple: take away one life. If any are left, put the player back on the field and return to play. If you're at zero, the road leads to game over. One subtraction decides everything.
C64 · 6502
Mega Drive · 68000
The dec/subq lowers the counter and, at once, also sets the "is it zero?" flag. The branch right after reads that flag: no extra comparisons.
Saving the high score
When the game ends, the score is compared with the record. If you beat it, the record updates. And this is where the two worlds truly part ways. On the Mega Drive the cartridge can have a battery-backed SRAM: write the record there and it survives even with the console off, forever. On the C64 there's no battery: the record lives in RAM for the session, and if you want it eternal you save it to disk. Same idea, two ways to remember.
C64 · 6502
Mega Drive · 68000
The 16/32-bit comparison is done a piece at a time, from the heaviest byte: if that one decides, the rest isn't even worth looking at.
And round again
Last loop: wait a moment, or a button, and go back to the title screen. The circle closes and the machine is ready again to wait for the next player. It's the same jmp title from day one: from here, everything starts over.
C64 · 6502
Mega Drive · 68000
Note that the record does NOT reset: lives and score start over, but the best stays. It's the game's memory.
A loop inside a loop
That's all: a big loop (title → play → game over → title) and inside it a small loop spinning sixty times a second (the game, frame by frame). The dialect and the machine details change, but the shape is the same from 1982 to today, and in the HTML5 game I started from too. Learn this, and you've learned the skeleton of any game.