GERLA.CC

tutorial · commodore 64

C64 sprites, explained by putting them on the road

Matteo85 is just starting out with Commodore 64 graphics, and he sent me two drawings: a SUV and a frog. But a sprite is understood far sooner by watching one move than by reading its definition, so I did the most direct thing: in a couple of hours, on a Sunday, I put them on the road. Out came Save The Frogs, and the name is his. This is the explanation that grew around it.

01 · what it is

Eight drawings the video chip moves on its own

On this machine a sprite isn't an image you draw on the screen: it's something the video chip puts over the background, on its own, while the electron beam crosses the screen. You tell it where it goes, and it puts it there. The background underneath is never touched, so when the object moves you don't have to redraw the road.

That's the real reason sprites exist, and it's worth saying before anything else. On a machine doing a million operations a second, erasing and redrawing a car fifty times a second would eat a good part of the budget on its own. Sprites take that work off the CPU and hand it to a circuit that does it for free.

There are eight sprites. Not nine. It's a fixed number, wired into the chip, and most of the craft on this machine is making eight moving things be enough.

moral: a sprite isn't a drawing, it's a drawing plus a piece of hardware carrying it around. If you remember only this, the rest is detail.

02 · the grid

24 by 21, and two ways to fill it

Every sprite is born on a grid of 24 columns by 21 rows. Those look like arbitrary numbers and aren't: 24 points are exactly three bytes per row, and twenty-one rows of three bytes make 63 bytes, which is almost a round block of memory. We'll come back to that "almost".

That grid can be filled in two ways, and the choice is per sprite.

In high resolution each point is one bit: on or off. You get the finest shape the machine can make, but only two outcomes, transparent or the colour assigned to that sprite. One colour. One.

In multicolor the bits are read in pairs, and each pair makes a point that's twice as wide. There are four combinations, and that's where the whole point of the mode lies:

00 trasparente, si vede lo sfondo 01 colore comune 1 ($d025) uguale per TUTTI gli sprite 10 colore dello sprite ($d027 + n) suo, e solo suo 11 colore comune 2 ($d026) uguale per TUTTI gli sprite
the four multicolor combinations

So it isn't "four colours of your choosing": it's one colour of your own plus two borrowed from everybody, plus transparency. If you change shared colour 1 to please the frog, you change it for the SUV too. It's a constraint that decides how you draw, and it can't be dodged: you design around it.

And you pay for it: the points are twice as wide, so across you have twelve, not twenty-four. Shapes come out blocky. Matteo chose multicolor, and it's the right choice for these two subjects: with a single colour, a SUV that needs bodywork, windows and wheels turns into a silhouette.

The 24 by 21 grid of the three Save The Frogs sprites

the three sprites on the real grid. You can see the double-width points, and that the SUV takes two grids while the frog takes one.

03 · the data

63 bytes used, 64 taken, and a pointer

The drawing ends up in memory as a flat sequence: three bytes per row, twenty-one rows, top to bottom. Sixty-three bytes. But the chip doesn't fetch the data from an arbitrary address: it reads a pointer, a single number, and multiplies it by 64. That's the "almost" from before: blocks are 64 bytes, the drawing uses 63, and the sixty-fourth byte sits there doing nothing.

; il puntatore sta negli ultimi 8 byte della memoria dello schermo ; indirizzo dei dati = puntatore x 64 lda #$0d ; 13 x 64 = $0340 sta $07f8 ; sprite 0 -> disegna quello che c'e' a $0340 ; dove va, e di che colore e' lda #172 sta $d000 ; sprite 0, colonna lda #180 sta $d001 ; sprite 0, riga lda #%00000001 sta $d015 ; accendi lo sprite 0 sta $d01c ; ...e leggilo in multicolor
switching on a sprite, from scratch

The advantage of that pointer is that changing the drawing costs a single write. An animation doesn't move bytes: it changes one number, and on the next frame the sprite is a different drawing. In the game, that's how a run-over frog becomes a run-over frog.

moral: on the C64 animations are cheap and memory is dear. All the frames are already there, and what moves is the finger pointing at them.

04 · using two

Why the SUV is two overlapping sprites

Twenty-four points wide, which in multicolor becomes twelve, is little for a car seen from above that has to read as a car. And above all one colour per sprite is little: the bodywork takes it, and only the two shared colours are left for the windows.

The classic way out is to use two, one on top of the other, at the same position. It costs a second sprite out of eight, but it doubles the colours you own, because each of the two brings its own. The SUV is built that way, the frog isn't: one is enough for it.

And this is where the number eight starts to bite. The SUV has already taken two, so six are left for the frogs on the road. It isn't a theoretical limit: it's the reason the game has that many frogs and not twice as many.

05 · the shadow

Not drawn: computed

