top of page
Search
  • Writer's pictureTom Grove

Flying Shark: Map Representation

There are four stages in the zx spectrum port of flying start. Each stage is described by this struct:


The two most important fields are Events and Map. Events points at an events track that triggers enemy spawning. Map describes the background tiles. The other fields control a few general difficulty parameters. The Checkpoints array supplies the locations in the map ( in terms of tile indices ) where the player can restart.


A Map is composed of ( for want of a better name ) an array of ( up to 256 ) macro tiles. Each macro tile is in turn composed of multiple tiles. Each 16x16 tile is composed from 4 8x8 cells. The same macro tile may be reused multiple times in a map. A macro tile can also be prefixed with a transform which will shift the cells of the tile right or left by an offset. This allows the same macro tile to appear different at different points in the stage. Tiles may also share cells.


The macro tiles themselves are compressed. Each macro tile consists of a series of 4-bit tile id offsets prefixed with a count and an 8-bit base id. These tiles are placed in the map using either a horizontal or vertical swizzle. The vertical swizzle is illustrated below.

The size and swizzling direction is chosen on a macro-tile to macro-tile basis. In the case above (the first macro tile of the first stage) a vertical direction is chosen as the runway would compress better with this choice than with a horizontal choice. Swizzling also helps as nearby tiles to tend to have similar ids. Similar techniques are used in modern GPU texture compression.


The tiles themselves are composed from four cells: in the case of the tiles holding planes, each of the cells will be unique. In many other cases such as the runway or ground, all four ids will index the same 8x8 cell.


The cell ids are also adjusted at runtime based on neighbouring cells: if the cell above and to the left of a cell has an id within a range that identifies it as a shadow caster, and this cell is identified as a shadow receiver, then the cell is replaced with blank black cell. This cheaply adds a bit of additional detail without requiring a larger range of tile ids, which would result in more memory and poorer compression.


How the decompression is done is quite interesting. In the title "Uridium", a similar compression strategy is used. As the player can move freely back and forth through the level, the level has to be fully decompressed before play can start. But in flying shark one new row of 9 tiles is needed only every 16 frames. It would likely lead to inconsistent frame rates if the game blocked everytime a new macro-tile was needed, so this decompression is instead spread across multiple frames.


As mentioned in an earlier post, tiles are read on the IM2 main game task and generated on the. The actual logic is something like:


On the ISR, every 16 frames

  1. read one row of 9 tiles from the decompression buffer and unpack these into 36 cellids.

  2. update the read pointer ( with wrap around ) and update the amount of free space in the decompression buffer

  3. flag the non-isr code to tell it to try and decompress another macro-tile


Outside the ISR

  1. if the flag has been set, read the size of the next macro tile.

  2. if there isn't space in the decompression buffer, do nothing

  3. otherwise decompress the next macro tile and update the buffer write pointer

The decompression buffer is a 256 byte buffer. This capable of storing 28 rows which is more than two full screens worth. This should be sufficient to ensure that there is little danger of the read pointer catching up with the write pointer.


The code for all this is quite involved, though, but can be found under ScrollBackground , GenerateCells and GenerateMacroTile in the disassembly along with complete stage maps.


I feel that is quite a sophisticated technique for the zx-spectrum and not one I have personally seen elsewhere, but I may have been looking at the wrong games. I would be interested to know of games that use multi-tasking techniques.


63 views0 comments

Recent Posts

See All

Flying Shark : Object Logic

Every object has a type field ( 0x5 ) that selects a tick routine. The tick routine for a bomb power-up is shown below (link to video). This object simply moves down the screen. If it collides with th

Flying Shark: Collision Detection

Given two game objects, how do we determine if they overlap? By far the most common technique in 8-bit game development is to compare the extents of the two objects and see if they overlap. The extent

bottom of page