Introduction
Over the past few months I've seen a number of reviews or play-throughs of our games on youtube. This has shown me any number of game features that I had forgotten. It shows me how blurred things become over time.
Scale
My first Dragon 32 project was converting 3D Space Wars. This took me around 6 weeks to code and add a few graphics. This is just a guess; but I suspect there were around 6,000 lines of assembler code in there and the rest was graphics and storage. I was using an assembler on the Dragon 32 and a DragonDOS disk drive. I had to split the game code into manageable lumps because the 32K of RAM had to be big enough for the editor, the assembler, the source code and the object code.
I do recall that we had to load the assembler into different memory locations to be able to assemble the various blocks of machine code into their correct locations. On the one hand 6809 code can be assembled relative so it uses branches rather than jumps, but at the same time fragmenting the code like we did meant that we had to load the various code lumps into absolute locations so that cross-calls knew where the code was.
Within the 6 weeks of development I created the code out of nothing, we had no library code to refer to and no monster libraries of code on the then non-existent Interweb. All we had was a 6809 assembler reference book (which I may still have but haven't seen it recently).
Since Steve Turner was coding in hexadecimal machine code on the Spectrum with only 4-character labels for jump locations, I was the first to create source code for one of Graftgold`s games. I was creating my own routine names and variable names.
By the end of project I knew all of the routine names and the location of most of the variables in the "zero-page". For the technically minded, the C64 6502 chip allows short fast instruction access to bytes in the first 256 bytes of RAM, i.e. 16-bit addresses starting with a $00, where each 256 bytes is a page, hence zero-page. That`s where you want to put all of your variables, where you can access them quickly and with shorter instructions. The 6809 allowed any 256-byte page to be designated as its fast access page. Whilst you could change the page number in flight you probably wouldn't unless you had 2 games in one set of code. I didn't use page $00, the OS was using that, and I needed the OS to poll the analogue joystick.
When we finished a game we would print it on the dot-matrix printer, at great length, a module at time. We didn't have space in the machine to include code comments so we added them to the listing in pencil. This process usually took about 3 days. It gave us a break from coding. I kept all the listings under my desk in one folder and it was quicker to refer to the old source code on paper than load up a different module than the one you're working on. I'm still looking for that blue folder. I know it`s around somewhere.
The process of game development then was that I'd play the game for half an hour or so, writing down any adjustments that I wanted to make, or bugs that I'd found. Since the game was split into separate modules I wanted to work on each module in turn once. I'd therefore load up the first module and see what bugs or changes needed making to that module and do those, then load up the next module.
Sometimes a module would expand so much that it would encroach on where I'd defined the next one to start. I'd either have to move a big routine to another file or relocate the next module in memory up by 256 or 512 bytes. This might cause a cascade and I'd have to move all the modules along a bit. I had an address for the top of the module, and then offsets from the top to the various jumps to the subroutines inside the module.
I used a jump table at the top of each module to get from a known address to one deep in the module, in the same way that modern DLLs do it. Trying to call routines deep inside a module would have been very high maintenance on keeping the addresses up to date. I figured it would slow down development a lot since one mistake would probably cause the computer to lock up and take ages to debug. Even at the end I could have adjusted all the calls to make the game slightly faster but any last-minute bugs would again be difficult to solve. I tried to organise it such that often-used calls were done in the same module. This would use a short-range relative BSR branch-to-subroutine instruction.
The Dragon assembler was pretty fast, and so was the Dragon 5.25" disk drive. The assembler was actually a multi pass one, rather than just a two-pass job. If it needed to do more passes to resolve some more forward references then it would just get on with it. I could probably do a whole book on why keeping C to a one pass compile has caused me so much grief, but I suppose since they released C in 1972 then they're not going to change it for me now.
The Dragon assembler was pretty fast, and so was the Dragon 5.25" disk drive. The assembler was actually a multi pass one, rather than just a two-pass job. If it needed to do more passes to resolve some more forward references then it would just get on with it. I could probably do a whole book on why keeping C to a one pass compile has caused me so much grief, but I suppose since they released C in 1972 then they're not going to change it for me now.
The Next Game
We would write the next game by stripping out all the game-specific routines from the latest code, leaving the utility routines that we'd need next time. All of the plot routines would stay, including the font plotter, and the sound routine. We'd spend a little while seeing if we could improve those routines we were keeping.
When I switched to the C64 I had the Commodore Macro Assembler and the very s-l-o-w 1541 disk drive. I could create one single program from assembling multiple files. The only rub was that this process took about 30 minutes.
Once I`d attempted to fix all of the bugs and add any new code, it was time for the assembly. During this time the 1541 disk drive would grind away, and I`d switch the TV aerial selector to the other C64 and get on with any graphics alterations or additions I wanted to do. I would dread that there was a typo in the code and the assembly would fail. It wasn't a sophisticated system with a make file so it knew whether it would need to recompile only certain files, it insisted on doing the lot every time. It also occasionally decided to destroy the floppy disk contents, so a source backup was always a good idea before a compilation.
By the time I had completed Uridium; the code was probably nearer 10,000 lines of assembler taking up about 16K of the machine. Some of the routine names came over from the 6809 code base, which helped with continuity and "The Zone", but since the machine architecture was so different there was little in common. The whole program was split into maybe 10 files, and I still knew which file had which routines. You couldn't afford to keep loading the wrong source file. I kept a list of modules and routines as a quick reference.
PCs Take Over
A big change occurred when we got our first PCs in 1987. They didn't have hard drives, only twin 5.25" sloppy disks, but they did have about a Megabyte of RAM, of which they could bring 640K to bear in a DOS environment. Windows hadn't been invented! We had to boot up DOS from floppy disk in the morning. We had enough memory to set up the DOS files in a RAM disk for quicker running.
We bought the EC editor, which must have been pretty popular because Visual Studio 6 at least had EC compatibility modes. I seem to recall that it was still under development because we had to contact the author for some advice or updates on at least one occasion. It was a nice editor.
We bought in some cross-assemblers for Z80 and 6502 and had to key in any code we wanted to keep again. I can't think how we'd have got files off of a C64 floppy drive or Spectrum tape onto a PC. We connected the PC to the C64 or Spectrum through the parallel port. We had to write a small code loader to run on the target machine to read off the parallel port. I continued to use the C64 to draw sprites and fonts. We would still load those from C64 floppy drives, and of course the final save to turbo tape had to be done on the C64.
We still didn`t have a debugger as such. We had my simplistic monitor that allowed us to dial in a memory location to look at and see the value there, and update it. Steve took the design a bit further and had it display a few consecutive bytes. Since we were always poking around in the game`s variables then it kept all the addresses and expected values very fresh in our memories.
We bought the EC editor, which must have been pretty popular because Visual Studio 6 at least had EC compatibility modes. I seem to recall that it was still under development because we had to contact the author for some advice or updates on at least one occasion. It was a nice editor.
We bought in some cross-assemblers for Z80 and 6502 and had to key in any code we wanted to keep again. I can't think how we'd have got files off of a C64 floppy drive or Spectrum tape onto a PC. We connected the PC to the C64 or Spectrum through the parallel port. We had to write a small code loader to run on the target machine to read off the parallel port. I continued to use the C64 to draw sprites and fonts. We would still load those from C64 floppy drives, and of course the final save to turbo tape had to be done on the C64.
We still didn`t have a debugger as such. We had my simplistic monitor that allowed us to dial in a memory location to look at and see the value there, and update it. Steve took the design a bit further and had it display a few consecutive bytes. Since we were always poking around in the game`s variables then it kept all the addresses and expected values very fresh in our memories.
We were still working in relative quiet as there were just the two of us working in a small office behind Steve's garage. There was just space for two desks side by side, piled high with bits of electronic equipment. We were still using TVs for the monitors to the target machines, though we decided to use amber monochrome monitors for the PCs, which made the source code appear nice and clear. Having that quiet environment was usual I suppose for the way we had both worked in our previous jobs and allowed us to really concentrate on the job. We also worked 9 to 5, which was quite unusual for games programmers of the time, many of whom only saw a morning from the other end as they were going to bed.
We didn't even think to install a stereo, not even a radio or a cassette player in the office. We maintained the professional hours and office environment. that we were used to. Only later when we expanded into a bigger office did we get a stereo, which led to the Tanita Tikaram incident. I'll leave that for another time! I've still got the mental scars.
We didn't even think to install a stereo, not even a radio or a cassette player in the office. We maintained the professional hours and office environment. that we were used to. Only later when we expanded into a bigger office did we get a stereo, which led to the Tanita Tikaram incident. I'll leave that for another time! I've still got the mental scars.
The Big Switch to 16-bit.
By the time I got to move onto the 16-bit machines Graftgold had grown to 7 of us. Dominic had already written a pre-emptive multi-tasking system for the Atari ST, with a view that an Amiga version was not far away, and by making calls to his OS the differences in hardware would be invisible to us. Along with that came linked lists and allocated memory. These changed the way we constructed our software. The joys of these are well-known to all C programmers, and 16-bit assembler programmers. Likely there aren't so many 32-bit assembler programmers since the 32-bit and up CPUs are not really designed to be used with assembler any more, it`s just too complicated.
The biggest change then is working within a team. I had to call someone else`s code on a frequent basis. I can say it really helps having the author of that code on the next desk. It means you can get new functionality added if you need it. I was also doing less graphics, actually none at all for Rainbow Islands, and only the fonts for Fire and Ice and Uridium 2. I did do some of the background pieces for Paradroid 90.
I had all of the game code in one place and was co-ordinating all of the graphics as they went into the games. In the early games we were saving graphics from LBM bitmap edited sheets into .dat files and adding the sizes into the code manually, followed by including the raw graphics with an incbin statement one by one. We would use 16 pixel wide sprites where we could, or 32 pixel wide sprites. We could also gang a 32 followed by a 16 or use multiples of 32 pixel sprites for the big bosses. The Amiga blitter chip was pressed into operation for plotting, but we had to enlarge the data for the sprites to include one mask for each bit-plane to be able to blit the whole sprite in one operation, else we had to blit each bit-pane separately.
Over the course of 4 games there was a lot of commonality of the plotting routines, object movement and general mathematics. That helps to keep you "in The Zone". Even if you choose to do something a different way you can still use the same routine names. Of course it's all the differences that take the time to write. Once we were using hard drives to store the code it became easier to put code into more logical file names so the number of files expanded. We used file types of .XX and .XXH for generic files of code and headers, and then split ST- or Amiga-specific code into .ST, .STH, .AM and .AMH files.
I pretty much still knew where everything was, and it also helped that by the time I was writing Uridium 2 I was also providing support for Virocop, keeping me familiar with all the code. The file sizes of especially the routine that contained all of the game object subroutines were growing immensely. Rainbow Islands had the Mk I simplistic movement controls and I honed those down for Fire and Ice with experience. Once you've gone a certain distance down a path, if you realise there was a slightly better path, it's still not worth going back over everything you've written. Save it for next time.
We were able to put decent comments in the code, which really is quite important for assembler, but we weren't printing off listings because they'd have taken about 1,000 sheets of fan-fold. Having the code in front of us for even longer development times kept the familiarity with the code, and the better code editors that could load more files at once allowed us to see the code easily without a listing.
When most of the code is your own, there is a familiarity that you can`t get with other people`s code. You have a confidence in changing routines because you know how they`re called and by which functions. Changing other people`s code requires a lot more caution and experience. Indeed I have rewritten other people`s routines in the past so that I better understand their limitations, or in some cases to widen them. I have even rewritten entire COBOL programs in some extreme cases, as I have mentioned in previous blog pages. Understanding the code is vital, and it`s very much harder to do that if that code was written by someone else, and likely has been amended by more people over time. It can become gnarled and odd-looking.
I don`t think I`ve ever looked at anyone`s code and thought: "Wow, that`s really neat." Other people`s code just isn`t familiar enough to look nice, even if I`ve shown them how I want it done. I can only conclude that anyone who has ever seen my code must think the same. I guess we all think we`re the best programmer in the world, and somehow we`re all right. I know I am, I`ve got the trophy to prove it! :-) I think it`s made of plastic...
As time goes on even our own code becomes less familiar. Firstly, there's more code to consider. I dread to think how many lines of code I`ve written over my lifetime, and in how many different programming languages. I don`t expect I could write any COBOL now, nor any assembler, you just have to be "in The Zone" at the time.
When most of the code is your own, there is a familiarity that you can`t get with other people`s code. You have a confidence in changing routines because you know how they`re called and by which functions. Changing other people`s code requires a lot more caution and experience. Indeed I have rewritten other people`s routines in the past so that I better understand their limitations, or in some cases to widen them. I have even rewritten entire COBOL programs in some extreme cases, as I have mentioned in previous blog pages. Understanding the code is vital, and it`s very much harder to do that if that code was written by someone else, and likely has been amended by more people over time. It can become gnarled and odd-looking.
I don`t think I`ve ever looked at anyone`s code and thought: "Wow, that`s really neat." Other people`s code just isn`t familiar enough to look nice, even if I`ve shown them how I want it done. I can only conclude that anyone who has ever seen my code must think the same. I guess we all think we`re the best programmer in the world, and somehow we`re all right. I know I am, I`ve got the trophy to prove it! :-) I think it`s made of plastic...
As time goes on even our own code becomes less familiar. Firstly, there's more code to consider. I dread to think how many lines of code I`ve written over my lifetime, and in how many different programming languages. I don`t expect I could write any COBOL now, nor any assembler, you just have to be "in The Zone" at the time.
In Conclusion
It`s great to see people take the time to video our games played all the way through and posted on youtube. These act as a reminder to me of what we achieved in putting the games together at Graftgold. It also proves that they can indeed be played all the way through. I can`t say that I`ve completed many other games, or at least got them to loop back round to the beginning with the difficulty increased. Arcade Scramble is the only one I can recall.
As time has passed I find that I have forgotten the smaller details in the games, such as the exploding fireplace in Fire and Ice Scotland, and the Victory Points in Uridium 2, so just when I was thinking that our games could have had more complexity in them, I see them again and it's all there.
I built the games to play differently every time rather than be totally rigid like some scrolling arcade games. That means even if you`ve watch a video, your game will play differently, every time. That hopefully is what keeps them interesting and is one of the reasons why people are still playing those games today, some thirty plus years after they were released.
When you`re writing a game you need to concentrate on everything you`re doing and using, all the time, just to stay "in The Zone".
As time has passed I find that I have forgotten the smaller details in the games, such as the exploding fireplace in Fire and Ice Scotland, and the Victory Points in Uridium 2, so just when I was thinking that our games could have had more complexity in them, I see them again and it's all there.
I built the games to play differently every time rather than be totally rigid like some scrolling arcade games. That means even if you`ve watch a video, your game will play differently, every time. That hopefully is what keeps them interesting and is one of the reasons why people are still playing those games today, some thirty plus years after they were released.
When you`re writing a game you need to concentrate on everything you`re doing and using, all the time, just to stay "in The Zone".
0 nhận xét:
Đăng nhận xét