The shadows under the SUV and under the frog weren't drawn by anyone. They come out of a routine that runs before the game, on the computer, and does one thing only: for every filled point in the drawing it looks at the position one down and one to the right, and if there's transparency there it puts a black point.

per ogni punto (x, y) del disegno: se il punto e' pieno: se il punto (x+1, y+1) e' trasparente: metti nero in (x+1, y+1)
the whole shadow, in four lines

Four lines, and the result is that the two subjects stop looking glued to the asphalt. It's the kind of trick I like showing to someone starting out, because it turns the starting idea on its head: not everything you see has to be drawn. Some of it gets written, and the program writes it.

There's a further practical reason. A computed shadow stays right if Matteo changes the drawing: he redraws the SUV, reruns the conversion, and the new shadow comes out on its own. A hand-drawn shadow instead comes unstuck from the drawing at the first change, and nobody notices until they look closely.

06 · moving it

The drawing doesn't know how to steer

A sprite switched on and standing still is still only a drawing. Its position is two numbers in two registers, and moving it means writing into those registers. Behaviour, the fact that it goes right when you push right, isn't there: you write it.

lda $dc00 ; leggi il joystick and #%00001000 ; il bit della destra: 0 = premuto bne fine lda $d000 ; colonna dello sprite 0 clc adc #2 ; spingila di due sta $d000 fine:
read, decide, write: and that's all the movement there is

There's a trap waiting, and it's the first one everybody falls into. The column register is one byte, so it goes up to 255, but the screen is wider. The missing bits all live together in another register, one bit per sprite: if you forget it, your object gets to the middle of the screen and teleports to the left. It isn't a fault in your code, it's the ninth bit you didn't write.

07 · what is NOT a sprite

The road is made of characters

Watching the game it looks like the SUV is racing. It isn't: it stays at almost the same height, and it's the road that slides underneath it like a moving carpet. And the road isn't a sprite, because it couldn't be: sprites are eight, and small.

The track is a table of rows. Each entry says where the edges are and which colour band to use, and the program reads an entry, picks the tiles, writes them into screen memory and moves to the next row. Off the carriageway grass, at the sides guardrails and kerbs, in the middle asphalt and a broken centre line. They're characters, that is eight-by-eight pieces redrawn once and reused everywhere.

The curves come out stepped, and that isn't a flaw: it's the visible consequence of that choice. Reusing tiles costs far less than redrawing every point, and on this machine you pay the price in looks, not in time.

Save The Frogs running: the road, the edges, the centre line and the score panel

everything visible here except the SUV is made of characters: the grass, the kerbs, the asphalt, the broken centre line and the score panel at the top. There are two sprites, and they're the car.

moral: the practical rule is this. Sprites for the few things that move by themselves; characters for everything else, including what looks like it's moving but is really scrolling. Getting that split wrong is the fastest way to run out of machine.

08 · collisions

The chip tells you, but not enough

The video chip can do one handy thing on its own: it notices when two sprites touch, or when a sprite touches the background, and it writes that into two registers. It looks like the answer to everything, and for a game like this one it isn't.

The register tells you which sprites are involved, but not where, and above all it clears itself when you read it: read it twice in the same pass and the second time the collision never happened. On top of that the chip counts as contact any non-transparent point that overlaps, shadow included. A shadow brushing a frog isn't running it over.

So in the game I don't ask the chip about collisions: I compute them. The program knows where things are, compares the frog's row with the car's and then the horizontal distance, and if it's under a certain threshold it counts the hit. It isn't a physics simulation, and that's better: results have to be predictable for the player, not faithful to reality. A threshold in numbers can be widened or tightened until the game feels right; the chip's register can't be tuned.

in short

What sticks, if only one thing does

A sprite is a 24 by 21 drawing that a circuit carries around for you for free, you get eight, and each has a colour of its own plus two borrowed from everybody. Everything else on screen is characters. The drawing doesn't know how to steer, or fall, or die: the program writes that, and the program is the part where a drawing becomes a game.

Save The Frogs was born in a couple of hours and it shows: an endless run, three lives, points that climb with speed, and no finish line. It was never meant to be anything else. It was there to answer a concrete question, do my drawings work?, and that answer comes faster by running them than by explaining them.

Eight minutes, from drawing to game

If you'd rather be told it, everything above is also in a video: the sprites, the road, the game loop, collisions, the menus and the scrolling fault I had to fix.

subtitles can be switched on from the player menu, the speech bubble at the bottom right: they don't start on their own.

savethefrogs.prg

14 KB · Commodore 64 · loads in VICE or on real hardware
loads at $0801 and starts with RUN

Download the PRG

Credits. Game design and sprite graphics: Matteo85, who also named the test. The programming is mine.

← All tutorials The C64 on this site →