C64 Character Modes

Introduction.

The Commodore 64 existed in that magical time between screens with only text and screens with only bitmaps. The C64 had both, plus it had the ability to display character maps with completely user-defined graphics. These graphics did not have to look like letters of the alphabet, they could be 8x8 pixels in 2 colours, or 4x8 wider pixels in 4 colours.

What`s the Hardware Doing?

In the character modes, the graphics chip is taking 1K of character codes, 40 per row down the screen, and using those character codes to index into a 2K character set of graphics. Since each character has 8 bytes, or slices, of graphics from top to bottom, it just scales up the character number by 8 to get the addresses of the graphics. It`s all very mechanical, but the fact that the chip is doing it every 50th of a second means you can have some fun with it.

Character animation.

The most obvious use of the character mode is to move the graphics data in a set of consecutive characters. By drawing a group of animations you can then move the character data, preferably during the vertical blank period when no characters are being displayed, so that the characters change from one image to the next. You probably don`t need the speed of doing this every frame as the animation ends up being too fast. You can rig up a system to just do that every 3rd or 4th frame. That means you could have 3 or 4 sets of animations and do one of them every frame. Typically each animation involves moving 32 bytes, possibly plus a buffer of 8 bytes. If you just want to move the data then you will have to be careful not to overwrite something you haven`t copied.

Programming is often about speed versus memory. If you have data for characters 0, 1, 2, 3, 0, 1, 2 then by picking your start position you can copy 4 characters' worth of data without having to check for the end and wrapping around. Logical ANDs can alleviate that as well to some extent when working with data lengths in powers of 2. With only a few registers you should use your variables wisely. For example, your character animation needs to go from frames 0 through 1 and 2 to 3. Your copy operation though needs a data index from 0 through 8, and 16 to 24. So rather than shift you animation number up by 3 bits every time, just add 8 to your variable and use it as an index. You can then AND the value with hex 0x18 (decimal 24) to keep it in range and it`ll go 0, 8, 16, 24 and back to 0.

Gribbly`s Day Out.




My first use of animated characters was for the barriers and buttons. To get the correct angle for the barriers I had to use 3 sets of animated characters as I needed barrier characters offset to the right by half a character. The buttons look like 2 character animations as the graphic is quite small and had to be done in one colour, so was much simpler. Animated characters were also used for the Gribblets. They are two characters wide. There are also three versions of them to keep processing simple. One of the versions can be picked up or turned over, one can`t, and one is the upturned version waving their legs in the air. Other character animations are the PSI grubs, the waterfalls and the surface of the water. More on how the whole game works in a later blog.

I had seen how other people were using animated characters. The beauty of them is that no matter how many animated characters you have on the screen, the cost is the same, they are all re-plotted by the graphics chip every 50th of a second... for free! The fact that you can also set smooth scroll registers to get 0 to 7 pixels of offset, also for free, means that we can have smooth scrolling.

I was also using sprite to background hardware collision detection. Gribbly gets an indication from a register in the graphics chip if any pixel in his sprite touches any pixel of the two higher colours on the background. Background colour and multi-colour 1 don't trip in the collision detection so he flies straight through the buttons and the waterfalls, but by careful use of the colours to make sure most of the edges are done in foreground colour or multi-colour 2, there is total pixel accuracy on the collision detection, and once again, it`s free.

Paradroid. 



I cut down on the animated characters in Paradroid just because I needed more characters to draw some of the graphics facing four different ways, such as the consoles. I never believed in putting in effects for the sake of it, they had to have a purpose. The energisers are animated characters, so it doesn't matter how many there are on screen, just the graphics data for 4 characters are being moved around. By making all the pass-through characters at the front of the character set, and the blocked ones at the end then a simple comparison of the cut-off point tells me whether a character under the player or bullet sprite is passable. 

The door animations then are just swapping blocked door characters on the background map for clear ones, a pair at a time. Once swapped to clear characters the player, other robots and bullets can pass through. Bullets don`t open doors though, only robots. If the player detects an energiser character under them then they gain power. Similarly, lift characters access the lift if the fire button is pressed while standing on one, and the characters in front of consoles do the same for computer access. That's the magic of a character set background rather than a graphically drawn one, whereby every active object in the game has to have a way of doing collision detection. That's for another blog too, though I am reluctant to reveal the system we learned from a fellow programmer, it`s his secret really.

Uridium.


