The original version of this piece was thrown together as notes for the RGCD review of Callisto but, since there was a little interest shown in what’s going on behind the scenes, I’m going to post it here in a slightly more verbose form as well.
So lets start with the basics, Callisto is a horizontally scrolling shoot ‘em up for any Atari 8-bit with 48K of RAM and the scroll engine started life as an exercise in efficiency, trying to find ways to keep the overheads for scrolling to a bare minimum. I’m not sure if there’s ever been an official name for the process (or even if it’s been done previously) but I’ve usually referred to it as “single LMS scrolling” since there’s just one LMS command in the display list governing where to fetch data for the scrolling area and that gets incremented once every eighth frame (with the hardware scroll changing every other frame) to shift everything to the left. The new column of arriving data is written into whichever bytes are just a little off the right hand side of the playfield so, apart from a few extra overheads for processing that offset each time and juggling the software collision and character-based bullets, the CPU load for the scrolling is about as minimal as it can get.
Now comes the complicated bit, the sprite-based in-game objects; the Atari 8-bit has eight hardware sprites in total, four are referred to as “players” and are 8 pixels wide, the remaining four are “missiles” which are just 2 wide. There are four colour registers so missiles either use the same colour as their associated player or can work in “5th player mode” where they take colour information from one of the playfield registers. Each sprite-based object in Callisto uses one player and its associated missile to produce a ten colour clock wide, 19 pixel high object and there can be seven on screen with a maximum of four per scanline. Which object gets which player/missile pair depends on their vertical positions (the player’s craft isn’t part of this process and will always be using the first player and missile) and these are sorted once a frame.
At the end of each frame, the Y movement is dealt with (the hardware sprites are a little shy of full screen height so to move in Y the previous image has to be cleared and the new one drawn in – this happens regardless of if the object moves because they also animate) and at the top of the play area, the X position of the sprite pair for player’s craft and the three enemies with the lowest Y position are set and a loop that splits the sprite colours kicks in; this loop only runs until the first of those three enemies finishes, at which point the X register is changed to the correct place for the fourth object before a second colour split loop kicks in and this process repeats a couple of times to reposition the remaining two sprite pairs.
The sprite colour splitting is being somewhat sneaky, since the character-based screen mode used in Callisto has what C64 coders call a “badline” every eighth scanline (where the DMA fetch happens to pull the next row of characters in) there’s not enough cycles left to split all four sprite colour registers on those scanlines and even getting it done on the other scanlines would be pushing things; instead the engine changes colours every second scanline, with the player’s craft being updated on the “badlines” to keep the number of jobs on those scanlines to a minimum and a few hoops have to be jumped through to prevent the transition between colour split loops where the sprite X positions take place.
So, along with housekeeping tasks like updating the sound effect engine, managing the scrolling and writing the relevant values into the status panel, Callisto‘s code locks up the CPU for 160 scanlines of play area to hammer mercilessly at the colour registers with a couple of quick pauses to change X positions, has to remove and redraw seven objects which each use 57 bytes of definition (so 95 bytes written per object per frame since the colour data doesn’t need to be cleared, 665 bytes for all seven objects), managing all of those objects (updating the current ones, decommissioning those outside of the active play area and assigning new enemies based on the level data) and sorting the enemies by Y position to assign the hardware sprites to them for the next frame. There’s room for improvement because the sort routine is… well, rubbish frankly but that’s still a lot of balls kept in the air at 50 frames a second!