A Proper Vertical Parallax Effect on the Commodore 64?
Ever since I released the first playable demos of my prototype game, Colony, back in the mid 1990s, I have mused on how I could have enhanced the visual qualities of the game.
Specifically, I wondered if the parallaxed landscape could be given a vertical component, as a means of emphasising the sense of space and motion.
Obviously, such features are common in games for more modern platforms, but have never been seen in legacy machines such as the Commodore 64; Ocean's 1986 release, Parallax doesn't count because the entirety of its eponymous parallaxing doesn't extend beyond a simple pattern shift effect - as can be seen in the clip below.
Unremarkable though that parallax effect was by today's visual standards, it was nonetheless enough to build an entire game model around and even name the game after!
Another example from the C64's heyday would be Thunderblade, which demonstrated an extremely crude and somewhat ugly kind of vertical (and slight horizontal) parallax effect:
A much more recent example would be MAH, an unusual game featuring vertical parallax elements
using what appears to be a simple (correct me if I am wrong about that!) vertical pattern shift effect:
It's a slick effect but what I am after is something quite different.
With close to three decades of the demo scene expanding the Commodore 64's capability envelope, maybe it's time to raise the bar on parallax effects too by working a vertical parallax scroll into Parallaxian's landscape so that it dips and rises as the plane climbs or dives.
In other words, let's make Parallaxian's parallax scroller a little more... "16-bit".
HARDWARE OR SOFTWARE?
Upon deciding I had to try to reduce the console-C64 gap through this innovation, the first methodology I thought of was the obvious "go-to"
hardware scroll feature of the VIC-II's notoriously tricky $D011 register.
After all, why bother concocting the charset graphics and associated handling routines for a bloaty software solution when the same effect could be achieved by tickling a register?
That said, I had to be wary of knocking the open top and bottom borders out of kilter, as they rely on $D011 tweaks from within the main game interrupt to stay open.
That initial concern was immediately allayed when I began to "cut code"; $D011 could be modified by the interrupt handlers managing the landscape layers between the top and bottom of the screen without losing the open borders effect.
But... the outcome was mostly hideous: landscape layers shunted out of place and system crashes for no immediately obvious reason; like I said, $D011 doesn't take kindly to being prodded.
However, through lengthy experimentation, I was able to use $D011 alone to vertically scroll the foreground's full-colour scrolling layer (that's the part that has the base and all the little men running around), but it required a sacrifice in the form of the panel below it being reduced by 8 pixels in height (later 16 pixels) to accommodate a buffer space for the vertical scrolling.
There was a snag, however.
The interrupt layering was such that there was only enough space for around 3-4 pixels of vertical scroll in that layer; any more and the machine would crash or the interrupt would stall.
That was never going to suffice; after all, we need the upper layers in the landscape to vertically parallax scroll as well if the effect is to be worthwhile, and that's not going to work if the foreground can only scroll a few pixels vertically.
The only solution for that was to alter the raster trigger values for each handler and to change the size of the foreground layer, making it eat into the distant trees layer above it.
That would mean I could now have a 6 pixel scroll vertical scroll on the foreground before it stalled the interrupt, which was more than enough to convey the vertical motion needed in that layer.
However, the foreground also required an additional interrupt handler, i.e., another raster interrupt layer to create the buffer zone mentioned above, bringing the total in the game engine to a staggering nine.
Or let me put it this way. The game's raster interrupt now does the following via its nine handlers:
- Multiplexes and updates the sprites across 3 screen regions;
- Animates the software sprites aka the little men running around the landscape;
- Sequences the toggleplexing and motions of Sprite #$02 (the afterburner and laser / bomb sprite);
- Polls the joystick for firing the selected weapon;
- Performs the collision detection for the plane's laser hitting enemy sprites;
- Opens the top and bottom borders;
- Dynamically chequerboards the colours (the best way to smoothly mix hues of diverse luminosity on the C64) on the radar display;
- Splits the screen into different zones for background colour, the two multicolours, character bank (using one of either two user-defined graphics sets available) and hi-res;
- Handles the bi-directional multispeed horizontal parallax scrolling and map-feeds, AND...
- Handles a large part of the new vertical parallax scrolling component.
However, after much "panel beating" - my term for any coding process that relies on many iterative trial-and-error sessions - I finally had to concede that the overall desired effect was not going to happen via hardware scrolling alone; some other techniques would also be required because, very early on, it was obvious $D011's vertical hardware scroll was not going to play ball on the other landscape layers.
For the more distant trees at low level (i.e. landscape layer 3) and for the reddish-coloured trees in the foothills (i.e. landscape layer 2), I thought that would entail multiple copies of the char data, offset vertically by one pixel in each iteration, using a fast routine - this time performed outside the game engine interrupt - to switch between the various definitions.
That worked okay (eventually) when I tried it for the low level trees, but I was out of char space for the wooded foothills.
Thankfully, the solution was staring me in the face: switch to another charset for that layer.
AN EXTRA CHARSET? ARE YOU MAD?
Now hear me out.
Before you berate me for the lunacy of finding an extra 2K of RAM just for a non-critical game effect, let me explain that I am planning on doing so much more with that extra charset.
It has to hold additional definitions for the foreground landscape to accommodate a major game feature, namely, the battle-damaged trees and other foreground objects that succumb to the rigours of the conflict raging above and around them.
Recall how I described this in the Parallaxian Game Concept post?
Well, this is the how to compliment the what of that game feature.
YET ANOTHER TECHNIQUE ADDED
So much for the bottom 3 landscape layers; what of the not-so-small matter of vertically scrolling the distant mountains (landscape layer 1)?
For that, I was able to use another cool C64 trick, so beloved of the demo scene (and used in the "get ready" screen of Mayhem in Monsterland).
Gentlemen, I refer, of course, to FLD.
That's Flexible Line Distance, a simple technique that keeps the VIC-II from drawing what it's "supposed" to on-screen until the next raster line (or however many raster lines down the screen you want to delay the rendering process).
In Parallaxian, this is executed within the very first raster interrupt handler, way up above the visible part of the screen, and it affects landscape layers 1 (the mountains) and 2 (the wooded foothills).
So in actuality, the wooded foothills use two methods for their vertical scrolling: FLD + character bank switching.
SUMMARY OF THE METHODOLOGIES
So, to recap, we now have 4 different techniques at play here:
- $D011 hardware scroll on the foreground layer (aka layer 4);
- User-defined graphics definition rotation on the distant low level trees layer (aka layer 3);
- Charset definition change via bank switching on the forested foothills layer (aka layer 2);
- FLD scroll on the distant mountains (aka layer 1) AND on layer 2.
A LITTLE PROBLEM: THOSE NON-STANDARD COLOURS
Remember in the Luma-Driven Graphics article how I said that when using ALM (the Alternating Line Method) to attain non-standard colours, the resultant new colour will exhibit
a bias in favour of the first constituent standard colour in the alternating lines?
Well, by vertically scrolling any screen region occupied by ALM, you inadvertently trigger an eye-jarring effect caused by this bias.
That meant, for example, the murky green of the grass behind the foreground trees was alternating between a much more pinkish green and said murky green with each vertical pixel the foreground scrolled.
Of course, the solution was to switch char banks with every vertical pixel scrolled, to maintain the integrity of the non-standard colours, which is what I ended up doing.
Laborious, fiddly, frustrating but utterly necessary to the final effect because, as I have said before, we're going for finesse here, something to make the game more "16-bit", so the inconvenience of the matter doesn't come into the equation.
WAS THE EFFECT WORTH IT?
Only time and the verdict of the finished game's players and reviewers can say, but personally, I love it and feel that another step in closing the "console gap" has been taken.
One small vertical scroll for this game, but a giant leap for the Commodore 64 gaming scene! (I hope).
In the meantime, check out the clip below and let me know what you think - be sure to set the YouTube Settings to maximum quality!
UPDATE: 29th May 2019
Since this article was originally published, the vertical parallax has been expanded further by 2 extra raster lines in the foreground, which makes a huge difference to the prototype effect, thanks to some major savings in raster time brought about by refactoring the interrupt code for extra speed. It may even be possible to expand it beyond 8 pixels, if the hardware limitations can be stretched further... time will tell.
If you liked this article and want to know when the next one is posted, kindly consider joining my 100% spam-free, nag-free Newsletter.
Anything you receive from me will be cool and interesting - especially if you're a C64 gamer or coder!
In the meantime, feel free to use the handy buttons on this page to share it on social media, if that's your thing!
Simmo (12th March 2019)
The seamless combination of advanced techniques you've implemented here is making my jaw drop now in 2019.
I can't imagine how my 1989 self would have reacted to this display of technical and artistic mastery.
(Actually I probably would have insisted it wasn't possible on a stock c64 and then been gobsmacked into stunned silence when proven wrong, only to then do a ridiculous about-face and naively wonder why more c64 games don't boast such features.)
Simmo, I can only say thank you for such praise - I'm not worthy!
Certainly, from my perspective, I have been hoping that other game developers would see merit in the idea of pushing the boundaries for the sake of creative excellence and, even more so, for the betterment of the player experience.
Cristian (12th June 2019)
Just outstanding. Really Jon! Thanks for that abuse of excellent techniques and tricks. Thanks for the love you are putting into it. I loved that article.
I'm glad you liked it and if all goes to plan, the effect will be expanded further and refined for the final game.
I must admit, I was thinking about this for years, long before I ever tried to find a coding solution for it, so it's very much a passion for me.
Anyway, thanks again for your comment!
Swedish Pete (23rd June 2019)
Please keep up the positive spirit, and keep the nay-sayers at bay! Can't wait to see what code you're going to cook - if the prototype shown so far represents the final game, then Parallaxian will push the limit of what a quality Commodore 64/128 release should be like!
Thank you for the kind words of encouragment - it means a lot to me!
I think the nay-sayers initially failed to understand / properly read what I was talking about and then, to save face, tried to argue their way out of it.
I still get hate mail from some of them... It's very childish stuff but it just gets binned because my website is primarily about promoting the game and hopefully encouraging others to raise standards.
Regarding code, the next article will probably be about a cool way to use the NMI as a lightweight supplement to the main raster interrupt system in the game, as I think it's a nice method for saving cycle time on a game's play area that requires a lot of interrupt-based services (e.g. sprite plexing, SFX, etc.)
So, thanks once more for your words of support and the lift it gave my morale!
Leave a Comment
Comments are moderated to prevent spam and emails are only required to filter basic spambots; such emails are neither harvested by me nor displayed on this website.