← All articles

Zaxxon Measures Your Height With Your Shadow

Zaxxon looks like nothing else from 1982. The fortress is drawn at an angle and scrolls past diagonally, and your ship flies over it, through gaps in its walls and under its electric barriers. It is also famous for being hard to read. On a flat screen, is the ship high above that wall or just in front of it? Players learned to watch two things: the dark shadow under the ship, and the altimeter bar down the left edge.

Inside the original arcade program, those two are more closely tied than they look. The game does not keep the ship's height and then draw a shadow to match. It keeps the position of the shadow, and the height is simply how far the ship is from it. This article follows that one number through the 1982 code, from the shadow to the altimeter to the walls.

The height is a gap on the screen

Everything in Zaxxon is a picture placed at a position on the screen. For the ship, the game keeps how far across the playfield it is, and how far down the screen it is drawn. It also keeps a second point: the spot on the floor directly under the ship. The shadow is drawn there.

The altitude is the distance between the two, straight up the screen:

Altitude is the gap between the ship and its shadow A diagonal strip of fortress floor. The shadow sits on the floor at the ground point; the ship is drawn straight above it on the screen. The ship is at 94 and the ground point at 162, counted down the screen; the distance between them, 68 pixels for a new ship, is the altitude the game stores. altitude = 68 pixels ship at 94 shadow ground point at 162 A NEW SHIP: 162 - 94 = 68
Altitude is the gap between the ship and its shadow, in screen pixels.

The game counts those positions in pixels down the screen. A new ship is at 94, with its ground point at 162, so it starts 68 pixels up. Push the stick forward and the ship dives: it moves down the screen toward its shadow, which stays put, and the gap shrinks. Pull back and it climbs away from it.

In the code it is a single subtraction:

ld   a,($67A8)    ; where the ground point is drawn, down the screen
sub  (hl)         ; minus where the ship is drawn
ld   ($6417),a    ; that difference is the altitude

Moving sideways is where the isometric view shows. The floor runs at an angle, so sliding across it also moves the ship and its ground point down or up the screen together, about half a pixel for every pixel across. Both move, the gap between them does not, and the height stays the same.

The shadow is simply placed on the ground point, so on screen the space between ship and shadow is exactly the number the game is using. Usually. The game hides the shadow in space, and at the start of each life until the ship nears the fortress. It also hides it for a moment whenever the ship passes a wall, and over some ground objects it draws the shadow 8 or 10 pixels higher, as if it fell on top of them.

The altimeter reads the same number

The bar on the left is drawn from that same altitude byte and nothing else. Every 16 pixels of height fill two character cells of the bar, and the last few pixels pick a part-filled end piece. It is not a separate instrument: it is the gap between you and your shadow, turned on its side.

Four floors in the sky

The altitude can be anything from about 7 to 73 pixels, but most of the game does not use it directly. It sorts the ship into one of four height bands:

The four height bands Altitude from 0 to 80 pixels, cut into four bands at 24, 40 and 56. Band 3 is the lowest, below 24; band 2 is 24 to 39; band 1 is 40 to 55; band 0 is 56 and up. A new ship starts at 68, in band 0. MAME saw altitudes from 7 to 73. Outside the fortress the ship's picture gets smaller one step per band as it descends. 0 24 40 56 0 1 2 3 new ship, 68 HIGHEST SEEN, 73 LOWEST SEEN, 7 SHIP PICTURE outside fortress ALTITUDE IN PIXELS · BAND NUMBER
The game cuts the altitude into four bands at 24, 40 and 56 pixels. Band 0 is the highest.

The band is what the game actually plays with. Before the ship gets inside the fortress walls, and in space, where the shadow is often missing, it even changes the ship's picture: each band has its own drawing of the ship, a little smaller each step down, so a high ship looks bigger. The level picture is about 14 by 23 pixels in the top band and 10 by 16 in the lowest. Once the ship is inside the fortress, where the shadow does that job, the picture stays at full size. (The switch between the two follows a flag whose low bits change as the ship clears the outer wall; reading it as "inside the fortress" fits every run but is not proven.)

Shots use the band too. A shot remembers the band the ship was in when it was fired, and keeps it even if the ship climbs or dives afterwards.

What a wall really is

Here is where the four bands matter most. To the player a fortress wall is a solid 3D block of bricks with a notch or a doorway in it. To the collision check, it is a grid: five columns across the playfield and four bands up.

What a wall looks like to the collision check Two walls drawn as the game tests them: five columns across, four height bands up. Left, a tall wall with its gap row at band 0: every cell is solid except columns 2 to 4 of the top row. Right, a low wall with its gap row at band 3: only the bottom row exists, columns 1 and 2 of it are open, and everything above it is clear. TALL WALL top row 0, columns 2-4 open 0 1 2 3 1 2 3 4 5 LOW WALL top row 3, columns 1-2 open 0 1 2 3 1 2 3 4 5 BAND COLUMN (SIDEWAYS POSITION) crash opening clear air
A wall as the game tests it: five columns by four bands. A tall wall with its notch at the top, and a low wall with a doorway.

Each wall carries three numbers: the band of its top row, and the first and last columns of the opening in that row. The test goes like this:

  1. If your band is below the wall's top row, you hit solid wall.
  2. If your band is above it, you fly over.
  3. If you are in the top row itself, you get through only if your sideways position is inside the opening's columns.

The tall wall at the entrance to the fortress, the first one in a game, has its top row at band 0, the highest, with columns 2 to 4 open. So you must be at least 56 pixels up and in the middle three fifths of the playfield. At 55 pixels, one pixel lower and so in band 1, it is a crash, however clear the ship looks on screen.

The check is not a single moment. When a wall reaches the ship, the game tests it on every frame for 30 frames, half a second, so climbing or sliding into the brick halfway through still counts. While that happens the shadow vanishes, for longer behind taller walls: 96 frames for a wall four bands high, down to 48 for a wall one band high.

Electric barriers use the same numbers in a different way. A barrier is deadly only in its own band, all the way across, and harmless above or below it. So you can fly under a high barrier or over a low one, but not through.

Watching the gap

All of this was read from the original program, then confirmed by running the unmodified 1982 code under a test script that recorded the game's memory every frame through the attract demo and a game. In every frame the ship was flying, the altitude equalled the gap between ship and ground point, or, in about one frame in nine, was one pixel off. The band always matched the 24, 40 and 56 pixel cut-offs, the altimeter bar in video memory always matched what the altitude byte predicts, and the shadow sat exactly on the ground point except when it was raised onto an object.

For the walls, a breakpoint logged every wall test: the wall's three numbers, the band and sideways position of the ship or shot, and whether it crashed. A simple autopilot flew the game, steering for each opening, and in a second run deliberately missing it. Across 3254 logged tests by the ship and its shots (some are repeats, since every run ends in the same attract demo), the rule above predicted every crash and every clean pass, including barriers passed underneath and overhead and one crash into a barrier in its own band.

The full detail, with addresses, is in the height and walls notes.

Credits and further reading

  • The MAME project's Zaxxon driver, src/mame/sega/zaxxon.cpp and zaxxon_v.cpp at the mame0289 tag, by Nicola Salmoria, Stephane Humbert and the MAME team: the source for the hardware, the memory map and how sprites and the scrolling background are drawn.
  • The Z80 disassembler is Lawrence Kesteloot's z80-disasm.
  • No published disassembly of Zaxxon was used; every address here comes from the lab's own reading of the ROM.