This started in early February '22 when this story appeared in a feed: https://spectrum.ieee.org/battlezone (and a few days later on Hackaday too: https://hackaday.com/2022/02/13/hackaday-links-february-13-2022/). Looking at the Battlezone screen I was struck by two things
- the line-work was not dissimilar to what I did with ElitePetite
- the radar screen looked a lot like an analog clock
So I embarked on recreating the demo mode of Battlezone, with the added ability to display the time, as raison d'etre.
As with Elite, I had a wonderful online resource to use as reference, https://6502disassembly.com/va-battlezone/ and I also watched some videos (like this). It was a matter of studying the 6502 assembly and recreating the behaviour in C. This project has nothing like the verisimilitude I battled for in ElitePetite. Battlezone is more complicated but also I don't have the personal connection to it that I have with Elite -- I'm not sure I've ever played Battlezone myself.
The key to this is my Sparse algorithm which encodes lines drawn on a rectangular canvas as run-length encoded rows. The game code draws lines on the "screen". A modified Bresenham algorithm sets "pixels" at row and column. The Sparse algorithm updates byte-oriented data which represent sequential runs of pixels on a row. When the rendering is done, it is a relatively simple (and quick) matter to send all the pixels to the LCD, as a block.
With ElitePetite, the active graphical area was modest and roughly square. Battlezone basically fills the screen so I needed support for more than 255 columns. The SparseXL algorithm does this quite compactly be "escaping" the column encoded when required.
The sparse algorithms are monochrome, a representation of "on" pixels with no colour information. But Battlezone is coloured red and green, and has different intensities. LittleZone simplifies the intensity as either solid lines or two different dash patterns. This does increase Sparse memory demands since horizontal runs of pixels are reduced. Colour is restricted to areas on the screen and these are rendered as separate passes. The top area is drawn in red and the lower area in green. The lower area is split into two halves to reduce memory requirements. The lines which constitute the lower view are rendered twice, with the Sparse buffer configured to clip pixels outside the active half. Unfortunately this does cause a little “tearing” in the frames.
There are other simplifications too; I have not implemented the volcano, scanning radar, track animation etc.
But I have added the ability to show the time
- digitally, as the score
- analog, as the radar screen and
- as an Enemy
With the touch screen, its possible to freeze the animation and manually move and turn the tank.
The bulk of the development was done on my laptop using Visual Studio/MFC to hack a simulation of the LCD. A few shim files let me recreate the Arduino IDE environment and share files. But debugging was a lot easier, to put it mildly. The screenshots are taken from that app.
The SparseXL buffer alone uses 1100 bytes of the 2k available RAM, so the sketch compiles on an Uno with dire warnings about memory usage. The concern is that the stack may grow into the area used for program variables etc. However, the sketch includes methods (StackPaint()/StackCheck()) which I have used to verify that there is ~250 bytes of headroom.