Sunday 30 July 2017

Compiling a to-do list

Real Life has been intervening but I have been chipping away regularly at Asteroids.

I've now got compiled sprites for the bulk of the rendering, and all of the erase routines. And it finally runs faster than the arcade game, albeit only about 18% faster atm. I do still have some optimsations to do - but I also have to remove the flicker and add sound.

To generate code for the compiled sprites (and erases) I simply processed my bitmap .asm file in a quick 'n dirty C program. Not the most efficient tool but... old dog, new tricks...

So to explain exactly how my compiled sprites work is actually quite simple. Instead of looking up sprite data in a table and rendering it to the screen in a loop, I have one routine for each and every sprite that simply loads the sprite data into the A register as immediate operands and then writes that to the display using absolute indexed mode, with the X register containing what is effectively the video address of the sprite.

In the case of the IIGS, the bottleneck isn't actually the execution overhead of the loop or the amount of data per se, but rather the number of video access required since these are rather slow. Where the compiled sprites make the most improvement in this case is that they are only writing pixels that are set, unlike an non-discerning loop which writes the entire bounding rectangle, set or not. And with the asteroid sprites in particular, where the pixels are either relatively sparse, or the asteroid itself is often a lot smaller than the bounding rectangle, the improvements can be significant.

Aside from skipping zero-pixels (or rather words of pixels), there's also no need to OR the value $FFFF to the display, so there's another video (read) access saved. And a mate had a good suggestion that I sort the values within each sprite and use Y as a temporary store (where appropriate) to save a few more cycles!

For certain sprites I didn't bother with some optimisations... for characters there's still a look-up table of data, since during the game there's only a few digits on the screen and little savings to be had in the character data itself. And for small sprites I simply erase the entire bounding rectangle since there's only 14 words to write.

So now, instead of look-up tables of sprite data, I have look-up tables of sprite rendering routines. The erase routines are similarly optimised; only those pixels that were set are erased, and of course it's sufficient to simply write $0000 to those words. The down side of course is increased memory usage - quite a bit in fact - and I've just hit the requirement to re-arrange my memory map because of it. Not surprising since up until this point I've left all the arcade RAM, ROM & hardware addresses in their original locations. That should be trivial to change with the 'source code' of course and there's still plenty of space left on the Apple so no danger of running out anytime soon.

Tonight though, before re-arranging the memory map, I thought I'd tackle the 'crash' at the high score entry routine. Turns out it wasn't a crash at all, but rather a combination of a bug on my part, and yet-to-be modified display code on the other; the core core was in fact running perfectly fine.

My rendering routine wasn't setting the start of the display list buffer correctly; when the high score message was being printed the display list exceeded 256 bytes and the MSB of the address incremented. I subsequently set that as the start of the buffer and so it only rendered what was in the 2nd page of the list - the last few words of the message.

Next issue was that I hadn't updated the routine that printed the initials as you entered them, so nothing showed up when changing letters. And finally, to select a letter it was debouncing the hyperspace key; having mapped that only to the Apple II keyboard you could never trigger the selection of a letter. So I mapped it to the 2nd joystick button and it fixed that issue.

So now you can coin up, play a game at (slightly more than) full speed, enter your initials on the high score screen, and start again.

I still have a few niggly bugs. There's an initialisation issue that sometimes results in garbage on the screen and non-zero velocity for the player. And starting a second game you have four lives instead of three. I'm sure they won't be difficult to track down, and possibly even the same bug.

And aside from bugs, there's re-arranging the memory map, adding compiled sprites for the player ship (already generated, I just ran out of space temporarily), adding the 'thrust' pixel, displaying the correct saucer size, and rendering of the exploding player ship. I also need to add special characters for 'underscore' (high score entry) and 'dot' (high score list). Lastly then, remove the flicker, add sound and a main menu screen.

No comments:

Post a Comment