Deep Winter Tech Demo
First published on:
If you've been reading this blog, you probably already know that in addition to developing
the ambitious Parallaxian shoot-and-bomb-'em-up for the Commodore 64, I am also working on its sequel,
Deep Winter, a survival-in-the-wilderness game for the same platform.
Well, when I say working on it, I mean the occasional, once-in-a-blue-moon glance at the project, as it's only really possible to focus on one major coding project at a time.
That said, due to popular demand (okay, one or two requests!), I promised a tech demo for the new game around this time and, as events would transpire, in developing some routines for Parallaxian's title page, I found myself sucked into an all-screen sprite plexor model that in turn quickly drew me into coding a prototype snowfield effect for Deep Winter, an effect that had its conceptual origins back in the mid 1990s when I considered it for Colony (Parallaxian's original name).
However, while I hated suspending work on Parallaxian, the plus side was - apart from creating the tech demo materials for Deep Winter - the emergence of a whole suite of more efficient coding methods for the NMI plexing system used on both games, plus the inadvertent discovery of the root of an annoying little bug on Parallaxian that had been on my "to-do" list for quite a while.
So, it's fair to say that that this coding diversion it wasn't a total loss to developing Parallaxian!
Both of my games in development are predicated on the design approach described in detail in my
Luma-Driven Graphics blog article, which, to recap, emphasises PAL-based colour mixing using both the old
methods from the legacy era and some newer ones not seen outside the demo scene (at least to the best of my knowledge).
A further principle in that approach is to reserve black for foreground objects alone or as the predominant colour for player and enemy sprites due to the Commodore 64's limitations in respect of luminances within its palette, the aim being to emphasise visibility at all times, rather than suffer the common lack of contrast that plagues many in-game art concepts on the system.
A third feature of Luma-Driven Graphics (LDG) is the wilful avoidance of discernible stippling (or dithering, as the de rigueur term seems to be these days), which means artwork design for LDG must avail of other expedients in creating blends (optimised for CRT display), the idea being we want to move away from the blocky, "8-bit" look of traditional ways of designing for the C64, seeking a more "16-bit" feel instead.
Parallaxian has been designed and refined based on those principles, but with Deep Winter I wanted to take it a little step further to impart extra freshness or uniqueness to it,
leading to an almost total ban on Multi-Colour Mode so that resolution on slopes is tighter, smoother and less
The style of the art concept is largely based on 1920s-1930s period art deco, specifically ski resort posters from that time, since it's a style that lends itself well to limited colour palettes.
As with Parallaxian, the upper and lower borders are open on Deep Winter to enhance the sense of space and provide extra screen real estate for icons, health info, etc., and the graphics are mostly either hi-res or Extended Colour Mode, with only a tiny sliver of MCM at the bottom of the screen, just above the icons (although that too is earmarked for replacement with ECM).
Finally, if you look at the two demo clips, you will note the striking difference between the monotones of the snowstorm effect and the wintry sunlit hues of the crisp, freezing morning scene.
The obvious aim with that is to impart contrast in mood and atmosphere, and this should also apply to the planned afternoon, evening, night and transitional schemes.
PS: There is a tiny but super easy-to-fix little mistake in the design... please let me know if you can spot it!
1 Pixel-per-Flake Full-Screen Snowfield Effect Overlaid on Parallax Scrolling Landscape
Back in the C64's Hay Day, I was very much smitten by the falling snow effect in Creatures 2, and wished
to be able to have a blizzard effect overlaid on a parallaxed scrolling landscape.
Obviously, that was quite a wish, given the technical challenges such an effect would entail, but I had the kernel of a method for making it happen, long before I had the coding abilities to attempt it.
Of course, creating a survival-based game and calling it Deep Winter demands that, at some point, the player be subjected to life-threatening snowstorms, thus reinforcing the imperative for a plausible falling snow effect to become an important feature of the gaming experience.
I go into greater technical detail on the effect further below, but for now may it suffice to say it is based on a screen-refresh optical illusion in which multiplexed sprites are alternated in their horizontal positionings to project a "canvas" on which falling snowflakes are rendered, heavily based on the Toggle-plex concept.
The effect wasn't exactly trivial to achieve (and again, the technical explanation will reveal why), but works beautifully and corroborates my 25 year old concept... hopefully I won't take a quarter of a century to bring any further new ideas to life!
NOTE: It's proven very hard to find ANY way to reproduce the quality online of the original VICE clip without effect-spoiling banding, so for now we're stuck with this imperfect rendition until such times as I am ready to release a downloadable .prg file... On a real C64, this is not a problem, which is the most important thing!
Planned Gameplay Elements
As I have mentioned elsewhere, the planned gameplay is loosely similar to the amazing Limbo 64 demo:
However, unlike Limbo 64, the player would have the freedom to travel out from his cabin in either direction (left or right), seeking resources to stay alive and expand his
The player would also be able to hunt wild game, lay traps, gather firewood, seek shelter during storms, monitor communications between other survivalists in the mountains and engage in counter sniper actions.
The principal aim, however, is to survive until the spring, so body temperature, morale, hydration, weather, tiredness, food and shelter are the constant considerations in the game world.
Straight off the bat I have to tell you, none of the tech demo effects - snowfield or trees and cabin - would have been possible without the
Non-Maskable Interrupt (NMI), that rarely used (in games) but ultra powerful feature of the C64.
But surely, you will say, it could all be done using raster IRQs (IRSTs)?
Well, no, or at least, not as easily, because the great thing about the NMI is it takes priority over the IRST (and the IRST's non-raster-triggered form, the IRQ), which in plainest terms means the NMI may interrupt code being executed by the IRST/IRQ and perform its own tasks before exiting, allowing the IRST to carry on doing what it was doing without stalling or worse, causing the system to crash - as long as the NMI tasks are completed quickly enough to leave raster time for the IRST handler to finish its own tasks before it's time to trigger another IRST handler.
In other words, the NMI is an interrupt that can interrupt other interrupts.
That means you can use the IRST to split up the screen into scroll zones for parallax scrolling, making sure no zone executes its own scroll code (as that will cause jitter / tearing effects), and then use the NMI to momentarily suspend the CPU-heavy character scroll code being executed by the IRST to perform, say, critical sprite plexing then RTI-ing to allow the scroll code in the IRST to resume (in the tech demo clips, the scroll code is not even optimised beyond unrolled loops... okay, it is "staggered" so that no two screen zones perform a full char scroll on the same frame, but it's not compressed using bank-switching).
Trying to achieve the same results with the IRST alone would entail breaking up the scroll code and distributing it all over the screen, but it would still be impossible to get the ultra tight timings needed for the plexing done as well, at least in terms of the on-screen effects produced by the Deep Winter tech demos.
So... Although I'm obviously speaking in very abstract and overly simplified terms here, hopefully you get the idea of how versatile the NMI is for plexing sprites over multi-zoned landscapes, as elsewhere demonstrated by the "swarm effect" in my Parallaxian "Stress Test" video (below).
The other thing of note is that in the Deep Winter tech demo code, even the IRSTs (not just the NMIs) are stabilised using a timer, specifically timer B on CIA #2, which is the chip that
controls the NMI (although either timer from CIA #1, which controls non-raster IRQs, could have been used instead).
Well, when I say "stabilised", I mean some instances are, because, as experienced coders will know, you don't have to stabilise interrupts for every task performed by them.
Screen splits, where background colours change? Yes, it would be normal to stabilise those, but plexing sprites? Not always necessary, or not necessary at all unless - perhaps - you're doing a colour split as well with the same interrupt.
So here we have the occasional NMI handler stabilised using the aforementioned timer, and the occasional IRST handler likewise stabilised.
In the Deep Winter code, sprite pointers must be written as soon as possible after each plexing NMI fires, so the standard "stack method" of recording and retrieving registers (PHA, TXA, PHA, TYA, PHA, recovered using PLA, TAY, PLA, TAX, PLA) is ditched in favour of STA ZPHOLDA, STX ZPHOLDX and STY ZPHOLDY, where ZPHOLDA are Zero Page variables. Hence:
|; Handler's main tasks begin here.|
|; When handler's main tasks end, we reset vectors here and all the other end-of-interrupt standard tasks until, finally, we recover the registers from the stack.|
Is replaced with:
|; Handler's main tasks begin here.|
|; When handler's main tasks end, we reset vectors here and all the other end-of-interrupt standard tasks until, finally, we recover the registers from the ZERO PAGE holders.|
To be more precise, most NMI handlers in the Deep Winter code don't even do that; where possible, for speed they use only one register throughout the entire handler, so we start off with just a single storing event, for example, STX ZPHOLDX, and then go straight into the sprite pointer-setting without any need to stabilise the interrupt:
|; Handler's main tasks begin here.|
|; When handler's main tasks end, we reset vectors here and all the other end-of-interrupt standard tasks until, finally, we restore the register to its state when the NMI handler started.|
However, because the IRST handlers are being interrupted by the NMI handlers, they use the traditional stack method or a cropped version thereof where, say, only one register (e.g. the Accumulator) is stacked and the other two are ignored if they aren't used in the handler code:
|IRST2||PHA|| - Push the Accumulator's start-of-interrupt value onto the Stack|
|STA $D016|| Set hardware scroll x-position|
|STA $D012|| Set raster line trigger point for next IRST handler|
|ASL $D019|| Acknowledge IRQ|
|PLA|| - Recover the Accumulator's start-of-interrupt value from the Stack|
Of course, all of the above would make more sense with a far more forensic breakdowns of the processes, which I intend providing in the major NMI article in the works for subscribers to this blog, but for now I hope this has proven an appetiser or primer of sorts for that article and maybe, if you're a coder, it has sparked your interest in the NMI more than hitherto.
FINAL TECHNICAL NOTES: I just wanted to link out to this great technical article on sprite multiplexing, as I consulted it many times during the tech demo coding. Perhaps some people imagine coders have encyclopaedic knowledge of the system, but the reality is we don't and we often need to revisit things we were previously adept at. This is why the Commodore 64 Programmer's Reference Guide is, in fact, called a reference guide and not the "Read-It-Once-And-Know-It-Forever Guide"!
I also somewhat expect some smarty pants to pull me on using ASL $D019 for acknowledging the interrupt in the code snippet above... It may not be the "proper" way to do it as it's considered more of a "hack" that won't work on non-native hardware, but it's fine for real machines and VICE so if I decide to make my games compatible with, say, the C65, I would replace it with the non-hack method.
With the underlying NMI-powered "plex-tech" proven and the art concept laregly settled, the design and code infrastructure are now in place for the game to be written.
Of course, the player's sprite and many other things are yet to be designed but the important point is that there is raster time aplenty to handle all that is envisaged for the game.
In other words, now that we have a completed proof of concept I can focus on finishing Parallaxian in the comforting knowledge that its planned sequel already has a head start and should require much less time to develop.