Thursday, 4 June 2020

Vertical monitors and self-erasing sprites

In search of low-hanging fruit I decided to fix the logic for detecting the edges of the screen so that the invaders reverse direction at the right point.

I decided the quickest and most reliable process was trial-and-error. I ultimately ended up with the right magic numbers in the code; whether it was the quickest is up for debate. FTR invaders take 8 steps to the right from the starting position, and then 17 steps across thereafter.

However this fix merely revealed another complexity and subsequent shortcoming in the rotation code as-is. In short, when the invaders reach either end of the screen and drop down a line, the previous line is not erased. That had me scratching my head for a while because there is no code to erase an invader.

The further I get in this process, the more I realise how the code is designed around and optimised for a vertical display. Invaders, for example, are always byte-aligned and occupy a single column of video memory, making rendering simple and fast. Contrast that to the rotated case, where they can be shifted across 3 columns and occupy 8 rows.

The generic sprite rendering routine, however, handles non-byte-aligned sprites using the hardware shifter on the board. Thus 8-pixel-high sprites (such as invaders) are potentially able to be shifted and rendered across 2 bytes (columns). But since they're always byte-aligned, the 2nd byte (column) out of the shifter is always zero, effectively wiping the 8 pixels above the invader. This is why there's more than an 8-pixel gap above/below invaders, and why they move down by exactly 8 pixels when they hit the edges. And so when the invader drops down, it erases the old copy.

I also mentioned in the previous post that the invaders also wipe themselves as they march left/right, via 2 blank pixels on either side of the sprite. Together this means invaders never require erasing as they move.

But none of this works when you rotate the screen.

I've thought about it and on first glance it seems rather complicated, if not impossible, to incorporate this into a generic sprite rendering routine without introducing, for example, more graphics data in the form of masks. However I realised tonight that taking this approach is just making things hard for myself.

There's only a handful of objects in the game and rather than try to shoe-horn complicated logic into a generic routine, it would be far simpler - and execute faster - to simply have a rendering routine for each specific object. In fact it'll likely be faster than what I have there now, as I can optimise the order in which bytes are rendered as well.

So my next task is to write a rendering routine specifically for the invaders.

I also saw the saucer/ufo for the first time today. Aside from similar issues to the invaders and the laser base, it looks right! I guess that's not too unexpected; after all, the game should run perfectly as long as the rendering routines aren't actually trashing anything.

No comments:

Post a Comment