Technical insights and a piece of news
QUOD INIT EXIT IIo has been in the works for about 9 years, and that is on top of the foundations laid by QUOD INIT EXIT IIm (and, even before that, by the ending of MAH).
Lately I explained two tech-minded friends of mine a reason (which adds to real life and other projects) of such enormous development time. I thought you might be interested in hearing the same story.
Since my friends did not know how the Commodore 64 (C64) works, first I had to provide them with some technical details. Therefore, the first part of the text below deals with the Extended Background Color Mode (EBCM). Who already knows how it works can skip such part altogether. I tried to make it as accessible as possible, but still the understanding of bits, bytes, RAM, etc. is required.
QUOD INIT EXIT IIo uses one of the C64's native graphics modes called EBCM, which works as follows:
* the screen consists in a matrix (i.e. grid) made visually of 40 columns and 25 rows of characters (i.e. squares), for a total of 1000 characters;
* each character is a 2 color bitmap (i.e. another kind of grid) of 8x8 high resolution pixels (i.e. bits);
* the programmer-defined characters (commonly referred to as "charset") are stored at a programmable address in RAM;
* each character shown on the screen has 1 foreground color (the color of the "on" pixels in the character) chosen from the 16 colors of the palette;
* each character shown on the screen has 1 background color (the color of the "off" pixels in the character) chosen from 4 colors of the palette;
* the 4 background colors apply to the whole screen; the programmer chooses them from the 16 colors of the palette; note: these colors can be changed dynamically by the CPU any time (but that requires extra CPU work);
* the matrix, from a programming point of view, is a sequential array of 40x25 = 1000 bytes residing in RAM;
* each byte in the matrix dictactes which character shows in the corresponding position on the screen and its background color; more precisely, the low 6 bits of the byte are the index of the character to show and the high 2 bits are the index of the background color; for example, the byte 10111001 (binary notation) indicates that the correponding character is the 57th (as binary 111001 = 57) in the charset and that the background color is the number 2 (as binary 10 = 2); note: given that only 6 bits are used to indicate the characters indexes, there can be only 2^6 = 64 different characters, unless the CPU changes dynamically the charset address (but that requires extra CPU work and RAM);
* the matrix address (i.e. where the first byte of the matrix is located in RAM) is programmable; therefore, the address can be changed to display different areas of the RAM; however, given that the address must be dividable by 1024, scrolling cannot be achieved by simply changing the address, as the smallest change is of 1024 bytes, which are more than the size of the matrix;
* the foreground colors of the characters on the screen are defined by the values in the COLOR RAM, an additional RAM that starts at the fixed address $d800 and which is another sequential array of 40x25 = 1000 items; each item is a value between 0 and 15 and indicates the index of the foreground color of the corresponding character on the screen; for example, if the first item of the COLOR RAM were set to 1 (the index of the white color), then the top-left character "on" pixels would look white; note: although the COLOR RAM is addressed by bytes, each item is made of just 4 bits (which suffice to hold all the 16 values from 0 to 15, as 2^4 = 16);
* to achieve the scrolling, the matrix is visually reduced to 38 columns and 24 rows of characters and only 39 columns need to be handled.
Now it is possible to explain the reason mentioned at the beginning. Reason that basically boils down to the fact that designing the graphics and the zones (i.e. levels) is enormously demanding.
The first difficulty comes from the fact that the characters must be designed keeping in mind that each on-screen character can be painted only in 2 colors, one of which must be chosen from a set of 4 colors shared by all the characters.
This is made worse by the fact that there are only 64 different characters to play with.
There limitations are intrinsic to EBCM and, I guess, are the reason why such mode is not frequently used.
Then, the game complicates things further.
Premise: the game maps are based on single characters, i.e. they are matrices of bytes that indicate which characters to draw on the screen and how to do it (more details about the maps are given further below).
One of the main technical features of the game is that the scrolling is "unlimited": it is possible to display any portion of the map any time, in full screen, with a complete update of the colors and at a steady 50 fps.
Given that, as explained above, scrolling cannot be achieved by means of a simple pointers update, the only solution is to rewrite the whole screen matrix and the whole COLOR RAM. Since the number of on-screen characters is 39x25 = 975, 975*2 = 1950 bytes must be rewritten. But with what? With the data coming from the map. So, in theory, other 975*2 = 1950 bytes should also be read as well. Unfortunately, there are not enough CPU cycles in a frame: even with the most efficient unrolled loop, the reads take (at least) 5 cycles and the writes take 4 cycles, so 1950*5+1950*4 = 17500 cycles would be needed, but in a PAL frame the CPU has only 63*312-40*25-500=18156 cycles (500 is, for simplicity, a rounded estimate of the cycles usually taken by the game sprites), so updating the screen matrix and the COLOR RAM entirely would consume almost all the cycles, leaving the CPU no time (18156-17500 = 656 cycles) for all the other tasks (executing the control instructions of the unrolled loop, executing the game logic, managing the sprites, playing music, etc.). Note: on NTSC the available cycles are even less and do not allow the game to run correctly, despite what explained below.
The trick adopted by the game is to write the same data to both the screen matrix and the COLOR RAM, thus halving the number of reads. Therefore, the cycles taken are "just" 1950*5/2+1950*4 = 12675. But those are not enough, as the unrolled loop needs also some additional control instructions which cost 2022 cycles (a trifle more than 2 cycles per character). In total, the screen update takes 12675+2022 = 14697 cycles, i.e. about 81% of the available ones. This allows the game to actually do something beyond updating the screen graphics (although it is still quite tough to fit everything is the little remaining time). (Side note: given that there is no double buffering, the game updates the screen matrix and COLOR RAM by means of an 8.5 kB unrolled loop that races the beam, which succeeds in avoiding any visual tearing precisely because it takes less than a frame time, even if it gets interrupted a couple of times by sprites multiplexing.)
The trick exploits the fact that the COLOR RAM items are only 4-bit, so that the upper 4 bits of the bytes written to them are ignored. It entails, however, that each byte in a map indicates, besides the character index and the background color, also the foreground color. This ties each specific character to a specific foreground color, thus greatly reducing the freedom of choice (which, as explained above, is already limited by how EBCM works). In practice, a charset always comprises 4 characters for each of the palette's 16 colors (so, for example, it is not possible to have 5 different characters drawn in red as foreground color).
But there is more.
The game maps are huge: they are 256 columns (i.e. 2048 pixels) wide and 114 to 120 rows (912 to 960 pixels) tall. So, the smallest map takes 256*114 = 29184 bytes and the biggest one takes 256*120 = 30720 bytes. In practice, almost half of the C64 RAM is occupied by the map.
Obviously, the game needs also some metadata to indicate the properties of the characters. Each character can
* be neutral,
* be a potty,
* be a switch,
* be a checkpoint,
* be a portal,
* be dangerous,
* be chain-removable,
* block Zampo in all directions,
* stop Zampo from falling,
* have zone-specific effects when Zampo steps on it (e.g. giving Zampo an upward push in case of trampolines),
* have zone-specific effects when Zampo enters it (e.g. opening a chest).
Moreover, characters also indicate whether the Zampo colors should be normal, dimmed or dark.
There cannot be a parallel metadata map, otherwise the two maps would occupy the RAM almost entirely.
The solution is that each byte in the map is also the index in a 256 table of another byte that condenses all the properties listed above.
In all, each byte in the map indicates the corresponding character, foreground color, background color and logical properties. And, on top of everything, some characters are animated (redrawn by the CPU in real time) or used for parallax.
Due to the scarcity of different characters, it is necessary to design them so that they can be reused in multiple contexts, in order to achieve an acceptable graphical variety. But the freedom of choice is further reduced by connection to the properties (for example, a character might look great as an ornamental tile, but maybe it also has the function of changing the Zampo sprites priority so that Zampo is drawn behind the characters, and that would not look correct in that secondary context; so, either the character is not reused as a decoration or zone-specific code is written to handle that particular situation, if possible at all - but that, needless to say, steals some of those few CPU cycles and RAM bytes left).
It is possible to change the charset dynamically (by changing the charset address so that it points to a different area of the RAM) depending on where Zampo is to increase the number of available characters (and actually the FUN PARK zone does it to have the graphics at the very beginning of the map recall the graphics of the first QUOD INIT EXIT game), but that requires:
* more RAM for the charsets;
* designing the area of the map that shows on the screen when the charset switch happens so that it uses only the characters shared by the previous and the current charset (otherwise the graphics would look suddenly garbled; this also means that the number of total different characters is necessarily less than 64*<number of charsets>);
* an additional properties table for each additional charset;
* the self-modification of all the pieces of code that access the properties table (and, no, centralizing the accesses in a subroutine is not possible as the required jsr+rts instructions would steal too many cycles).
Also, it is possible to change the background colors dynamically (the CLIFFS zone does it), but that also requires special care when laying out the map and designing the characters, and, of course, additional code.
Making choices is extremely complicated and often requires to undo the previous ones and/or to rearrange/redesign the charset/map and/or to update/rewrite the zone-specific code. The choices made for the characters affect the map layout and vice versa, and the same goes for the gameplay. Code, graphics, map layout and gameplay are so intertwined that, I guess, it would be next to impossible to have multiple persons work on them.
It must be mentioned also that coming up with new graphical and gameplay ideas (which can actually be implemented within the technical contraints) has become harder and harder over time. The sheer size alone of the maps challenged my fantasy in order not too look monotonous.
Overall, creating the zones has been very fun and gratifying, but also extremely demanding.
After making the TOWERS zone (the one inspired by Impossible Mission II) I was exhausted. That zone amplified the design difficulty due to depth dimension: even if it is fake, it still it requires to be taken care of, especially to simplify the player's life (for example, it was necessary to write some code to aid the landing of Zampo on platforms, as the eye might be fooled by the graphics).
Once I finished that zone, excited by the fact that only one zone was left to do, I immediately started to work on that last zone, but after a week I was totally blocked, as I was unable to think of something new and cool. Therefore, I decided to take a break and to return to the Amiga for a little while (and so I made this game).
Technical babble aside, you might have noticed the little piece of news in the paragraph above: the last zone (which is actually the one that opens the game) is in the works! The additional piece of news is that I plan to restart working on it soon.
I just cannot wait for the game to be finally finished. It has been quite a ride and the goal no longer looks infinitely distant...
QUOD INIT EXIT IIo
Alternative free-scrolling platformer [C64]
Status | In development |
Author | RETREAM |
Genre | Platformer |
Tags | 2D, 8-Bit, Colorful, Commodore 64, Cute, jumping, Pixel Art, Puzzle-Platformer, Retro, Sprites |
Languages | English |
More posts
- Progress report 11Mar 05, 2025
- Progress report 10Dec 28, 2024
- Progress report 9Oct 29, 2024
- HistoryJun 24, 2023
- Preview 6May 12, 2023
- Progress report 8May 05, 2023
- Progress report 7Apr 03, 2023
- Progress report 6Oct 10, 2022
- Progress report 5Sep 18, 2022
Leave a comment
Log in with itch.io to leave a comment.