More Isometric Fun with Scrolling on the ZX81
A more complex isometric playfield you can move around in.
My frist isometric test was with a static background. Although that works well, it limits the size of the playfield. Thus, I decided to expand the playfield and scroll it around the player instead. It ended up being a lot more complex than I expected.
# Giving it a scroll.
To get this working, I really had to rethink a few things. The first was to build a playfield that you could move around it. My initial version was focused on getting the player to move around the new world.
To make that happen, I needed to create a world to move around in. This became a simple 10 by 10 array that I could set to 1 or 0 (block or no block). This would act as the basis for what to display on screen. Sticking with much of the original code, no optimizations here, I decided to reuse playfield. This let much of the original program remain the same.
To make the program function, then, I moved the display routine into a get key routine. This is similar to what I'm doing in Gem Quest. If the player doesn't move, the delay kicks in and repaints the screen. If the player moves, it sets a variable and then allows the screen to scroll. At a high level, things look like this:
main_loop:
call set_playfield ; sets up playfield to display
call get_key ; wait routine that gets key and prints display
call check_move ; check if player's move
jr main_loop ; rinse and repeat
# Adding a mask of sorts.
While I was at it, I added in some black blocks to make it easier to verify my code. Doing so, I realized I had to deal with a few more cases where I needed to mask the blocks. I ended up generating those routines so I could call them from different routines. It is a bit brutish, but works.
isotest [2022-12-21 12:52:07] by Steven Reid, on Flickr
With the fix in place for the blocks, I found the player images weren’t masking correctly. That required added more masking that I hoped I could get away without. But the final result looks good enough. In this screenshot, you can see both pieces and how they look with the two colored blocks.
isotest [2022-12-21 12:52:19] by Steven Reid, on Flickr
# Cleaning up the scrolling.
Although I had it working, I decided to redo the math for how i was setting the playfield. I wanted to use common coordinates for testing. To do that, I created a lookup table to decide what part of the world to display. This let me treat the world array as a regular array, but then display in the isometric display.
Sadly, doing so was a pain to troubleshoot. I kept running into artifacts. My math was off in a few places causing overwrite in the buffer. To confirm, I added a border to help me better visualize things. Once I fixed the errors, I could move around the display as expected.
isotest [2022-12-22 09:25:14] by Steven Reid, on Flickr
This allowed me to easily test player location using simple math. The more more complex isometric display was only done between moves. This kept the display speed acceptable. The final loop code looks like this:
call print_borders ; print a little border around things
main_loop:
call set_stuff ; puts any pieces on the board
call set_playfield ; sets up playfield to display
call get_key ; wait routine that gets key and prints display
call check_move ; check if player's move
jr main_loop ; rinse and repeat
In testing, though, I still noticed a few artifacts. Specially things like holes seemed to drop too early or empty drops where there really was a block. To compensate, I ended up expanding the playfield from a 3x7 array to a 4x9 array. I then adjusted the display size a bit to hide any remaining artifacts.
Although this impacted the display speed a little bit, it ultimately looks a lot better. I think it is good enough for whatever I might use it for. I can always adjust later. The final test looks smooth and buttery.
isotest [2022-12-22 09:51:32] by Steven Reid, on Flickr
# What's next?
Now, the interesting part of all this is that get key routine. Because it refreshes the display each delay, I could easily add animations to the display. The double buffer hides any delay in prints, so I can get pretty complex routines (although at the cost of memory).
Now other games create more of a square turned side ways. I thought about doing that, which should let me reduce some of the playfield at the cost of a more complex copy routine. The game I choose would probably dictate how that would look.
For now, though, I like the look and speed. I just need to narrow down a theme and start coding some game logic. An exercise for another day.