v1.0 Challenging constraints
Here is the game I set out to remake - Artillery on the Macintosh by Kirk Crawford:
My version works within the limitations of Sinclair BASIC in the following ways:
- For performance reasons the trajectories are plotted as a series of lines, rather than pixel plots, with the chosen time interval being a trade-off between curve smoothness and game performance. The result of a DRAW command cannot be partially on screen, which explains why lines do not plot all the way to the edge of the screen when exiting or re-entering the screen bounds. A single pixel plot is always shown when re-entering even when in terrain though, so this can often be used for ranging the next shot.
- Consequently collisions cannot be detected per plotted pixel, and must rely on character block attributes. The castles are checked for colour changes so their hit detection is always accurate. However, only the end position of each shot's trajectory increment is checked to see if it has hit the terrain. This means that it is possible to skim a high velocity shot through a jagged edge of terrain for instance. This is a necessary compromise of the design choices.
- The trajectory and collision loop is at the top of the program listing to maximise BASIC interpreter performance. DEF FN was also avoided for the maths for the same reason. The loop was optimised to minimise the amount of conditional logic, and even REM statements were stripped here.
- The terrain generation algorithm is a sine function with some tweaks since that produced the best looking hills (though still very jagged) with the required variability. I had experimented with a 4th degree polynomial function which the Macintosh Artillery seems to use, but I concluded that it wasn't suited to such low resolution. To rule out any lateral bias to the algorithm, the terrain function has a 50% chance of being horizontally flipped.
- The blockiness of the terrain is a necessary design compromise unfortunately, because using any inked pixels would result in awful colour clash as the trajectory arcs passed across those cells. I had anticipated smoothing the blocks somewhat using the quarter block graphics characters on the number keys until I realised this.
- The animations for the flags, the fire, and the explosions make creative use of OVER, and FLASH, and pre-existing characters.
I did investigate compiling some or all of the BASIC to machine code via HiSoft BASIC or Boriel's ZX Basic to improve performance, but there were some obstacles - mainly because I considered it was important for the players to be able to input null values to retain the angle or velocity value from the previous turn. This is because in practice a player will tend to only adjust one variable rather than both per turn, so this design decision significantly reduces the amount of typing needed and improves the flow of the game. A string INPUT can be null, but not a number INPUT, hence I have to use the VAL function to convert the string to a number which neither of those BASIC compilers supports. However, by removing that feature and compiling with HiSoft BASIC, I found that although the trajectory plot was faster it didn't actually improve the game. It did introduce some functional problems though, probably due to variable types autodetecting incorrectly. The relatively slow trajectory plot arguably introduces a degree of suspense to the game increasing the enjoyment of a two player match, so I think the game is just fine remaining as a pure BASIC program.
The experience of writing this game has brought an even greater appreciation of quite how special a product the ZX Spectrum was. The BASIC language remains versatile, not quite the horrific retrograde step I was expecting, and the reference manual that was bundled with every Spectrum is absolutely exemplary. It's clear enough that a child can understand it (I did, back in the day), it introduced escalating complexity with perfect pacing, and it's amazingly concise. They don't make 'em like they used to...