Continuing from part 2 where finished by getting the initial game screen shown. In the meantime I have made it to a playable version of the game.
This time I won’t be showing of a lot of code listings and so on, instead I will try to walk through the process I have been through, getting the game to function correctly.
As I now had the screen ready to start showing mazes, I needed to figure out how to store, retrieve and draw the mazes on the screen. I knew that i wanted the mazes to be stored within the assembler file, for now, to keep compiling as simple as possible. I also knew that a maze is simply a sequence of walls and spaces.
This made it obvious that a maze could be represented with bits. In ACME assembler, a !byte can be defined as a decimal number, a hexadecimal number or a binary number.
!byte 127 ; Decimal number !byte $FE ; Hexadecimal number !byte %11100110 ; Binary number !byte %#..#.##. ; Also binary number
As you can see from above, a binary value can be represented with ones and zeros or with hashes and dots. The latter form makes it easy to ‘draw’ a maze directly in the code.
!byte %........,%..###### !byte %........,%.####### !byte %#.......,%.####### !byte %#.......,%######## !byte %##......,%######## !byte %##.....#,%######## !byte %###....#,%######## !byte %###...##,%######## !byte %####..##,%######## !byte %####.###,%########
The only drawback is that for every 8 bits, I need to define a new byte which makes it a bit harder to see the shape of the maze. I did, however, just ignore the size of bytes when ‘drawing’ the mazes in code. When I had finished creating a maze, I went back and got the bits divided into groups of eight bits.
In order for the code to be able to take the bytes in memory and turn them into mazes on the screen, more information is needed. We need to know the width and height of the maze as well as which coordinates the player starts from.
So each maze needs a header that tells us the width, height and start coordinates. But I also need to know the complete size, in memory, of the maze. The reason for this is that the mazes are just a sequence of bytes in memory and in order to get from one maze in memory to the next, we need to know the relative placement in memory. The final maze header ended up like this:
!byte 25 ; Size of maze in memory !byte 10 ; Width of maze !byte 10 ; Height of maze !byte 0,1 ; Zero based start coordinate
If you look at the maze and header above you will see that the maze is 10 lines of 2 bytes = 20 bytes and the header is a total of 5 bytes. So size of maze in memory is 25 as it says in the header.
Now the code is able to find any maze as long as it know where the first maze is located in memory. If I want to find the next maze in memory, I simply add the value of the first byte in the maze to the current memory location and I am at the beginning of the next maze. The first maze will ofcourse have a label so that the code knows where to find the mazes.
When the correct maze is found, it is simply a matter of shifting through the bits in the maze data ensuring to switch bytes and lines according to the width and height of the maze. For each zero-bit a space is drawn on the screen and every one-bit is just discarded as the screen is already filled with ‘wall’
Finally when the maze is drawn on the screen, it is a matter of placing the cursor on the right coordinates in the maze. It was actually easier to write the code than I had anticipaded, although it did take a bit of fiddling around before I got the counters of bits and bytes to behave as I wanted them to.
In the beginning, I just had a constant for the color of the cursor and trail, but I knew that I wanted the color to change between mazes. I manged to find some code that could help generate a pseudo random number and with that I was able to find a ‘random’ color each time a new maze is shown.
Next I needed to be able to move the cursor dependant on the users inputs. The way the game works is, when a direction has been chosen, the cursor will travel in that direction until it reaches a wall. So it is a matter of waiting for the user input and then moving the cursor accordingly.
My plan was to read the screen memory to figure out if the cursor could move in the direction the user had chosen. This turned out to be a bit more complicated then I had initially thought. Because of the very volatile state of the VERA graphics chip, I did not want to rely on talking directly to the screen memory. Instead I wanted to continue using KERNAL calls.
Normally the screen is write-only, but it is possible to use KERNAL calls to open a handle to the screen that is read-only. In this way I was able to move the cursor to a specific coordinate and read the character that is stored there. This is very slow, but fortunately it is fast enough for my purpose.
The cursor will keep ‘touching’ blank spaces until a wall is reached. When a wall is reached, the cursor will stop and the game waits for the user to indicate a new direction. When all blank spaces have been ‘touched’ by the cursor, the maze is completed.
Once I had the functions for reading characters from screen it was very simple to create the game-loop of waiting for input and acting accordingly.
Lastly the cursor was actually moving a bit too fast so I needed to slow it down. I created a function that sets the timer to 0 and loops until the timer has reached 3. These increments are called jiffies and the timer does 60 jiffies for every second. This means that my delay is 3/60 or 1/20 of a second. This delay is between each move of the cursor and I feel it works well.
When I started writing this game, the emulator and ROM for the Commander X16 was at version R32. At the time of writing this we are at version R34 and a lot have changed.
A lot of zero page memory has been freed for use by assembler and basic programs. The SWAPPER function which was originally taken from the C128 KERNAL API and switched between 40 and 80 column mode has been replaced with the CX16 SCRMOD KERNAL API which does not work in the same way.
Several other small things have changed as well which is why I decided not to dump a lot of source code in this post as it will most likely be out-dated by some point and I do not want to have to keep coming back to these blog posts to update code and comments.
Instead I have made my source code available on github and there, I will try to maintain the code and ensure it follows the different versions of emulator and ROM.
I encourage anyone to reach out to me with comments and suggestions as well as any questions there might be. I will be happy to answer any and all questions about the source code and my process of developing this game.