Subject: [stella] Qb: Post-Mortem From: "Andrew Davie" <adavie@xxxxxxxxxxxxx> Date: Thu, 15 Mar 2001 01:41:39 +1100 |
I thought I'd jot down some of my thoughts on Qb, now that I truly believe I am in the last week of development on the game. Ruffin requested a post-mortem, so here it is. I'm pretty tired - this is typical of a project for me.... getting it out is the programmer's equivalent of childbirth. You really have to push hard, or it won't happen. I tend to work long hours, into the wee hours of the morning. I'm very happy with what I've ended up with - quite a playable game, and essentially the same game as my original on the Atari 800. It's turned out pretty much exactly as I would have planned it, had I planned it exactly :) But I didn't plan it exactly... each step seemed to be a natural one, and I just did the next thing that needed doing. It helped a lot, knowing exactly what I wanted before I started. As I wrote to the list earlier, I'd spent some time thinking about if it was possible. I'm not really sure if/when I knew for sure that I could do it. Obviously, looking at how tight things are now, there were major problems compressing the amount of code/graphics into the ROM, and let's not forget the RAM usage (multiple overlays, etc). It is amazingly functional for 4K. If I'd planned out all of that, how much code/ram needed... I'm not sure I would have started. A large part of time, during my early programming years, was spent playing around trying this and that... just putting in anything and everything... where whim took me, without any gameplan, so to speak. That is where the majority of time goes. If you know what you want, and stay focused, then you can get things done quickly. I think Qb was done pretty quickly... well under 50 days from first keystroke to last. The thing that sticks most in my mind is the optimisation cycle. It constantly amazed me how, whenever I really needed to squeeze some space out of the code (which was just about every day for the last three weeks), I could find almost as much space as I needed. I recall being jam-packed, then saving 70 bytes, then 'spending' it, then saving another 190, then spending that, then finding another 100... etc. I guess each iteration the code was becoming more and more esoteric and less structured. I started thinking about doing some playing on the 2600 (again) sometime in January. I couldn't stand the thought of programming for some months before that (I tend to burn out, and was at that stage, then). However, I found the supercharger, and got it set up and found my (very old) PUSH demo. The push demo was an aborted attempt at a sokoban clone - in particular, it demonstrated a 4-colour playfield by multiplexing playfields of different colours, in time. This was not well-received by the list (such is life!), but one thing that stuck in my mind was somebody's comment (about a fast-moving square on the screen)... "that's playfield graphics animating? cool!" or something like that. I hadn't (and still haven't) seen a lot of 2600 games (and played even fewer). But there didn't seem to me to be a lot of games which animated/used the playfield. Mostly the playfield was used for walls/pictures... but nothing interactive. Yeah, I'm sure there are some games that do it... my point is that this is what I was thinking about back then... and what was on my mind when I picked up the Supercharger again. As I said, the Sokoban-clone (push) didn't make it... but it was my first experiment with animating playfield. The blocks were all playfield. So, this was the first bit of code I picked up... just to see what I'd done. I started to think about my Atari 800 game 'Qb' and thought that the blocks in Push were pretty similar to blocks in Qb. So I thought I'd set up the dev environment again, and see just how many blocks I could draw. This required me to set up a playfield, of course... but the essential code was already there. I wrote it all very general-purpose - using equates for the sizes of the blocks, calcualtion of RAM usage, etc.... however as I settled on an actual size (4x4) things kind of got more and more hardwired (mainly for efficiency), and the generality suffered. That wasn't a problem, though... just a natural progression from a testbed to an actual game. Generality was compromised for functionality. Hold off on the compromise as long as possible :) So, it took me a night to experiment and I had 7 blocks shifting around fairly randomly (using an eor-draw). I posted this to the list on 30 January. At that stage I clearly had in mind Qb, and was thinking about how to implement the game on the 2600. I was quite happy with the kernel, as it had a fair bit of processing time left, though I was rather concerned about RAM. Kind of gung-ho that I'd find the RAM if I needed it :) It only took me a few days to mock-up a target display, as well as a main playing grid. Really, these sorts of things were rather straightforward, as I didn't have to think much about resources... I had a whole 4K. Mostly you could call the first couple of weeks an experimental stage... I was just playing, and prepared to drop the project at any time. In fact, the feedback for the first few weeks was (to me) most disappointing. Nobody seemed really interested. Oh well. One problem was that I had balky emulators running on my sytem, which didn't lock to the video card frame-rate. So, what looked normal speed for me... was in fact about 700x normal speed :) So the code posted to the list animated/crawled like a slow snail. It took me quite a while to realise this. Once I fixed up the speed, people started paying a bit more attention. I guess I was seeing something different to everyone else. At this early stage, people were starting to suggest code optimisations to me. I'm in two minds on this one. The chances are high that you will need to rewrite your systems anyway, so I prefer to get it working, first... and then optimise it if you must. A typical example of poor optimisation was my use of a 256-byte table for the sprite-draw routine. I figured (incorrectly) that it would be quicker to have a ROM-table, so spent some time writing code to use the table (and to avoid branching in my kernel). I was pretty proud of it! Only, it was crap - as Thomas rightly pointed out. The moral is, don't be too proud to toss your brilliant work away :) About a week after starting, I had a rudimentary demo which let you move blocks around, to their correct positions, even... and a rudimentary target display, and was working on sprites. This was pretty rapid, but there was very little 'guts' in there. The gameplay and polish is what really takes all the time. At about this stage, I was really beginning to learn new things about the 2600. In particular, tight timing of kernels, and how sprites worked, tv-frames were generated, etc.. Here the list truly became useful - many many times people like Eckhard, Thomas, Manuel, etc.... helped me out with suggestions and comments and answers. It would have been much more difficult without this help, and so the [stella] community truly deserves part-credit for the game :) Thanks! I was freely sharing my source code, pretty much from the start of the project. I guess this was one incentive to keep the comments and structure fairly good... but fundamentally I'm a programmer who just needs to have good coding style, anyway. Things get too complex for me to remember, and every comment helps :) I also feel that it is the nature of this [stella] community that we give what we can, and get what help we need. Sharing my code wasn't so much me saying 'hey, look how well I comment', but more... here's what I've done and how its done. The benefits from sharing my code (optimisation, suggestions) were enormous, and I would recommend it to anyone. Don't be shy :) By a week into development, I only had 6 bytes of RAM (!!) and 1300 bytes of ROM left. I was concerned about the RAM, but ROM seemed plentiful. In the end, it would swing the other way around - as I developed a neat overlay system (which you should all use!!) - which essentially removed my RAM troubles for most of the rest of the project. ROM, however, became an increasing problem - especially towards the final days. By 8th of February, I had a version which let you play through the screens. Enemies were yet to come, as were things like scoring, jumps, etc., etc. But at the time it seemed like a significant step. I could see my game coming along, and about this stage I really decided that I was going to 'go for it'. I started spending long hours (4-5 a day) programming. I gave myself till the end of the month to get something done. About this time, Eckhard was pointing out the timing problems - which remained until very very late in the development process. I definitely appreciated the assistance, but figured fixing timing at this stage was a waste of time because things would probably (and did, several times) significantly change. One change was the kernel. Initially, I recall, I had something like 4 kernels in there... all doing similar, but not the same, things. They were all rather massive, and I started to run seriously out of ROM space. So, over a few days I generalised the functionality of the kernels and managed to come up with a single kernel which draws the target area, the playfield area, and the sliding cube coming on to the screen. It's quite a neat working kernel... looks quite simple, but it is doing a lot. I spent a lot of time (and heartache) trying to get it working. I was absolutely delighted when I finally managed to get it all going... this was a major achievement of the whole project - for, compressing the multiple kernels into a single one meant that I 'd saved many hundreds of much-needed ROM bytes. I started to think about scoring, and dug up the 6-digit score routine from the list archives. As my original had large digits, I wanted to do the same thing - so it was a simple matter (and fun) to develop a double-height 6-digit variant. I don't think that had been done before, so I posted it to the list. About this time, Thomas became prominent with his wonderful optimisation suggestions (and I gave in to illegal opcodes - much as I'd earlier disliked them, they gave wonderful functionality). I've always been most impressed with Thomas's code/suggestions... The scoring routine is a good example of being in a rut. I spent considerable time writing a pretty-neato binary-to-decimal conversion routine - because I figured I'd need a fast one to do it in the avaialble time. It was pointed out to me that I'd not need that if I used BCD (something I'd completely forgotten about) - and so, the neato routine was promptly junked. A shame, as I liked it :) But, BCD was clearly the way to go. We spent some time playing around with colour-shading the digits, but you will note that this is not present in the final version (removed to save ROM space). Nobody but nobody mentioned that this was missing (something I use to judge if features are important or not).... if somebody notices it and mentions it, then its probably something worth reconsidering. An example of the above is the scores when you eat fruits. Several times these were installed and then removed. Nearly every time, somebody commented that they liked them, or missed them. They were major space-wasters for me, but clearly a wanted addition to the game - and the final version does retain the scores (even though they're costly). On about the 11th, I was working on sprite positioning and ran into the weirdo method that the 2600 uses for positioning sprites horizontally. Basically, a divide by 15 was required. I asked for a quick version, but no response came (I was working quickly anyway)... so I sat down and analysed the difference between divide-by-16 and divide-by-15. I came up with a ... ahem.... stunninlgy beautiful routine, which performed admirably. Proudly, I posted it to the list, only to find that I'd reinvented the wheel :))) somebody had done essentially the same thing before me (in fact, the code was strikingly similar). This was a moment of relevation for me... at this time I realised that many many hundreds of programmers had spent years on this machine - and just about anything you could think of had already been done by somebody else - and better! So, I'm constantly impressed when we see new tricks show up on the list. Of course, we have the benefit of a huge knowledge base, and great tools.... On the 12th, I started numbering versions. I was in serious-mode. My version of the 16th was just about the first version where I started wasting time actually playing the thing. There wasn't much gameplay, but I've always found it kind of fun just sliding pattern after pattern into place. I was pretty happy with things at this stage. This was about the time that the versions of Crazy Valet were posted. I kind of went through a little slump.... it didn't feel like I was doing anything worthwhile... I didn't seriously consider dropping it, though I did feel that what I was doing wasn't up to scratch. I recall being determined to finish... that's probably one of the main factors I kept going. Looking back on it, I'm not sure why I felt this way... but this is a post-mortem, and I was just so impressed with the other guys' efforts... it hardly seemed worthwhile going on. On the 18th, I was complaining about lack of space. I had about 400 bytes, with no creatures or AI installed :) I changed to the new sprite-display system that Thomas had suggested.... and gained myself heaps of ROM (mixed with other changes/optimisations). Even though you think you have a lot of space, you don't. Just a few lines of code chews up ROM . In hindsight, I'd recommend saving 500 bytes JUST for the finishing touches that everyone requests. Clearly, I was deluding myself thinking that I'd be able to pack it all in and only tweak a few things here and there to finish it off. However, deluded, I carried on ;) I added colour to the player on the 19th, and was very dubious that I would be able to get a SINGLE opponent into the game (!). things were obviously extremely tight once again. This constant see-saw/fight between features, progress, and available space is something that clearly sticks in my mind. I am still amazed how I managed to find space (with help, of course!). I added fruit sometime around this point. For the longest time, you couldn't do anything... it just sat there, sliding up and down. The original game introduced creatures by having them slide up out of cubes. I implemented this on the 2600 version, too... and a lot of hard work THAT was! Basically I had to introduce ten zero-bytes at the beginning of every frame... and adjusted the sprite pointer up/down so that the creature appeared to slide in/out of cubes. It worked, but it was very expensive. I spent quite some time worrying about how to solve this. Clearly, I couldn't afford the ROM space (10 extra bytes/frame). Equally clearly, the creatures couldn't just pop on and off (well, maybe clearly in hindsight). For a while, I let the creatures do just that - and, though there were no complaints - it just seemed 'odd' to me. Then I thought of eggs... and tried that... and it worked nicely (even added some gameplay element - jump on the egg before it hatches)... so I'm very happy with how that turned out. Just 4 frames of egg animation... and I drop all the sliding up/down code and data. Good thing, too. Manuel kept badgering me to let him eat the fruit. And, for me, this was a turning point in the coding. Pretty much up until now, I'd been concentrating on systems. I'm a systems guy - I like designing systems and architecture... I'm good at it. What I am *not* good at is finishing things, and hacky-type coding. By that, I mean code suited for a single-purpose. I love general-purpose code which doesn't have any little fiddly bits for specific circumstances. So, I'd been concentrating on the sytems and now it all worked. But now, I was at the crossroads. If I was going to make the fruit edible, it really meant that I was going to start tackling gameplay and creatures. I kind of dreaded this - this is the stage I always get to where I spend ages procrastinating, optimising and improving generality... when I really need to start making the game... the game. So, Manuel's request came at the right time. I figured I'd start with the fruit. This meant collision detection, and getting creatures to react to things. I've done this sort of thing many times before, of course, so it was pretty straightforward. I opted for a simple state-machine (which is an excellent way to do this sort of thing). Each creature has a table of pointers to routines. If a creature can react to a message, it has an entry in the table for that message. That way, you don't know anything about a creature, you just send it a message and let IT worry about what to do about it. OK, so I got the fruit working, collisions... and then the weapon, and started to concentrate on the gameplay. I had been thinking about what to do for creatures, of course, for quite a while. I'd planned to have one creature opponent, and an invisible opponent which did nasty things. The first nasty thing I came up with was to shift cubes randomly. I posted a version which did this - moved the cubes - and it worked OK, but feeback was rather ambivalent. I wasn't happy with it, anyway, and soon opted to have an actual creature doing the shifting. One thing about the Atari 800 version was that I had two creatures on the screen at the same time (enemies). I thought this would be a major problem on the 2600 version (in the end, it wasn't). But I was trying to figure out how to make things more difficult - and one creature seemed a major limitation. It was a limitation I couldn't get around, though, so it wasn't much point worrying too much about it. The game would have to survive with one creature (that is, visible sprite). But, as I optimised, and added more frames and AI, and optimised... I found that I had room for 2, even 3 creatures (and later, even 4...5)... I had to find things for them to do. So, I settled on one creature which shifts cubes away from their correct place (the Octopus), one which shifts them towards their correct place (the Rabbit), and one which is an assassin (the fireball). Why these shapes? Well, they looked OK, basically. It was exceptionally difficult for me to do reasonable graphics, as I was just doing character-bit editing in a text editor - no graphics tools. One feature that I implemented early on was colour-multiplexing of sprites. You will have noticed that the fruit, for example, is 3-colours (red, green, yellow) and they flicker (like crazy, on an emulator). I toyed briefly with monochrome sprites - but, IMHO, they looked crap. I traded flicker for colours. I'm quite happy with the results, and I'm not sure if it has been used elsewhere. I got some nice comments from people about it. It was very tricky, though, designing sprites which multiplexed nicely (and, to tell the truth, I have *still* not seen it on a real TV). I released alpha #1 on 27/2. This is basically a version which has all the features (is essentially complete), but which needs extensive testing/revision/fixing. An alpha is a demonstrable game, which can be played. I hope my alpha meets that criteria... I haven't gone back and checked it :)) I got quite a lot of feedback on the alpha... all of it was much appreciated. Throughout the process, i have tried to listen to and respond to feedback/requests. I hope I've succeeded in that respect. Many of the suggestions that I've taken up have significantly improved the game - right up to the last version! So, thanks once again for all those who complained ;) OK, here we are into march. I'm at the end of the time I allocated myself for completion... but obviously I'm pretty close. An alpha is a long way away from completion, but it was really an unannounced, self-imposed deadline. Basically, if I have a time to work towards, I can judge my progress... if I just did things when I felt like it... it would never happen. Now I've released an alpha, things are starting to move. I'm getting interest in cartridges, people are starting to enjoy playing, and I'm getting more and more feedback. Good! I'm not sure when, exactly, but in the newsgroups one of the organisers of the PhillyClassic convention posted a short note about the convention. I figured that this would be great - to release a cartridge at the show - and so, wrote to them and asked what they thought of the idea. They were pretty keen on the idea, too, and so I now had a target date (April 20th) by which I'd not only need to have finished, but by which date cartridges would need to have been made AND delivered. But, the timing was good. Finally, I'd have done something from start-to-finish. It was my plan to do the whole shebang (disassemble cartridges, desolder, burn ROMs, solder, swear, throw away and start again). I soon realised that this was impractical, and decided that I'd get the carts made externally. Randy of Hozer offered a pretty-good price for the finished thing, AND he was going to the show... so I went with him. Chris also has boards available, and I'm still leaving the option open to use his boards for the later private release. So, I've got release organised... and I'm in early beta testing.... and disaster strikes!! Chris, I think it was, pointed out that the game worked OK up until about screen 4, and then started flickering like crazy. It was a black few days for me, actually. I found out that I was simply using too much time to do things. And I really really needed to do those things. For a while I thought I'd have to cut back to just 3 cubes (ridiculous!) or ... well, I was in limbo. I tried playing with my code, but didn't really see much hope. The code was heavily optimised (for speed) but it was still too long... I wrote to the list with my options. I wasn't terribly happy, really. I guess I thought I'd fix it somehow... but the fight against the available space vs. the functionality I needed... was a tough one. Forgot to mention that I'd spent some time working on a nifty title screen. I'm sure many of you will remember that. It was the wonder of the modern age ;) I fought long and hard to get back the memory to allow the playfield title to be installed, and finally managed to fit it in. And then, Chris's problem struck. I blame you for this Chris, I really do!! Whenever I think of the pain and difficulty caused by the flickering of >4 cubes...I think of "Chris's problem". ;) At this point I was so short of space that a byte here and there were major miracles. And I found that the only solution to the flickering problem was to de-optimise some code (split it into several subsections and execute the subsections at different times). I figured about ... I'm not sure... about 50 bytes, something like that. Clearly, I wasn't going to find that space in the already heavily optimised code. So, the title screen got junked. It's still there (in the code)... just disabled. I have visions of one day restoring it. But in reality, losing it was a GREAT thing... it allowed me to add extra animations to the player, and gave me space for the tweaks, polish, and optimisations that I really wouldn't have been otherwise able to afford. Sure, it would be a bit more 'professional' looking with the tile... but it plays a LOT better without it. Well, it took a great suggestion from Manuel (not one of my options posted to the list) to resolve the flickering problem. I split the culprit routine into two and executed the second part in the vertical blank, and the first part in the overscan. It's all to do with available time. I still found that I was using too much time (specifically in the vertical blank), but I managed to multiplex the routine usage in time (one, one frame, another, another frame, etc)... and that finally solved the over-usage of time. That was the last really thorny issue I had. Over the last day, I've just finished installing a few suggestions (RESET, SELECT). These probably came a bit late in the day - I should probably have thought this bit out a bit more thoroughly. It seemed to me that it was OK to require the player to turn the machine off/on to restart.... but that's what a reset button is. Anyway, after a very grumpy and frustrating night... I got the ahem... frigging code... to work... and I've just posted my final version. Yes, I know... maybe not final. But... closer than anything that's come before. The one failing of the game is the lack of decent sound. The two reasons for this are that I am obviously not the right person to do sound (I don't hear so well, and I know nothing about sound/music), and I would obviously have to trade off some other feature to allow sound support. The game works OK with the minmal sound there is... but it is something I am still a bit uncomfortable about. Still, that's really the only missing thing that I regret. Everything else looks pretty good to me, and I'm quite happy with the results. Personally, I'm a wreck. Burnt out, not sleeping well... and most definitely not relaxed. In other words, a typical games programmer at the end of a project. So, there you go Ruffin... that's your post-mortem. I hope it doesn't sound too self-centered. Cheers A -- _ _ _| _ _ _| _ * _ _ , (_|| )(_|( (/_\/\/ (_|(_|\/(_(/_ ,~' L_|\ ,-' \ see my Museum of Soviet Calculators at ( \ http://www.taswegian.com/MOSCOW/soviet.html \ __ / L,~' "\__/ @--> v - Archives (includes files) at http://www.biglist.com/lists/stella/archives/ Unsub & more at http://www.biglist.com/lists/stella/
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [stella] parallel efforts / Inv, Thomas Jentzsch | Thread | Re: [stella] Qb: Post-Mortem, Chris Wilkson |
RE: [stella] parallel efforts / Inv, Brian Prescott | Date | Re: [stella] Gunfight 2600: Little , Glenn Saunders |
Month |