In order to get a game running at the full 50 frames per second speed that all of the arcade machines were managing, I needed to reduce the time spent per frame, so there`s no character animation here. There are a couple of little tricks though. I was able to track the mine ports on the dreadnoughts and update the colour map so that they glowed. Right now I'm wondering whether bullets glowed if they went over a mine port. There's an experiment to try! For this game though I wanted plenty of player bullets so I used the character set in another new way, for me anyway. I reserved some 24 characters in the character set for bullets. When the player fires a bullet, I look at what the character is where the bullet should go, I copy its graphic to a spare bullet character, and then add the graphic of the bullet onto the character. Now I substitute my bullet character onto the map where I need it, noting what character I am substituting and where it was.  

For each of the 24 bullets I just need to know if it's alive or spare, and which direction it`s going in. One byte does all that: if it's a zero the bullet is spare, ready to be used, -2 it`s going left, 2 it's going right. I can add this to the X position each move and check for being off the visible screen with another quick check. The bullets are 1 character wide and character aligned, they're all going at 2 characters a move. All the enemy spaceships are looking at a 3x2 character block beneath them, checking for a character in my 24 bullet range, and if so they blow up and award their points to the player. They'll always spot a bullet moving under them. Every frame then I have to repair the background of bullets in reverse order (in case 2 bullets are in the same character, they have to unwind in the correct sequence. Yes I could have just restored true characters with a bit more simplicity. Hindsight is wonderful!

Collision detection with the walls for the player is as straightforward as Paradroid, all the blocked characters are at the end, the destructible ones are in the middle, with whole and destroyed versions arranged so I just add a constant (preferably a one) to the character code to get the destroyed version. The only thing you need is a little map of what character is part of a larger object so that you take out all the relevant blocks together. Likely I had offsets X and Y to the top left of the object, and then the X and Y size for each of the destructible characters.

Alleykat.


For the race-tracks, most of the scenery is destructible, with up to a 5x3 block of background. I had to split the character set into blocks that you could fly over, under, or into, as I was trying to represent a 3-dimensional view with a 2-dimensional map. The height that you're flying over background adjusts your position and, rather helpfully, the nose of your ship always points to the character you`re going to fly into, you just allow the player to pass if the height of the character is lower or higher than you're flying. I can't remember exactly but I'd have lined up all the graphics so that they could be drawn in position for whatever the editor needed. I didn't get involved in re-arranging the characters for different heights, but some simple comparison tests would tell you if you were over a top height character as they were all lined up together. You only need to do the required tests for the height you`re flying at.

I had animated characters for the energy blocks on the background. I did 4 different frames to make the graphics bob up and down, and the animation was sequenced up, above, middle, down, below middle. I didn't want to lazily copy the middle frame to positions 2 and 4. The 4 character graphics just cycle around in the 4 graphics positions, and you can put any of them on the background and they all move, but at different stages in the animation to look more random.

I couldn`t quite scroll the whole screen, 1,000 was too many characters to do in a 50th of a second, let alone a 60th for the U.S. release. The trackside left and right characters were posts spaced at 2 characters apart. I had to swap the graphics over depending on whether I was displaying starting on an even or odd vertical map character. The outside characters were just continuous vertical lines, so was not scrolled at all. Total genius, I thought! I did reserve a lot of characters for the giant trench that the player makes should the ship run out of energy. Some reviewers seemed to enjoy just making as large a trench as possible.

I also used animated characters as black animated silhouettes for the fire effect on the titles screen. I had a system of driving character-high colour fades through the background and I was moving a bunch of those up the screen randomly, and they could overlay each other so they would cycle round and with animated black characters over the front produced some wacky fire effects. Mostly the colour technique was just to be able to do colour fades across text. By Intensity I also had the X smooth scroll position under control every raster line so I could make the text italic or wave about.  

Morpheus.



For this game, I sat there with my hex calculator and converted 256 angles in a circle into hex sine values. There are 256 degrees in a circle, not 360, as school would have you think. It makes sense really, as you can add two angles together, ignoring any carry over, and get the answer without having to do any range checking. A multiply algorithm was needed to multiply an angle's sine and cosine by the polar speed to get a Cartesian X & Y speed out to add to the X & Y positions. I needed these so that I could drive individual pixels around the screen for explosion and star-field effects. In multi-colour mode you get 3 different colours to plot over the background, so by arranging the multi-colours carefully you can get fading effects too. 

As with Uridium then I reserved as many characters in the character set as I wanted pixel particles, something like 32, I do like round numbers. By the way, character zero is usually blank so it is easily recognised as empty. You always need a blank character, right? Anyway, when you want to plot a pixel particle you work out the character on the screen where you want to plot it first. Make a note of that character code, and where you got it by address, not X & Y, as you'll need to restore it later. Copy the graphic in that character to your particle character, add the particle graphic to the correct place in the character. The low 2 bits of the X and the low 3 bits of the Y give you the pixel position X and Y. You have to AND in a gap where you want to plot before ORing in your colour pixel so that it doesn't wipe another particle on the same line. Then you substitute your new character onto the screen where you worked out earlier. All this needs to be done in the vertical blank period to avoid flicker, but before you get started each frame you need to clear up the previous frame's activity by restoring the previous move's alterations. The fastest way is to mow through all the particles, skipping any unused ones or any where the substituted character is itself a particle character, as it will get cleared by the first particle in at some point. That way you don`t even need to clear the particles in reverse sequence. For speed, never work anything out more that once, save the answer for later, and every CPU cycle is precious, plan to write it efficiently first time. Don`t just figure out how to do something lazily and then have to optimise it later. Why write it twice?

The "tooth-paste" gun at the front of the ship is also done with characters. All the characters are in a set range to allow the meanies to just check under them for a character code in that range and they die. The firing sequence then just defines which characters to plot in front of the gun to make the shot grow, hold and then decay. 

I wanted shots to be fairly immediate from the gun add-ons, you just see a muzzle flash and the bullet is not shown, it's too fast. I'm now wondering whether I just fired out a bunch of blank characters in the direction of the shot, making sure that the alternate blank character was in the reserved bullet range too. No animation needed. I hope I did it like that. When testing, you can put a graphic in the character to see that you`re plotting the character and then removing it correctly.

The giant character font is made of blocks so I had a map of which characters to make each letter. There are 3 different widths of letters 1, 2 or 3 characters, and they are 3 high. You always want your score digits to be the same width, you don`t want scores and timers hopping about just because a 1 appears in the top digit. It`s one of my pet hates, it looks so horrible. So you have to widen the 1 artistically. The two big text bars are actually changing the character set with raster interrupts. This meant I wasn't limiting the game`s character set by having to use half of it for text.

The radar at the top of the screen had a reserved block of characters for it and the particle algorithm was used to plot pixels into an array of characters. The clearance routine was slightly different as I wasn't replacing whole characters on screen, I just had to blank out the lines I had altered, so I just had an array of addresses of lines in the character array altered, and all I had to do was blank them out. This worked better for a smaller chunk of screen where you can afford 1 character for each character in the radar, rather than 1 character per pixel particle.

The other use of characters were the top and bottom rails in the docking bay. These are being dynamically built to move the 3 parallax layers, and then to fade them out by applying different masks to the graphics before combining them.

Intensity.



This was a game without bullets, and the sprite multi-plexor was handling most of the object plotting duties. However there were a couple of character-based features. The hatchways where the crew emerge had a lot of animation frames to show airlocks opening and the lift rising up with the crew member. Lots of animation for just the one character area. 

I wanted to show damage being done by the meanies, so I drew some damaged background characters for when they are landing on the background, as well as pre-damaged bigger chunks to show the space station was under attack. For the sprite shadow effect, the colours have to be rather broad. The shadow sprite colour has to match the shadow colour on the background, i.e. one of the character multi-colours. The main un-shadowed background colour has to be a related colour that is darkened to the one and only shadow colour. The highlighted, usually white, background colour can also be covered by the shadow sprite colour, and space is actually the foreground colour, which obscures the shadow sprites. Yes, space is in front of the shadows!

The walkways are also characters that can modify the background when you land a ship on the end character, allowing the crew to cross. I`m just plotting extra characters into the map until the bridge hits solid platforms. The bridge stays until the ship takes off and doesn't hold the bridge open.

If anyone has managed to get to the final completion screens in the game, I had drawn an escape ship using background characters. I had this idea to make it take off. I had to redraw the space ship in sprites, so between playing the level and revisiting it after completion, the characters are replaced with a flat take-off area, and the sprites do the work. Certainly gave the sprite multi-plexor a work-out. 

As well a using the character map as a reference for allowing landing, behind the scenes the game generates firstly a height map for the screen, to decide whether either of the player craft can fly over or crash. In order to make the craft`s attempts to fly over obstacles smooth, the game also generates a recommended height map. The craft fly at the recommended height or their maximum, whichever is smaller. For space, I could probably have combined them into 4 bits each and make one map, but it was only 1K each, so I had two maps to make access to the data a bit quicker. All this is to show off the shadows showing how high you're flying (c) Uridium. Always work out the tough stuff in advance rather than on-the-fly. Space versus time, if you have space you can store answers in advance to save you time.

Conclusion.

So that's the different ways I was using the fabulous character modes of the C64. The VIC-II chip was tirelessly refreshing the background every frame and giving a level of indirection between the graphics and the screen that we could take advantage of to get some interesting effects. Whilst we can simulate that now, we have to program it ourselves. A step backwards, I feel. However, as resolutions have increased and pixels have consequently got smaller everything has got so fiddly that other techniques have taken over. The Golden Age of Character Graphics is sadly over.
    


1980s C64 Development

Introduction

The Commodore 64 was a 6502-based computer. That chip just had 3 8-bit registers, each with slightly different purposes and capabilities. Working with assembler to program the computer to play games was the best job in the world. It probably still is.

Assembler

Just before I get into the various uses I made of the C64 character mode, I would just like to mention the dark art of programming in assembler. Way back in 1984 I was just using a pair of C64s. I would be assemblin the program on one using the Commodore macro assembler and a 1541 disk drive. The process took about half an hour to assemble and construct the binary executable for a game, being anything up to about 16K. While the assembly process was going on I would have to wait and hope that the assembly would be successful. That taught me to type carefully and read everything back to achieve that first-time success. 
  While the assembly was going on I needed something else to do, so I had a second C64, also with its own 1541 disk drive, to work on the graphics. I used the SpriteMagic and UltraFont editors which were bought as a pair from the local computer shop. Every town had one back then.

Once assembly was complete I could download the executable to the C64, along with the various graphics files and fire up the program. We had no debuggers, let alone remote debugging from another computer, so if the program crashed, and it would... a lot then you're left with nothing. There were no magic cartridges back then either, which might have offered a bit of disassembly of the crash site. I did buy one later, mainly to try to thwart them from being able to steal our programs, but that`s another story.

6502 assembler is a pretty simplistic affair by today`s CPU standards. You have 3 usable registers, each with slightly different capabilities, so you're writing in simple blocks of code to carry out slightly less simple operations. When it goes wrong it might just not quite do what you want, or it might go into an endless loop, or it might go rogue and start executing where it shouldn`t. When you have user graphics on the screen rather than letters, as we often did, then the computer has no way of showing you a message as to what is wrong, and in any case you wouldn't have space for many messages of any value. 

You tend to write in the same patterns all the time in assembler. You have to figure out how to write your new code a bit at a time. If you write a giant routine in one go and then run it straight off it`s just bound to end in disappointment. The clever architect figures out whether write inner loops first and test them, or write the outer loop first and maybe use the trusty method of changing the border colour to show different results. We used to set the border colour to differnt colours between each major routine call so that if the program crashed then the border colour would indicate the culprit.

I would have a pad of squared paper by the computer. Every test cycle I would write down every bug I found and any tuning speeds or rates that I felt needed adjusting. I 'd try to test as thoroughly as I could, given that at any one time there would likely be a page full of things to check from the last time. The program might crash and that would bring things to a halt. I would then reload and try to figure out what caused the crash, and then avoid that and do any other testing. I could tick off items on the list and start creating a new list. Usually I would be developing the game and the titles sequence. I would then try to fix all of the bugs and change the tunings as required before embarking on another 30 minute assemble. 

We didn`t have conditional assembly as such, or at least we weren`t using it because we needed to keep the source code files as small as possible. I would therefore have code like setting the start level to any desired test level and would have to remember to remove all that at the end. There are no cheat modes in any of my games. I felt that might distort the testing and my view of how easy or tough the game was. Being able to start on any specific level though is a time-saver when getting to a particular feature or issue. I also tended to just make the level I wanted to get to the first one, which is turning everything on its head.

When I was developing game levels, rather than try to develop a tougher or easier level as required, I would just develop a level and then work out where it would go in the hierarchy. Whilst you can make a level a bit tougher or easier with tweaks, to alter the difficulty a lot might take a whole bunch of time. 

While we never had to decide on an end date at the beginning of a project, we certainly were getting the idea that every game was taking a bit longer than the previous as the program was getting slightly more clever and bigger than the last. Based on that we would have to start working to an approximate end-date once we thought we were in the last 6 weeks or so. We were starting to fill the machine and it was important to ensure that the game was bug-free. Fortunately we didn`t have any tough issues to fix at the last minute, though changing the Paradroid firing mechanism for the third time was quite hair-raising. 

As the last weeks approach; schedules start to be made for production and delivery of the game to wholesale. We would also visit some of the magazines, and have a launch lunch in London for the magazines there. We would want the game to be complete before showing it off. I wasn`t totally happy about giving a complete game away for review because it was unlikely that the game would be fully seen in the time needed to get a review to print. However they did insist on having the whole game. When we were there to talk to the press we could answer questions as well as demonstrate how to play the game. That used to work out well for us as the reviewers didn`t get frustrated when they couldn`t figure something out.

ABMON

One of the first things I did write was a little monitor routine. I reserved 16 characters in the character set for the numbers 0 to 9 and A to F so I could display hexadecimal. I had it operate every game frame, selectively on a button press, to display an address in memory plus the value at that address.  I just had a simple cursor mechanism rigged to flash one character and I could dial the digit up or down with cursor keys. Usually it would be on the top line showing something like:
 0035 01
meaning that the byte at address 0035 was set to 01. I could alter the value up and down as well as the address; so if a variable got set incorrectly I could change it. Mostly it was a good idea to pause the game while using this. 

I had a master sheet of all of the variables with their addresses written down, and as they don`t move then you get to memorise the important ones pretty quickly. I could dial in the address of a particular variable and see what it was set to.

I might have rigged it to skip over the chip registers as you don`t want to be writing to some of those with out-of-date values. 

ABMon allowed me to get a glimpse into the workings of my programs and was invaluable in solving some of the bugs. 

As a game was just about to complete, i.e. no more development was needed but there might be a bit of tuning tweaking still to be done, I would remove all the debug code, including ABMON, in order to save some space, maybe for a couple of extra graphics. I would also try to use the start-up code memory space for something else in order to reuse the code that has done its job and serves no purpose other than to reveal how I initialise my code. I might use the space as a buffer for some process or other, maybe the object variables.

Zero Page

The first 256 bytes in the computer have an address that starts with 00, hence the first 256 bytes are referred to as the zero-page. 6502 assembler has short instructions that can read and write to these 256 bytes nice and quickly. Naturally the operating system is using these bytes as variables so when you take over the machine you will likely just put your own values there and there is no way of getting back to the OS other than flipping the power button. Amazingly though you`re back to BASIC in a second with a fully operational computer. 

I kept all the main variables in the zero page. It still surprises me to see cheat pokes where the number of lives, for example, is not stored in zero page.

I didn`t have space in zero-page for all of the objects` variables such as position and animation for 16 objects, so I used to keep them in a table elsewhere, but I found it economical to copy the variables for one object into zero-page at a time, operate on the object, then when finished I would copy the bytes back out. That made the routines a bit smaller and faster. It certainly saved space and probably some execution time.

Around the time of Alleykat, late `86 or early `87, we got our mighty PCs. These didn`t have hard-drives, nor Windows, it was just loading DOS from a floppy drive into RAM, the machines had one Megabyte! We bought in some cross-assemblers and the EC editor. EC allowed us to edit the source code and had enough memory in the machine to allow us to put comments in the code. When assembling on the C64 we didn`t dare spend any space on comments as the assembler and the code had to sit in memory at the same time.

We then had to write the software at the C64 (and Spectrum) end to receive the software downloaded from the PC through the Centronics parallel printer port. That meant that we only had to load that downloader software from the 1541 drive and then it would be primed to read the data sent by the PC. Actually the graphics data would also have to be loaded from the C64 drive as they were still being produced on the C64. Our mighty PCs had just an amber screen and no graphics packages. Still, they were more like what I had been used to in my previous job working on an IBM mainframe.

PDS

As I got to writing Intensity, a PDS development kit became available. This ran on my PC and allowed me to edit 8 files at once. That was rather handy as this was to be by far the biggest program I would write on the C64. I ended up with a 29K executable, almost half the available memory. There were landscape analysis buffers for height maps and recommended altitude maps, all requiring code to generate them. I also managed to squeeze 75 levels or so of screen maps in there, and used the RAM under the ROMs as video memory for the first time. That seemed to offer me the best available space and I could switch all of the ROMs off and keep my 29K of code in one contiguous lump. 

Video RAM

You had to consider how you`re going to load your code and data into RAM in one load operation, take over the machine and get yourself a clean 16K of video memory, since the sprites, screen and character sets have to come out of one quarter of the memory. Of course you can swap in alternate character sets from level to level. I had 8 different 2K sets for Alleykat for the different race styles. Usually all of the game graphics at any one time would have to come from one 2K set of 256 characters. We might use a screen interrupt to swap character sets for an information panel. Typically then that would be 4K or 1/4 of your video RAM. The screen would take 1K for a character map, leaving 11K for sprites, at 64 bytes each that would be 176 different sprites. Some games may well have paged in different images per level, or even in real-time, but I don`t believe I went that far. Equally we didn't think of compressing anything as it would have meant spending space on a decompressor algorithm.

Optimisations

To get extra things done in the time you have to think of cunning ways of doing less than you thought to achieve what you want. Set up tables of common results, such as multiplying numbers by 40 so you can look up answers rather than calculate them. 

By Morpheus I had a sine and cosine table coded in hex so that I could do circular effects. There was a multiply or two in there for sure, too,many different inputs for a look-up table. You only need to set up the sine and cosine once in the life of a fragment, after that it continues on using the calculated sine and cosine speeds, so I was storing Cartesian speeds and polar (circular) speeds and directions.

Conclusion

Developing in assembler with hardly any debugging tools, certainly nothing modern, was not for the faint-hearted.  When things go wrong you have to go back to the source code and spot your mistake. Maybe a loop went on too long? Did you choose the right register? There were only 3! 

It is very satisfying seeing something you`ve created working, and you know that it`s running as fast as it can. 

One For the Programmers

Notice

In light of the passing of Ben Daglish this week, I would like to dedicate this page to him. He went to great pains to explain to us that his surname was spelled Duh-Ah-Ger-Lish. Taken way too soon.

Introduction

I just want to write a little bit about optimising your games, one or two of the things I have learned over the years. How relevant these things are now is rather moot, as the CPU has been relieved of the burden of plotting the graphics for the most part and therefore has plenty of spare time to do things deeply, or slowly.

However, once you find a faster way of doing something, as long as it`s not ten times harder, then why not use those techniques knowing that you`re saving time that you could later use for something clever?

Over-defensive Coding

This came up a few articles ago, so I`d like to clarify what I mean.

Imagine you write a routine that takes as its input a number between one and a hundred. Having set the rule for the expectations of the function, should that function test the input to make sure it does indeed receive a number between one and a hundred, and what should it do if it doesn`t?

The answer slightly depends on whether you`re writing a black box function for someone else to use, or whether it`s just your internal function. If it`s a black box for someone else to use, then yes, it should always test the input value passed, and you need to publish what it will do if you get the input wrong, i.e. will it crash, will it pass a message back, or some failure-indicating value? Just for info: it should NEVER crash!

If you`re writing a function for your own use then you can be a bit cleverer. We usually develop code in a DEBUG mode, which produces less optimised code that can be seen by the debugger, and the final RELEASE mode code is compiled to be optimised, and not debuggable. In theory, both versions of the code will behave the same, but most of us know that differences can occur because the compiler does some helpful things in DEBUG mode, such as zeroise all your variables. Additionally the programmer can detect which mode is being compiled, and you can put your additional validation tests only in the DEBUG mode. The idea being that you thoroughly test your code in DEBUG mode, and deal with any incorrect calls long before delivery. Error messages can be pushed out to log files that won`t be produced in the final RELEASE mode. You can also just plant a break-point in the test failure side to make darned sure the code stops if you send in an invalid value. If it kicks in then you can investigate and fix it there and then.

Way back in the 8-bit days when CPUs were running at 1MHz and scrolling the screen took 60% of your time per frame, every test you didn`t need to do was important.

Scaling your numbers to be computer-friendly was important. I have spoken to some of my work colleagues about hexadecimal numbers and they just glaze over or look blankly back. Most modern applications don`t directly involve binary or hexadecimal, so they`ve never learned to think in hex nor binary, but for games coding they offer some lovely short-cuts.

Let`s take the above example of validating your input of between zero and a hundred, an inherently decimal test. You`re going to have to code something like this:

   long Answer = 0;

   if ((Input >= 0) && (Input <= 100 ) {     // Two tests
      Answer = DoOurStuff(Input);
   } else { 
      Answer = -1;                           // Signal failure
      printf("Invalid value %ld passed.\n", Input );
   }
   return(Answer);


We`ve created two tests that will be done every time, and if we`ve debugged our calling code correctly they will never fail. You`ve also had to code two more lines of error reporting, and somewhere  a jump will have been compiled in to get to the return statement.

Now supposing we re-scale our input to be a value between 0 and 127, or in hex: 0x00 and 0x7f. We can ensure we always get a valid value by logically ANDing the input with 0x7f. That doesn`t even require a test, we have simply removed any bits from the input that we are not interested in. We should however still test the input for range, in DEBUG mode at least to ensure that the caller knows they`ve passed something bad through, but we can do that in one test now:


  long Answer = 0;
   long VettedInput = Input&0x7f;       

   if (VettedInput == Input) {          // One test only
      Answer = DoOurStuff(Input);
   } else { 
      Answer = -1;
      printf("Invalid value %ld passed.\n", Input );
   }
   return(Answer);
}


Things get a bit messy with a DEBUG mode test as we`re removing two chunks of code. Any time we remove one squirly with conditional compilation there must be another block with the same test that removes the corresponding squirly.

{
   long Answer = 0;

#ifdef _DEBUG
   long VettedInput = Input&0x7f;       

   if (VettedInput == Input) {          // One test only
#endif
      Answer = DoOurStuff(Input);
#ifdef _DEBUG
   } else { 
      Answer = -1;
      printf("Invalid value %ld passed.\n", Input );
   }
#endif

   return(Answer);
}

_DEBUG is a compiler flag that is only defined in DEBUG mode, so we can test if it exists and include the extra code. Usually the non-debug RELEASE code has NDEBUG defined. You can, of course, include your own user-defined switches unique to each mode.

The code is even simpler if you need a signed number between -128 and 127, or an unsigned byte from 0 to 255, you can just use the byte as-is because there are no invalid inputs.

When I was writing Morpheus, way back in 1987, and decided that I wanted some circular patterns, I developed some custom sine and cosine lookup tables. You can always decide on the size of such tables depending on how much accuracy you want. Did we use degrees? No, 360 doesn`t fit in a byte, which was a convenient size to pass around. Did we use radians? No, we didn`t have floating point on the C64, and though we could have scaled some hex values and use 2.6 bits, we decided that there should be 256 degrees in a circle, that would be enough. Just fits in a byte, and if you`re adding angles you get automatic wraparound if you stick to bytes. My array of sines and cosines would be byte values of S1.6 bits, so not especially accurate, but good enough. The sine and cosine values can be read from the same table, offset by 90 degrees, or hex $40. Since the offsets are byte values, and there are 256 of them, adding $40 just wraps around nicely if necessary.  

Even today when using SFML, the tests that I have to keep doing after angle calculations to ensure that my angles in degrees don`t go over 360 or under 0 irritate me. SFML must be doing something like this too when called upon to display an object rotated.

Being a library for everyone to use, you can`t trust that everyone will get it right so you have to do range-checks. Range-checking a floating point value and resolving it into a valid one may well involve a number of instructions. In any case, we don`t want our angles going out range either, so we should always be doing our limit checks. In fact, any one operation that I do on angles by addition or subtraction will only push numbers into the range -359 to + 718, so I know that if my angle goes below zero I just have to add 360, and if I go into 360 or above then I just subtract 360, I'll never have to deal with numbers any bigger, i.e. repeat the test and correction. Of course logically ANDing the number with 0xff for a 256-degree system is much faster!

Actually there is nothing to stop anyone from implementing a 256 degree system of their own. We had one on the C64, and then again in 68000 assembler. Once you`ve been thinking about 256 degrees in a circle for a few weeks it becomes totally acceptable. After all, 360 was pretty arbitrarily decided upon, it`s just a nice number that you can divide by 2, 3, 4, 6, 8, 10, 12, 15, 20, probably just to make slicing cakes easier! I always use a protractor to make sure I get the biggest slice. Doesn`t everyone?

As it turned out, angle 0 wasn`t straight up either, it was to the right. With a co-ordinate origin of 0,0 in the top left, the sines and cosines just work out that 3 o`clock is angle zero and they went clockwise. There's nothing to stop you setting them up however you want to, of course, but we want the maths to be as simple as possible.

In keeping with making things as simple as possible on the Amiga, we used signed 1.14 numbers for the sines and cosines, or 14 binary places in a 16 bit two-byte word. We need values from 1 to -1, and while we could fit in some invalid bigger numbers than 1, we can`t quite get the full range in 15 bits, with a sign bit.

To accommodate the maths nicely, we then chose to store our 16-bit polar speed as an S5.10 signed number, making the hex value 0x0400 equivalent to 1 pixel. That way, when we multiplied an S1.14 sine or cosine by a polar S5.10 speed we get S7.24 signed 32-bit answers for X and Y, where suddenly the number of pixels is in the top byte, making it easier to read. We then had to sign-shift it to the right by 8 bits to make our Cartesian co-ordinate system S15.16. That way we could lift the pixel position directly out of the top word for plotting. 8 bits of pixel positions isn`t enough even for a single screen, as anyone who has set up a C64 hardware sprite will tell you.

There`s another technique in there then, whereby we have the pixels in the top word of a 4-byte long, and the sub-pixels in the lower word. We can add very fine movements in 32 bits and then store the value in our object stuctures, but then for plotting the object where we only need the whole pixel positions we can just tell the CPU to lift out the top half of the variable, ignoring the rest.

It`s useful to be able to read your values easily with the debugger, so keep the numbers scaled to byte boundaries where possible. Floating point offers its own solutions and as long as it is accurate enough for you and fast enough then it is certainly the modern way. The debugger will happily decode them for you into something displayable. Bear in mind that they are not able to resolve all values, unfortunately they do struggle with base 10. I wouldn`t recommend them for monetary calculations because of the inaccuracies, you at least need to be familiar with principles of rounding, and how many digits you can represent. Some sort of packed decimal representation would be better. The 8086 chips had packed decimal instructions, and while C doesn`t directly support packed decimal, I would expect there to be libraries that do support it. For financial organisations, the accuracy is more important than execution speed. Currency conversions are an especial delight. 

Saving Space

This isn`t so important any more, but how many times have you seen someone code a single flag in a long variable? That`s 4 bytes, or nowadays even 8, that simply says "Yes!" or "No!" Being familiar with the assembler instruction sets is such an advantage when writing C because you can tell how it`s going to translate your C instruction into machine code. If you write C that does what a single or pair of assembler instructions can do, then the compiler will do just that, it`s not going to mess around creating a mass of code, especially in RELEASE optimised mode. Testing a single bit in a long is something that machine code can do. Putting all of your boolean flags into one long keeps them all together, and you can give the bit numbers a name in an enum list, equivalent to giving each a variable name. Setting, clearing or testing one arbitrary bit resolves down to a pair of assembler instructions too, just as quick as testing a variable. Now you can get 32 (or 64) bit flags in one variable. You quickly get used to the logical operations that can read, clear, set, or toggle one specific setting without altering any of the others.

Binary Mathematics

When working in assembler, especially on a CPU with no divide, and possibly not even a multiply, you start to think about how to do maths in binary. There are instructions on the CPU to shift numbers to the left or right. Sometimes you might need those to slide graphics into the correct position, since in the 8-bit days 8 pixels would share a byte, or 4 multi-colour pixels, and in the 16-bit Amiga days, you`d have 16 bits in a word representing 16 pixels in one bit-plane, and the display chip needed to read multiple bit-planes to determine the colours for those 16 pixels, having an address register for each bit-plane. On the one one hand we got user-definable numbers of bit-planes, but plotting was a nightmare. Yes the blitter did make the job a tad easier, but understanding how to get it to do what we wanted resulted in any number of desperate phone calls to Commodore technical support. The later PC graphics cards got it right with 1 byte per pixel, leading to the 4 bytes per pixel that we enjoy nowadays.

Taking a byte value and shifting it left multiplies it by 2. Shifting right offers a choice of 2 instructions, since the top bit is the sign bit of the number. If you are dealing with negative numbers then you would need an arithmetic shift right to divide by 2, which retains the value of the top bit after the shift. A logical shift right regards all numbers as unsigned and shifts all the bits down, introducing a zero at the top. Now we can divide and multiply by powers of 2, so there's a real effort needed to make sure you`re using powers of 2. On the Amiga and ST it was faster to get a multiple of 40, for example, by shifting left by 3, copying the value to another register, shift left by another 2, and then add the copied value. We multiplied the number by 8, saved it, multiplied it by another 4, making 32, then added the multiple of 8, making 40.

It`s probably not worth doing that on a modern PC, though the syntax exists to do it in C. I use left shifts to get my boolean flag bits tested, i.e.

enum {   
   SessionOver = 0,
   Paused,
   SuspendTime,
   GameFlagsMax};

long glGameFlags = 0;

   if ((glGameFlags & ( 1 << SuspendTime)) == 0) {
      // Time not suspended code
   }

In the above, SuspendTime will be 2, so we need to isolate bit 2 to perform our test. We logically AND only the bit we're interested in. The compiler will actually do the shifting and resolve bit 2 to be the value 0x00000004, it won`t be done at run-time anyway.

Random Numbers

I`ve seen people ask questions such as: "how do I get a random number between 1 and 3 quickly?" The fact is that most random number generators are algorithm-based, so no random numbers are delivered all that quickly. In fact, the only time I`ve found a hardware way of getting a random number was on the C64 SID chip. You could set the third channel to noise waveform, rack up the frequency, and read out out the current waveform value. I used to direct all the noise sound effects to that channel, and when it had finished I switched the sound channel to play silent high-frequency white noise. Any time you need a random number; just read it off the SID chip: 1 assembler instruction, nothing faster!

The advantage of algorithm-generated random numbers is that they can often be seeded, so you can get the same set of numbers out every time. In my latest game I could watch the first titles sequence, with supposedly random things happening, and every time the first demo sequence ran, it did exactly the same thing. To change that, I now get a timestamp of when the program starts, and seed the system random number generator with that. Now I get a different demo every time I start the program. I`m still not happy about the time that the system algorithm takes to supply a random number. Firstly, I have no idea actually what algorithm it is using, but secondly, that might change at any time if someone decides to alter the C library. 

In order to supply my game with random numbers faster than the system can, I get an array of 256 numbers in advance from the system. I refresh that every time a game starts. Getting 256 numbers at the beginning of a game doesn`t take a great deal of time in the grand scheme of things, the player is just getting ready to play and likely you`re doing some kind of arrival sequence anyway. I then keep one index pointer into the array of random numbers and my fast call pulls out the next entry and shifts the index along by one. It just has to make sure it doesn`t fall off the end of the table. Actually an assembler optimisation for that would be to start at the end of the table so you decrement the index and easily detect the underflow case that resets the index to the end. It saves a compare. In C, the get a random number function is so short that on a RELEASE build it`ll likely drop in the code in the function rather than calling it.

Coming back to the random number between 1 and 3 then... I would always try to avoid anything that doesn`t involves powers of 2. Scaling our 32-bit random number to a lower power of 2 is again just a case of logically ANDing the random number with a mask to reduce the scale. ANDing with 0x03 gives you an equal chance of 0, 1, 2 or 3. None of the powers of 2 are divisible by 3, strangely enough. If you do want to do that then you could do it quicker by, say, getting  number between 0 and 255, and testing it for being less than 86 for 1 route, less than 172 for the second, else the third. The only faster way is to set up a specific array of random numbers between 0 and 2 for later diving into.

The process of setting up an array with answers to complex calculations in advance is nothing new. On the C64 the screen was 40 characters wide, and there was no multiply instruction, so a little table of 25 entries with multiples of 40 in it was great for calculating the screen character address at a particular co-ordinate. You would divide the Y pixel co-ordinate by 8 by using the logical-shift right instruction 3 times, then look up the multiple of 40 in your table, then take the X pixel co-ordinate and divide by 8, and add that on. 


Square Roots

In the days before floating point, some calculations used square roots, which is a hideously slow answer to get, for example, in a Pythagoras distance calculation, so we needed a simpler way. Some clever mathematicians have worked out some simpler calculations that give approximations. The calculation we used gave an answer within 10%, which is fine to know whether something is close to the player or not. In fact, just taking the bigger of X or Y (or Z, in 3D) would probably be enough to be informed, with a worst case 45 degree 41% inaccuracy (in 2D).

Just as a curiosity, here`s our 68000 approximate square root function. I didn`t write it, as far as I remember, I just said "Dominic, how do I..." and it was done. 


;---------------------------------------------------------------
; Square root function
; Expects - d0.l unsigned number to find root of
; Returns - d0.l unchanged
  - d1.w root of d0.l
;
;----------------------------------------------------------------
SquareRoot
push.l d2
move.w #$0100,d1 ; First guess
Rept 4
move.l d0,d2 ; Square
divu d1,d2 ; result=square/guess
add.w d2,d1 ; guess=result+guess
asr.w #1,d1 ; better guess=guess/2
cmp.w d1,d2
beq.s .DoneRoot
EndR

move.l d0,d2 ; Last attempt if
divu d1,d2 ; not already got
add.w d2,d1 ; the correct
asr.w #1,d1 ; result
.DoneRoot
pop.l d2
rts 


We found this to be more than accurate enough for our needs. The "Rept 4" is an assembler directive to repeat the block of code to the EndR. You could increase the number to get more accurate results, but we found that those 4 with the fast get-out plus the final one will get you good results. Depending on what you need the square root for; your degree of accuracy might vary. There`s nothing to stop you having one super-accurate routine if you need it, and a less accurate one where you don`t need total accuracy but it`s quicker.

There`s no reason why you shouldn`t have a bit of apparently random behaviour that affects things that is purely down to mathematical inaccuracies. After all, behaviour depends upon a lot of other factors which you`re not necessarily including. Quite often we`d put in some random number fetching to affect behaviour anyway.

Conclusion

If you can work out some answers in advance and look them up at run-time then you`ll save some CPU, at the expense of the space that the answers take up. All the better if the calculations are quite complex to get the answers you need, as long as the set of different inputs isn`t too large.

It`ll take a lot longer if you have to optimise at the end of your project because the game isn`t fast enough. Better to think efficiency all the way through and see what you can do with your desired frame rate.

Fire and Ice

Introduction

Fire and Ice was Graftgold`s first Amiga-led project. The Bitmap Brothers had set up their own publishing company: Renegade, and we had been in talks with them about publishing some games.

As usual I have culled some screen shots from the interweb, so thanks to the creators of those for producing images of our game. Nice that this gif runs through its animation.
 

 Smooth Scrolling

It was late 1990 when Paradroid 90 had shipped on Atari ST and Commodore Amiga. That game was using Dominic`s 16-bit "OOPS" kernel, which he had developed originally for Simulcra, and we had used for Rainbow Islands. This had allowed us to write a game predominantly on the Atari ST, and then port to the Amiga, running in 16-colour mode, in about 3 weeks. The kernel took care of common functionality such as keyboard, joystick and mouse input, interrupts, debugging, and displays. The up-side of this was that we could produce a game on 2 similar platforms quickly, but the downside was that we were working always to the lowest common denominators. This particularly exposed the weakness of the Atari ST: no sideways smooth scrolling in hardware. 
 
Meanwhile Turrican 2 had been released for the Amiga, showing what could be done on the platform. It had plenty of sprites, a great copper-listed backdrop of colours, smooth scrolling in all directions at 50 frames per second, and a great game with plenty of action.
 
We had some telephone conversations with Julian Eggebrecht, representing Factor 5, the team who wrote Turrican 2. They had written their own development system as well as the game. They were keen to tell us about their scrolling technique, which utilised the unique feature of the Amiga hardware: that the bit-planes for the display can start on any word address in memory. Most displays had fixed or boundary-limited addresses in RAM for the screen.
 
The issue for the Amiga was also that the CPU was not fast enough to rebuild an entire screen`s worth of data every 50th of a second, fast though it was. The magic of the Factor 5 scrolling system was realising that during smooth scrolling, quite a lot of the screen data stays the same. Only areas covered by software sprites, animated background characters, and the scroll leading edge(s) change, so if you can efficiently update those then you can get to the magic 50 frames per second arcade speed.
 
I`ve written a detailed description of our interpretation of the scrolling routine in an earlier blog article.
 
I spent about a fortnight implementing the scrolling routine. I drew up a test set of graphic blocks, just some numbered squares, really. The first screen is initially built by starting the display a whole screen to the side of where you really want to display, and then letting it slide all the way across to where it needs to be, building up the leading side edge of the screen. Whatever garbage happened to be on screen to start with is discarded off the trailing side. The scroll routine is set to loop round building the edges for as many times as it needs, but once the game is running; it is controlling the scrolling and limiting the speed usually to about a maximum of 4 pixels a frame, so a leading edge will only be needed every 4 frames (blocks are 16 pixels wide to match the smooth-scrolling span and the hardware pickup of 16-pixels in a word. 
 
To start with, I just used the mouse movement to drive the scroll position. This allowed me to check the edges where scrolling needs to stop, and I could move the screen slowly or quickly. Since there's no game to run then there`s plenty of CPU time available.
 

Animated Background Blocks

The display system needed animated background blocks. These allow squares of the screen to be efficiently updated to create areas of movement. I therefore needed to set up some simple lists of animations. This goes back to the old days of C64 animated characters where each 8x8 pixel graphic was defined by 8 bytes of graphic data. In those days it was necessary to shuffle the actual graphics data between 3 or 4 consecutive characters, whereas it would not be efficient to shuffle the 128 bytes per character of the 16x16 blocks. Since the characters are done by software, there were no character modes on the Amiga, we could get to the graphic data through a list of pointers to the characters, so animation was a simple case of shuffling some of the pointers so that the character renderer just gets redirected to different graphics.
 
Animated graphics in Fire and Ice include the underground waterfalls under the jungle, the high score initials entry screen, and the rising bubbles underwater, but for an extreme example, John Lilley went for some psychedelic party effects all over the level completion screen. 

 
 

Software Sprite Plotting

When we plot software sprites into the display bitmap, we need to restore the background when those sprites move, which is every frame. The sprite plot routines have to calculate the position on the screen where they`re going to plot the graphics, so at the right moment they just note the offset into the screen, the width, and the height of the plot into a restoration list. 2 frames later than the plots, for a double-buffered system, the restoration list is parsed and the pristine graphics are copied, nay blitted, from the restoration buffer to the display buffer. A restoration buffer is a third copy of the character background that never gets any sprite graphics plotted to it. It also has to scroll in synchronisation with the game objects in order to have the correct graphics available to be copied for restoration. 
 

First demo

The first demo that we submitted to Renegade featured a furry, flappy-eared bouncy creature than may have been descended from Gribbly. The background graphics were quite mountainous, and the creature merrily bounced around the place. This must still exist on a floppy disk somewhere... For now we have a magazine snippet from an unknown contributor in the comments. Seemed natural to me that a fluffy bouncing dog with flying ambitions should live in a nest at the top of a tree. 



Some of the lower pictured sprites made it into the final game. At this time they were all single-character prototypes by Phillip Williams, to see what he could do.
 
Renegade reported back that the character was a bit too "unconventional", shall we say, and wanted something more traditional in its movement.
 
We gave our lead graphics artist on the project, Phillip Williams, free reign to animate a character of his choosing. At this point, the full palette for the game, levels, and sprites has not been decided, but the colours chosen for the main character, what they are and how many are used, has a great bearing on the yet-to-be-drawn levels. We had decided on using 16-colour mode still, I wasn`t confident that we could manage 32-colour mode. You lose CPU cycles if the code is in video RAM as the graphics chip has to steal cycles to pick up data from any more than 4 bit-planes. Whilst we couldn`t really quantify that, we also had in mind that we still would like to produce an Atari ST version of the game. We split the palette into 4 groups of 4 colours, making the last 4 the blue to white range, so that we could map the other sprite colours just into those last 4 for the ice effect. Arranging one's palette colours is always important. 
 
Phillip came up with the smaller Coyote character. We had Renegade visit to see the new graphics. They were pleased by the more conventional walk of the Coyote. The suggestion came up that they wanted something to rival Sonic, plus they liked the Sonic colour scheme, so we adjusted our palette again.
 
I had my ideas of what I wanted to use the hardware sprites for, and that was the score overlays on the screen. Firstly they only needed to be 3-colour sprites, I could use the copper list to get more colours, and secondly they would then not need to be plotted on the background, they would ride over the top in their own layer. Many people might think that the main character is the best subject for the hardware sprites, but there are cases where you might want to have it interact with the background and pass behind or in front of other graphics, which the hardware sprites can only do one of at a time. In our software since the 16-bit days we always implemented layers for our software sprites so that we could control which graphics got plotted first to last. That allowed us to add foreground objects that the other objects would go behind, including Mr. Coyote.
  

A Real Sunset

I really liked the Turrican 2 colour-fade. I noted that they had interleaved colours to expand out the fade over a wider distance. This is because the resolution of colour change on the chip was 4 bits of each of red, green and blue, which doesn`t give that many changes, only 16 different values of each. The AGA graphics chip had 8 bits of red, green and blue, giving 16 times as many colours. More on that later.
 
I did some research on what is happening with sunlight to produce the reds, oranges and yellows of spectacular sunsets. I then rigged up a routine to simulate those colours and drop the results into a copper-list to display the colours on the screen for every raster line. Unfortunately the resolution of the resultant colours being only 4 bits meant that my sunsets were rather... "lumpy". I therefore chose not to use them and went for the more simple "curtain" effect which just mixed in two lists of hand-picked colours, one for daylight and one for sunset. It looks rather mechanical, but the quality of the colours is better. I wish I`d kept the original routine, because it would have looked really nice on the AGA chipset, which expanded the colour resolution to 256 levels.
 
When we did the A1200 and CD32 versions of Fire and Ice, as well as adding an extra background layer, I also revisited the colour lists and put in the extra resolution to get really smooth colour fades. Those colour lists were all typed into the assembler by hand in hex, not done in an art package.
 

Lower Screen Banner

We had limited the scroll screen area to 192 pixels high to be ready for an NTSC version, should we need it. You only get 525 scan lines on NTSC TVs, which translates to 262 pixel lines, and there are certain processes that need to get done during the screen "off" VBlank time, such as getting any copper list changes done. Nevertheless I enlarged the screen with the land panel at the bottom. I decided to get self-indulgent with wiggling the smooth-scroll registers to make the water shimmer.
 
The first thing that I found out then is that time is very limited and you can`t get the copper to do an infinite number of things in the limited time it has in the horizontal blank time. Firstly you need to get the 4 bit-plane pointers switched over, then set the smooth scroll register, and start to switch the colours. There ended up needing to be one pixel row of sky colour with no other colours as getting 16 colour registers set up takes a while and the colours aren`t all ready by the time the display starts. So get the sky colour done first as it`s the first one to be seen, and don`t use any of the others until the next line. The next issue occurs at the waterline, we change the bit-plane skip factor so the same data gets re-displayed upside-down. Then we start altering the colours to darker ones, and on each raster line we alter the smooth scroll register, which is centred on the middle position, 8 pixels, and run a sine-wave through the subsequent lines so the water wiggles. This all added about another 48 pixels to the overall screen height. There were certain rules in the hardware manual about where you could start and end your display, which you had to stick to. 
 

First Levels

One of my initial game features was going to be some fire creatures that lived in pots, and then come out and fly off to various points around the level and, if un-stopped, start fires. I was using the Paradroid 90 patrol-route system, and had added a routine to analyse the network so that when a fire creature emerges, it chooses a target point on the network and finds the shortest route round the network to the target. Once it starts the fire, it then returns to a different pot for the night. It`s actually a feature I had initially used in a COBOL game called "Navigate".
 
The upshot of the initial tests was that since the fire creatures fly, they are difficult to follow on foot, or paw. They are also mostly off-screen and difficult to monitor, so the whole concept was somewhat flawed. 
 
We developed the pesky little Incas that fire darts at the player. Being quite small, we could have quite a few of them on screen at once, doing different things. We created a curly-haired king Inca who could generate new Incas too.
 

Slopes

I wanted to do a more complex ground surface system than just simple horizontal surfaces to walk on. This would include slopes and walls that could deflect bouncing objects, as well as provide surfaces to slide on.
 
I devised a two-part system to record the slope or surface of each character. Firstly I would define the angle of the surface using 4 bits, and then the other 4 bits was the offset of the surface down into the character for walking on. I then created graphics for all of the valid combinations that just showed the surface definitions. During testing I rigged up a keypress to tell the graphics plotter to use the surface definition to access the surface graphics instead of the real ones so that I could check that the surfaces were all cohesive. You mustn't leave holes for objects to fall through or escape.
 
We had decided that the Coyote should fire, spit, or bark ice-balls, rather than carry a weapon, which then got me to calculating bounce angles and sliding accelerations for the ice. This led to all sorts of physics fun when an ice ball rolls into a valley and needs to stop. Getting them to stop when resting between two opposing slopes took a few weeks to pick the bones from.
 
I had accepted that we wouldn`t be running at 50 frames per second due to the amount of plotting and physics calculations that were going on. I believe that Turrican 2 was using a lot of hardware sprites rather than software ones, giving it an edge. Running Fire and Ice with what I regarded as a reasonable number of objects was regularly over-running, causing stutters that looked and felt horrible. I reluctantly limited it to 25, knowing that it should never over-run that. I never saw Turrican 2 over-running, that was irritating!
 
Julian, Thomas and Holger came over from Germany to see us, on the pretext that they could tell us where we were going wrong and get the game running at 50 frames per second. After I had explained what we were doing and how, they agreed that the workload was too much for 50 frames per second. We explained to them the virtues of a triple-buffered system, then watched them retreat into a corner for a brief discussion before coming back and just saying "No". For the record, while your joystick input and display can suffer an additional lag of a 50th of a second, a third buffer can get you over short busy peaks as it buys you up to an additional 50th of a second of processing time to spread over a few frames.  
 
I had a set of control mode parameters for the Coyote that were tied to the level data. This was so that I could make the ice levels slippery, and the underwater levels more treacly. The other meanies also tapped into some of the values so everything got intertwined.
 
We didn`t feel that the control mode was quite right, it seemed a bit slow to some people. Renegade set up a meet with one Julian Rignall for me to show him the progress so far and see what he thought of the control mode in general. The upshot of the meet was that I needed to speed up the movement, jumping acceleration and gravity, everything really. Once I had done that, the coyote was moving a lot better. Unfortunately... changing those variables caused all sorts of upsets amongst the various meanies that I'd tuned up. Whilst gravity is shared across all the game objects, the initial jumping speeds, for example, of meanies are individually set. Jumps that used to cross gaps no longer did. I had to re-tune all of the meanies so far.
 
My tip of the day then is to get the physics set in concrete early on. Just to riff on that a bit: when designing a game and its software you need to keep on top of dependencies: which parts depend on which others. Altering something with no dependencies won`t have any unexpected consequences. Altering something with a myriad of dependencies can topple an empire. This is why I hate it if my code calls external code, you have a dependency on something that you can`t control, nor change, but someone else can... in the future. I`m now using SFML, a set of external libraries. I`m pleased to report that the recent upgrade to 2.5.0 didn`t even cause a ripple, all my code still compiled and no behaviour degradation has been noticed.

Weapons Systems

Weapons upgrades were the norm by 1992. They`re always a double-edged sword because you mustn`t require a player to have them to progress. If none are available then the player still has to have a chance, the extra weapons should only make things a little easier.
 
We could plant green disks around the level marked with the weapon that they give. The extra weapons were typically shot-limited. There are also question-mark ice-cubes that deliver multiple disks, so you can choose which to pick up. These can be hidden until you fire at them. Ice crystal balls also contain a limited number of disks. My favourite weapon was the super-bark. There`s also an ice shield, multi-fire, and big ice-bomb. Since we can`t depend on them being available, they don`t have massive effects.

The Clouds

The snow bombs are accumulated by collecting snow-flakes. Snow-flakes are produced when you fire ice into white clouds. Firstly they start to rain, then hail, and if you keep firing then they go into a cycle of snowing snow-flakes, which you should collect by standing under the cloud. When the cloud turns black, get out, there will be no more snow-flakes but there will be lightning. This can kill the coyote, any unfortunate nearby puppy, or any meanies for that matter.
 
Don`t confuse the white clouds with the permanently dangerous dark clouds in the Scottish levels.
 

Snow-Bombs

Snow-Bombs are shown as snow-flakes at screen top-right, under the lives count, marked with Ls. You can hold up to 8. This is by sheer coincidence the number I could display in the hardware sprites available.
 
To fire a snow-bomb, the coyote has to crouch on the ground, then hold the fire button.
 
Snow-bombs are excellent for bringing down flying meanies, and of course they freeze every meanie on screen at once. It`s worth saving a stock of them for big meanies.
 

Thawing Time

Meanies are deadly to the Coyote unless they are frozen by hitting them with ice first, sometimes multiple times. When frozen, they turn blue. There is only a limited time to smash frozen meanies before they come back to life. This thawing time shortens as the  game goes on, since the lands become warmer. That's about the only reason why the lands are in the sequence that they are!
 

Level Time

The sky fades swap over from day to night and back to day 7 times before the coyote gets a hurry up. The snowflake in the top left loses an arm after each day. The day and night lengths shorten as the lands progress. Mostly this doesn`t come into play, there`s plenty of time, but it focuses the player on getting the job done.
   

Development

We actually developed the later levels first, unwittingly, just because we had some graphics ideas for the hotter levels first. When we developed the game scenario of the coyote having to travel from his igloo in the Arctic to near the equator, we were obliged to put the colder levels first, and the Arctic level is the trickiest to play. Just watching new players slide about uncontrollably was something of a concern. I wonder to this day whether I should have just not had the coyote slide about, it doesn`t seem totally necessary. The skiers and the walruses do skate about, but that`s about it. Well it`s a bit late now!
 

Arctic Levels

Having decided that Cool Coyote lives in the Arctic, we built him an igloo. I requested lots of slippery slopes to launch the skiers. We also had the magic of the ice ladders and bridges. I had intended those to propagate through the other levels too, with the idea that as the lands got hotter, the ice would melt more rapidly. They make a reappearance in the Inca levels.
 
We also developed the puppies here. They are keen to stay with the coyote and will follow him obediently. You can also instil bravery into them by firing/barking. This makes them go ahead of the coyote, and since they can smash frozen meanies and not be hurt by non-frozen meanies, they can be very useful. Barking to make them go ahead of the player is the safest way of getting them to go through the doorways ahead of the coyote.





The intention was to locate the puppies on the levels and herd them to the exit door, while collecting the 6 key parts. Each species holds one key part. This provides a motivation to explore and deal with the meanies. Since any member of the species could hold the key part, you get a different game every time. To herd the puppies, you tend to be getting them to move ahead of you, and you do that by firing. That also tends to protect you from rapidly arriving skiers.

The rope bridges which sink under the weight of the player are a nod to Turrican. I would have preferred rope bridges that sank down a little more but I didn`t come up with a nice way of doing that.

 Scottish Levels

There's a lot of wacky stuff that comes from Scotland. I remember an old episode of The Goodies that featured the bagpipe spider, so I definitely wanted some of those. I also wanted the wild haggis, porridge, the Loch Ness monster and a castle. We also had some permanently moody storm clouds, hares, eagles, and bears with shields.
 
The ground is no longer slippery, like on the ice levels, controlling the coyote is much easier. I was finding that the meanies were a little too easy to freeze, so we gave the bears a shield. There`s an extra collision area in front of the bears that if it sees an ice pellet arriving tells the bear to raise his shield. It works well, they`re infuriating. You either have to jump over them and hit them from behind or use a special weapon that can hit them from behind.
 
The first wild haggis that you find live in the trees. They jump out one by one and run for it. If they hit the edge of the screen, they go splat. The solidity of the side of the screen (aka the edge of the world) has an important significance in that it absolutely has to stop anything from escaping, or the program will potentially pick up duff data and may crash. To embody that edge of the world as a real wall that you can run into tickled me. All of the other meanies just turn around.
 
Actually, to prevent any escape I had two columns of wall characters and each side, two rows of ceiling pieces at the top, and two ground pieces at the bottom of the maps and I had to stop the scrolling 2 characters inside the map edges to not show them. Nothing was getting out of my screen! I did that because since the meanies have to check the characters around them anyway then having unseen blockages can be done for free. At no point did I also have to say: "turn around if X < 2 or X > 4072 or Y < 2 or Y > 1076", all of which takes valuable time.
 
Inside the castle we had some naughty platforms in the wall blocks that only come out and can be stood on when you fire at them. They're sitting over the top of the porridge pool. We relied on the player trying stuff out and revealing the trick. Once they`ve figured that out it`s a case of getting an ice pellet to the next ones as you jump from platform to platform avoiding a bath in the boiling porridge.

 


The second-generation haggises live in the castle and can ooze off the end of walkways. When they get close to the player they can jump at him. Also in the castle are the pesky archers, These are best tackled from behind after they reveal themselves, but beware of others firing at the same time.
 
All games are enhanced by crocodiles, I`ve always said that. As we know, they can`t open their mouths if you`re standing on them, so wait until they close their mouths and then jump on them.
 
The Loch Ness Monster is sort of the end-of level meanie that`s nearly at the end, but mostly it`s the fish that leap out of the water. Those fish can also have a key piece, you do need to freeze them as you jump along Nessie`s back. 

Underwater Levels

These levels game me an opportunity to re-tune all of the movement speeds and accelerations to get some slower movements, especially gravity. I realised that we couldn`t use the ice bridges and ladders underwater, they wouldn`t look right, what with the dripping melt-water, underwater. I had a couple of different mechanisms to get upwards: there were big air bubbles released by sea anemones, and then there were the clams. I spent a long time trying to tune those, almost as much time as many people took to master them. The trick with the clams is built into the coyote control mode. He has a gravity-altering downwards pull when jumping. I put that in as you have less control while jumping, but it might be useful to dodge stuff to increase the downwards speed a bit, in the same way that the jump height can be extended with extra up joystick. The Rainbow Islands control mode had some interesting attitudes towards gravity and there's not a lot you can do with a switched joystick to indicate your intentions to jump a little or a lot, so we have to improvise. So, back to the clams: the spring you can get off the clams is proportional to how hard you land on them. This in turn is connected to how high you jump off them in the first place, and if you then pull down at the right time you can get some extra speed. Then it's a case of applying up stick as the right moment to maximise the jump as the clam springs open. A very slow speed landing on the clam just causes it to close.

I had always intended that the coyote would have accessories, and the scuba mask was one such. We realised that the landscape was more severe and there were many lifts, and the puppies were not smart enough to use sprite-based platforms. We also didn`t have any small enough scuba masks for them. The coyote control mode was able to handle the character ground pieces and single flat sprite surfaces, so we could do moving platforms, that was it. I play Ray-Man Legends and can only admire the variety of moving and static surfaces that all the objects can traverse. 

Phillip was getting into his graphical stride by the time we got the undersea levels. He was also getting a feel for how many frames of animation he was allowed for the level. Every object in the game is custom coded, each with its own program, animations, and rules, nothing is table-driven, so if he could draw it, I could make it move. The meanies had fairly free movement in the levels, especially fish and birds. If they left the screen they would be purged, and recreated if their start position was on the leading edge of the scroll again, ensuring that nothing appears out of thin air in full view.

Phillip was working on a propeller-driven animated fish that was moving along nicely, and then he showed us some frames of the fish rotating round to face the other way, and it really looked like a solid 3D object. He'd done it all by eye, we had no 3D graphics tools to help. I remembered being so impressed that he had managed to create this object with limited colours. I was more than happy to spare the animation frame space for the turnaround. He did something similar for the squid. We had lots of bubbles coming from objects. Some of the rising bubble streams were animated characters, others are software sprites.

It was when we got to these levels that we realised they were big and difficult to remember where you were going. That`s when we came up with the mini-map. This has to scan the character blocks and pick out 1 pixel per 4 x 4 pixels in each character for display.
 
We also created the helpful hint arrows to appear in many places if there is little movement, to give the players a hint. I was a bit naughty with secret jumps in some caves that give shortcuts to secret levels, or just advancement. There's no such thing as a pointless cave in the game. There might be treasure, or a meanie that you need to find, or an exit, albeit largely invisible. I think I might have a small sprite that appears every now and again where there's a secret jump spot if I was doing the game again, especially since I can no longer remember the routes!
 
There are also "The Eyes" in various dark places. These have no real bearing on the game but they do look towards the player when he`s nearby.

The turtles in the game are moving platforms to jump on and reach places that you might otherwise be unable to do. Most people notice that the turtles can`t be frozen, but don`t realise that you can jump on their backs and take a ride.
 


 
I`m also responsible for draining all of the red out of the colour palette for these levels. I don`t know if that was quite the right thing to do, but no-one stopped me. Makes little difference to someone who is red-green colour-blind because our issue is that we don`t have the full quota of red cones in our eyes and so red gets swamped by green and we can`t tell brown from orange from green from red. And yes, that is infuriating!
 

Jungle Levels

I was keen to get the caterpillars in, as my nod to the old arcade game, which I spent a lot of time playing in the pub on a Friday night. I wanted to get them to split if you hit the middle of them, though that didn`t fit with the way the rest of the game worked, so I had to settle for freezing them. They are a multi-part object, and I could make them long or short.



I realise now that I made a mistake in the way the coyote restarts after losing a life. The game remembers the last piece of solid ground that he was standing on for a restart. For this level though we had a straw bridge above some fly-traps. The straw blocks can be destroyed by ice-balls and snow bombs, making the bridge much harder to cross. If you stand on the destructible blocks and then fire a snow bomb or otherwise destroy the block you're standing on, and then get shot by an arrow, it won't recreate the block but it will put you back to stand where it was. You then repeatedly fall into the fly-traps until all your lives are lost. If it had happened to me in testing I`d have sorted it, but it never did, rather embarrassing, really. It may well be fixed in the CD32 version, possibly the A1200 version too.
 
 
 
Phillip took a few attempts to do a multi-layer animation for the waterfalls in the secret level. He had to do 3 separate animations and then overlay them. They really do look impressive. Many people might not see them if they don`t jump down the rabbit hole on the second level. Another one for the little tempter sprite to hint that it's OK to go down. There are some tricky jumps to negotiate down there, mind. There are also points to collect, and a bone-us life.

We tried to get a 3D feel to the jungle scenes by having burning spears lobbed from over the other side of the water, along with lumps from the volcano that goes off periodically. Interestingly it`s not featured on the video I watched, so apparently it can be avoided! Maybe that's why it is a good idea to take the rabbit hole at the beginning of the level. 
 
The main tip for this level is to keep firing as there is danger coming from everywhere. The over-ground levels are flat, a consequence of me needing to colour the river with the copper colour-fade. Let the puppy go ahead and pick off the meanies that you have frozen. Just don`t use the snow-bombs near the straw bridge above the fly-traps, as in the picture above. 

Inca Levels

These levels were the ones we started with. At the time, the game plot had not been thought out. We had the Inca minions in various walking and jumping incarnations. I must have been thinking about Indiana Jones as I wanted to do a runaway mine-cart set piece, with a trackway that collapses behind the cart. Tuning that up to get the cart to behave correctly at the end at just the right speed was a nightmare. When we re-tuned the speeds it all fell short again and I had to re-work it. Jason Page and Phillip were suggesting ideas for more features. I suspect they had played a lot more platform games than I had. It`s definitely great to have more input, better to have too many ideas than too few.  
 
I was keen to have more smaller meanies rather than fewer big ones. When the game is only partly written then you don`t know how big it`s going to get. The number of character blocks used for the backgrounds is variable, but generally the more the better, and that space is shared with all of the sprite animations. There are lots of moving platforms, rotating pendulums in different ways, others that fall. There are also collapsing platforms, spikes, a nice big rolling ball, boulders carried by birds that just shouldn`t be that strong...
 
 


When you`re putting your first levels together, you get a feel for how difficult the level is to play, and therefore you can design some easier or harder levels around that. Never assume that the first level you create will be the first level in the game. In nearly all cases I have had to make easier opening levels for my games. Once I watch newcomers struggle with levels that I find easy because I know how they work and have played them a lot, I realise that experience is colouring my view of the difficulty. 

There are a couple of set pieces in the Inca temple that require you to be armed to the teeth. The above picture shows one place to stock up on snowflakes from multiple clouds. An aggressive special such as the super-bark is also recommended, or one of the multi-fire ice bombs, the shield isn`t going to help so much since you`re locked in with something, and it`s you or it.

 
 This is actually a photo of the PC version. We also finished a Sega Megadrive version, along with the ST version. I actually have no recollection of the ST version, not even how we would have achieved such a thing. Eldon Lewis did most of the Megadrive conversion but I`m not convinced that it got released.
 

Bonus Levels

The number of mechanisms needed on each level was high, each one requiring to be individually programmed in our Alien Manoeuvre Program (AMP) language. I fancied something a little simpler, and wanted to do a nod to my other platform game: Gribbly`s Day Out.
 
I also wanted something a little more wacky, so we set the scene in rock islands in the sky. It`s definitely a nod to the work of Roger Dean, which I suspect inspired Avatar too. Unobtainium, indeed!
 
There are many presents all over the levels, but they are being picked up by the meanies, so you need to get round as quickly as possible as each one scores more than the previous. Then you can decide whether to take out the meanies on the way to stop them from picking up the goodies. Since they`re arriving from the top then it makes sense to get up to the top of the level to stop the meanies. I had Gribblets in there too, just bouncing around, like they do.
 


We also left little meat pies lying around as food for the coyote, but they sprout legs and run off in a short time, behaving in a lemming-like way at the ends of the platforms. Get to them as quickly as you can.
 
Being bonus levels, even if you fall off the lower levels, you don`t lose a life, it`s just a bit of fun before the final level. There are a couple of "Bone-us" lives to be collected that should be useful.
 

Egypt Level

Having drawn the fire creatures and the pots within which they live, I was determined to at least use them, albeit in a more minor role. They were quite wide graphics with a number of frames, which meant they were taking up quite a lot of memory, and would have been expensive to have on every level. Without an editor for the patrol routes that the fire creatures follow, the co-ordinates of all of the points have to be put in by hand, and that gets laborious too. You have to balance the time spent entering and debugging the data against the time spent coding and debugging an editor, and then entering the data. To this day I`ve never written an in-game editor. John Cumming wrote our background editor in STOS on the Atari ST that we used for Rainbow Islands, Paradroid '90 and this project. I never had a level editor for any of my C64 games, everything was built up from smaller blocks. Some of the earlier ones were listed on paper.  
 
 
 
 
We also wanted quite a large end-of-level/game meanie. The rules generally are that the larger it is, the less frames of animation you can have. That's both because of the memory cost, and the time it takes to draw the graphics. The former is what stops you, of course. The end-of-level meanie is the end-of-game meanie and we wanted him to be pretty tough, but beatable. Of course when you know what you`re up against then you can pace yourself  bit, don`t use all your weapons at once. No spoilers here, move along.
 
 

Sounds

As usual I waited until development was nearly done before getting the sounds added. It`s best to get them done all at once, and by the same person. Also, the music needed to be created. We included a music on or off option, which creates additional issues. The sound effects compete with the music player for the 4 available sound channels, and for your attention. When the music is off there needs to be enough sounds to make the game sound full enough, but when the music is on you don`t want to lose half the instruments to the sounds, nor do you want the sounds to be covered by the music.
 
As usual, Jason Page did a great job, as there are a lot of sound effects. We ended up with 15 tunes, 26 resident effects for all levels, and then the levels each had their own set, making just over 50 more effects. We used to give every effect a priority, so one effect could only interrupt another on a particular channel if it had a higher priority. That can be used to ensure that important effects get heard, or that long effects get to complete properly.
 
For the title music we wanted the coyote playing the piano and barking in the music where Jason had included that sound. For that, the music has to let the coyote animation know when to bark. That was a slightly odd communication, since the music player is playing on the interrupts and might cut across the main cycle at any point. I expect that a fairly simple global variable just shouted "Now!" when a particular sample was played. Many years later I was playing Mario on my Wii U and we saw the meanies shimmy in time to the music and I thought: "That`s a good idea! Wish we`d thought of that."
 

A1200 AGA version

We had a short while to get set up for the Amiga A1200 at the end of the project, and to produce an enhanced version. The thing I wanted to do most was get the game running at 50 frames per second, which the hardware was easily capable of. Initial experiments showed that I could change the definition a Second from 50/2 to 50. I would then have to adjust the control mode accelerations and top speeds, and reduce gravity. Oh, the power.



As I alluded to above, meanies that jump had their own upwards accelerations since it ultimately determines how high they jump, and how quickly, likely related to their weight, which of course we weren't simulating. There was another bunch of game objects that I realised would need adjustment: there were quite a lot of different pendulum platforms that needed to be slowed down, and I remembered how long it had taken me to tune them all up. Whilst you can pretty much just halve the speeds at twice the frame-rate, the accelerations need a bit more thought. It would also have meant a full and length re-test of everything.



I also remembered the days I had spent tuning up the runaway mine cart to get it working just so, and when I revised the speeds I had to re-do just about everything. I reluctantly decided that it was too much work in too short a time. Similarly re-doing all of the graphics in more colours when the originals took about 30 man-months wasn't a go-er. Knowing that the A1200 could do 2 play-fields of 16 colours each, we set about producing some backdrops in 15 colours, plus upgrading the sky colour fades, and get that parallax scrolling. The title sequence also got its own back-drop. We had the Coyote playing the piano in a hall with lots of animals looking on.



We dished out the level pictures to the graphics artists. The backdrops were just pictures, not made of character blocks, as there was plenty of video RAM since the whole game fitted into a half meg A500. That made the pictures easier to produce, the guys could just pick their palette and draw away. I can't remember exactly who did which ones now, but I do remember John Kershaw being particularly impressed with his undersea shipwreck, and I liked how Colin Seaman`s Sphinx on the Egyptian level had apparently huge size in the distance, plus the cool camel chewing away. "It`s all about the perspective." he told me. Another "trick" is that distance causes the contrast to reduce, so the palette colours get compressed a little. Colin is an amazingly fast artist and worked to a very high standard, I have a feeling that he did some of the other backdrops too.



I put some extra foreground rocks into the first levels and rigged them to parallax scroll with a simple multiplier. This helped the cave areas where you couldn`t see the parallaxing background layer.



The snow-bomb got a giant snow-flake graphic, made out of smaller parts. Plotting lots of objects suddenly became not a problem. It was all about enhancing the picture without having to re-tune and re-test too much, time was very limited.
 
On the jungle level we split the original background into two layers so that we could parallax scroll the trees from the other side of the river. I had to deal with the change in co-ordinates of items launched from the other side of the river, including the lumps from the volcano.
 
The game completed sequence was a complete upgrade as we could do a new luxury inside-the-igloo background. The original one was a bunch of animated characters just to show what it could do when there aren't too many sprites to plot.
 

Christmas Demo Version


 
 
We had the opportunity to produce a cover disk for Amiga Power. Being Christmas time, we based a level on the original snow level, and let Phillip loose with the graphics sheets. The Coyote got himself a nice red Father Christmas coat, and the penguins have party hats. John Lilley added a Christmas raft of pick-up presents and we had to build in an end sequence for the completion. We also had to put in a new one-level banner at the bottom of the screen.
 
 
 
 

CD32Version

We were loaned a CD32 and a controller in order to produce a CD32 version of Fire & Ice. We also had a development budget to pay for 6 weeks` work. Our SNASM development kit connected the assembly on my PC to the Amiga via a card expansion device, it wasn`t going to interface into the CD32. Our 6 weeks was going to be spent getting the A1200 version booting and running on the CD32, hooking in the CD32 controller with multi-button support, for the first time ever, and playing CD tunes from the disc rather than using chip music.
 
We had to cut a CD, which took a while back then, and the state of the CD writing software was such that they hadn`t got any buffering so you had to make sure the PC didn`t try to do anything else while it was making a CD or it would mess up.  
 
Jason created a new set of music on CD. He had better equipment at home so he stayed at home for a week to use his gear, including a Korg M1, Akai S950, Roland JV880, and Cheetah MS6. We had been using samples on the Amiga, but nowhere near CD quality, and the music was orchestrated by our software, creating full CD tracks was new for us. Playing CD music freed up the sound chip to just do the sound effects. As Jason noted, he  included ambient sound effects around the CD music too. The only issue is that to loop the music there will be a pause while the CD laser finds the start again.
 
 
 
 

Finally

This game felt much more like a team effort than, say Paradroid '90, as the direction of the game was being set by more of us. It taught me that platform games need a lot more variety in them than I expected, It was nice to finally do an Amiga-led project, and I`m especially pleased with how nice the A1200 version looked, and then how the CD32 version sounded too.