Jump to content

Gauntlet by Donald R. Lebeau 1984


Recommended Posts

Hi everybody! I figured I'd start by posting my interview with ABBUC magazine. It will be published in German and I'm supposed to get an English translation. This is the unedited interview and it'll be interesting to see what parts make it into the final article.


Some good questions here. Not used to talking about myself because I lead a pretty boring life. :)


----------------------------- Cut Here -------------------->8



> Nowadays it's hard to find programmers of the eighties. We've found you, the author of the game Gauntletak. Could you explain your game in a few words?


It's a 2D shooter where you control a spaceship that can fire in eight directions and accelerate in any direction. You face a number of enemy ship types and each one is different. They are smart, use different tactics, and even know how to team up against you. The terrain is completely destructable and changes during the course of the battle. Your goal is to fight through 50 screens of defenders and kill the final boss at the end.


At a time when most other games had your enemies marching in a line across the screen, this was a pretty innovative approach. The enemies don't follow any set patterns. They react to everything that you do and each encounter is unique.


> Was it your first game you created? What are the names of other games/programmes you have written?


Gauntlet was the first and only game I published. I had two more under development at the time I released Gauntlet, but since Gauntlet didn't sell well, I went on to other things. One game was a First Person speeder bike chase game from Start Wars and the other was kind of like what Worms turned out to be.


I did a lot of cross-platform translations at that time and wrote "How to Program in BASIC" for the Atari, PC, and Commodore 64. After that I got into the commercial market and developed a lot of embedded software. I worked on controllers for six different laser printers and a typesetter, did the weather map distribution service that all the TV weather stations used to use, and a bunch of other stuff.


The best, and most useful machine I designed was BorderGuard - a device that identifies fake passports. It is currently used in 11 countries including Hungary, Canada, Germany, Austraila, and the US. We caught over 30 terrorists with it during the initail trials. It even appeared in the movie "The Terminal". Heck, my machines are more famous than me. :)


As far as gaming goes, the only other thing that I published was a huge strategy guide called "The Grenadier's Bible" for the Laser Squad Nemesis under my player name Crank. It's almost a hunderd pages long. LSN is the best game I've ever played and at the time I was the top Marine player. I haven't played in four years but people still talk about how scary I was. :) I'd love to get back into it, but I just don't have the time. But I still pop in there from time to time to discuss tactics.


I currently play DDO, Tabula Rasa, BF2, and COD4 online and a number of RPG games on my laptop tat I play when I travel.



> What was your inspiration to write such type of game?


I typed in a Lunar Lander program in BASIC from Antic magazine. After getting it working, I statred playing around with it to see what else I could make it do. I changed it so that you could take off again and land on another pad, and then I added a second lander so that two people could play together. A soon as I got the two landers on the screenI wanted to make them shoot at each other, but I had pushed the limits of the BASIC language. So I rewrote the lander program in assembly language and started adding features until I had something that looked like it could be fun. At that point I realized that it was possible to write a real game on the Atari and the APX would let you publish it, so I go serious into turning into a game that I would like to play. I've always like games where you had to fight smart enemies and think on yor feet, and that was the major focus. It took over two years to get the game to play the way I wanted it to.



> Did you use some special programming techniques and tricks?


Yes, there were a few things. This might get technical:


The first was throw to out all the Atari graphics and sound routines and write my own. The Atari graphics routines are unbelievably slow because they recalculate the screen resolution EVERY time that they draw a dot. I could draw 100 dots on the screen in the same time it took the Atari routines to draw one. I also read the keyboard and joystick dirretly. When the game is running, there's no "Atari" software running at all, my program is driving all the hardware directly.


The game uses a queue system to manage everything and a task controller to process the queues. There are five queues: Drawing, Movement, Font Cycling, Thinking, and Firing (New object creation). Each queue is processed 30 times a second, and they are processed in order. Processing stops when time runs out for that time slot. This makes the whole game self-throttling because if there are too many objects on the screen there won't be time left to Fire and create more objects until there were less objects are on the screen.


The player ship is always the highest priority and was handled seperately so that it is always responsive to the user and never appears to lag.


I used a special graphics mode with "flat" dots that gave the game a unique look.


Since I didn't use any of the Atari software, I grabbed all the RAM space that the Atari software needed and used it for my own program. Gauntlet uses all the available space and I got to the point where I couldn't add anything without ripping something else out to make room. I wrote a lot of data compaction routines to fit everything in. You know all the text at the start of the shareware version? That even gets overwritten and used as running memory as soon as the game starts. Space is that tight.


I made my own sound driver with eight sound channels that prioritized sounds by "importance" and then sent them along to the Atari four channel sound chip. That makes the player always has the critical audio feedback that he needs even when there's a lot happening on the screen. It's one of those features that nobody really notices but it makes a big difference in the gameplay.


Every time an object "moves" on the screen, it has to do a number of things. First you erase the old position. While you're doing that, you check all the dots to see if any of them are missing (indicating a hit). Now you draw the object in the new position, and while you doing that you have to check if any of the dots at the new position are filled in (indicating a collision). For the commercial version, I managed to rewrite all that logic without using any branch statements, just ANDs, ORs, XOR,s etc. The resulting code was more compact and almost 5 times faster, which allowed me to put a lot more and a lot bigger objects on the screen. The shareware version had problems with slowdown but this eliminated them.


My development system had four disk drives and 128K of RAM (through a custom memory board) to compile the source code. I had a second Atari 800 as a test machine so that I could test the game on one computer while I was compiling the latest changes on the other. The game took an hour to compile from scratch, but I broke it up into smaller modules that would compile in about 20 minutes each.


I was a member of a local Atari Users group and each week I would bring my latest build to the meeting for everyone to try. They were a great group of people and *very* hard on the game. Their enthusiasum was also great and they helped keep me motivated. They are probably the biggest reason that Gauntlet turned out as well as it did.



> Do you have some hints to get higher scores?


The biggest thing is to learn how to lead enemy homing missles into the ground so that you don't have to shoot them out of the air. That allows you to shoot at the launching ship instead of wasting time on it's missiles.


There's a LOT more hints in the back of the games manual that I wrote back when I really knew how to play. :)



> Look at your product from today. Are you still proud of it? What do you like on your game most? What don't you like?


Yes, I am. Mostly I'm proud that I was actually able to finish it and that people seem to like it even after all this time.


The things I like most are the large variety of "smart" enemies that use different tactics to fight you. Each one fights differently and it keeps the game interesting. My goal was to cause you to think on you feet and I think the game accomplishes that.


I absolutely HATE the way the terrain looks! It was the best I could do at the time because of the Atari 800 limitations, but I never liked the looks of it. I also wanted the game to have a smooth scrolling screen, but it was impossible to do that.


The graphics in general always disappointed me because I was limited to the Atari display modes and I couldn't get more than four colors on the screen at once. The game could easily drive higher resolution graphics, but the Atari couldn't support them.


> How did you sell your product? Did you have some professional publisher or other professional help?


Originally the game was targeted for the Atari Program Exchange (APX), but the APX closed down a month before Gauntlet was ready. I submitted the game to a number of publishers, but at the time Atari was in financial trouble and nobody wanted to market an Atari-only game. So I distributed it as shareware with the option of buying a registered version and uploaded to a number of BBS's.


> Could you tell us the main differences between your shareware version (Gauntlet) and your commercial version (Gauntletak)?


The shareware version has one difficulty setting and every screen has the same enemies on it.


The commercial version has six difficulty settings and the enemies are randomly generated. There are a number of new ammo types and enemy ships. The enemies are smarter and different types of enemiy ships work together. The graphics are also faster and there can be twice as many objects on the screen at once.


> How many copies were sold of your game?


I sold about 50 of the registered version and an unknown number later on when a publisher of old 8-bit games picked it up.


> How could we, abbuc members, enjoy your program? Is it still available?


I thought the game was lost forever because all my master disks were destroyed when I stored them in an attic about ten years ago. Two months ago, my daughter found out that people were discussing the game on the Atariage forums and were looking for the commercial version. My daughter was born the year the game was made, so this was pretty strange.


The discussion was three years old, but I responded and gave them some information on how to identify the commercial version. Amazingly, someone from the forum had one of the original 50 registered disks and he made it available again. Thanks to him, everyone can now play the commercial version. I'm happy to say that the game is included on the magazine disk so that abbuc readers can enjoy it.


> Could I asked some personal Atari related things?




> Was the Atari your first computer? When did you buy it and why?



I was my first "home computer". I used to build single board computers as a hobby. I was a hardware engineer a the time and had just gotten a Sim-One single board computer. I wanted to buy a terminal for it, but I found out the the Atari 800 was actually cheaper than a terminal and it was a full computer with color graphics and everything. I bought one and decided to learn programming on it. Since I loved games, I decided that would be a good project to learn on. I've been writing software ever since.


> How old were you at this time?



24 years old. I was married with one kid.


> How have you learned to write programs and what languages did you prefer on the Atari?


I had written some assembly language programs at work and also wrote some test programs in BASIC. I was mostly self-taught after college and learned most of my programming and hardware design by doing small projects at home.


For the Atari, I used BASIC for a lot a small wargamming aids like dice rollers and stuff and I used assembly language for Gauntlet.



> Did you play on the Atari? What were your favourites?



I played almost everything on the Atari, but my particular favorites were:


Star Raiders


Computer Ambush,

Ali Baba and the Forty Thieves

Missile Command (I actually beat it!)

Asteroids (4 player co-op)


> Do you still use your Atari today?


No. About ten years ago I lent my development machine to someone who wanted to learn programming. It didn't run because one of the expanded memory switches was in the wrong position, so instead of asking me for help, the idiot took the whole thing apart and ripped out all the "unnecessary" wires. I was furious. The machine was totally customized and I didn't have any of the old wiring diagrams. He also managed to crack the motherboard trying to pry it out, so the machine was unrepairable. This happened just after I discovered that all my source code disks were unreadable, so I just got rid of everything. Oh well.


> Why not? Never thought of buying one for a few bucks on ebay and relive old emotions/feelings?


I got into PC gaming and never really looked back. I played with one of the emulators a few years ago and that brought back memories. Some of those old games are very unique and have great play value.


Now that Gauntletak is available, I'm currently setting up the emulator again on my PC. I already ordered one of the old joysticks. It's exciting because half of my kids didn't know I wrote a videogame and now they want to see it. They think I'm some kind of hero now. :)


I actually can't wait to play it again!

Link to comment
Share on other sites

Hi everybody! I figured I'd start by posting my interview with ABBUC magazine. It will be published in German and I'm supposed to get an English translation. This is the unedited interview and it'll be interesting to see what parts make it into the final article.


Some good questions here. Not used to talking about myself because I lead a pretty boring life. :)


Be that as it may seem (to you), the article was a lot of fun to read, and makes me want to go home and try the full version. :) I've been playing more and more of my Atari 5200/8-bit Atari stuff on the Dreamcast for some reason, so I need to add this game to my Dreamcast:Atari800 emu CD. :) That could be fun.


I noticed that you like Ali Baba and the 40 thieves, which was the flip side game to Return of Heracles. Did you get the version of that which was only Ali Baba, or if not, why did you like Ali Baba more than Return of Herc? (I always thought Return of Herc was the better game) ;)

Edited by doctorclu
Link to comment
Share on other sites

Yes, nice article! One thing I found interesting:

I used a special graphics mode with "flat" dots that gave the game a unique look.

What is this? ;)


I suppose if I was doing Gauntlet now for the Atari I would look at a tiled texture for the landscape, perhaps with dithering to make it look like more than 4 colours. Proper 3D looking terrain would probably need to be pre-drawn in a renderer and that's beyond the scope of the machine.

Link to comment
Share on other sites

That's what I thought, but why was that special? Or was that because it wasn't used till a few years later for most games?


Yeah it was the 7.5 graphics mode. At the time is was one of the "undocumented" modes that you only found out about by pouring through the Atari technical manuals. There weren't any games using it. Used to get a lot of comments about how different it looked.


I picked it because it was the highest resolution that gave me at least four colors and the objects looked less blocky. If I remember correctly, it was the highest color resolution.


The screen is actually running two graphics modes, the lower part where the scores are located is in one of the text modes. I made a custom raster list to make that work. You could have a different graphics mode on each scan line and pull the data from anywhere you wanted to. It was a pretty advanced chip for it's time.




I didn't know there was another game like Ali Baba. I played it with a friend for an entire weekend while our wives were away. Each of us took turns "driving" and "backseat driving". Maybe it was the company or the lack of sleep, but I still remember it as being one of the most fun RPGs I've ever played.


I'll have to check it out. Thanks!

Link to comment
Share on other sites

Don, in Gauntlet why do the players shots not all move at once, but seem to move on different frames?


Each object is independent and only moves when it's X and Y ring guages tell it to. Since they were fired at different times, very few of them are in sync with each other. The player ship's shots only move in eight directions and at a constant speed, so the only real difference is the spawn time.


For every other type of shell, their direction vector is usually different since they are (usually) fired directly at the player ship. Because of the way the ring guages work, these will all be moving at different times.


Is this to spread out the CPU load a bit?


Actually, this is one time when it isn't. It's a byproduct of the algorithm I used to move the objects. But it's a very fortunate byproduct. :) I can't hold off moving stuff on the screen because people immediately notice it. It's amazing what your eye can pick up! The slightest jitter or stutter and the whole game just looks like junk. So everything in the system was a slave to ensuring that I made my video updates on time.


However I did take advantage of this effect by how I handle my firing queue. When a ship wants to fire, it puts a request in a queue. I don't process all the fire requests at once, but I spread them out over several video interrupts. That way the start times for the movement, font rotation, and think modules are staggered. I try my best to keep an even workload across the interrupts instead of having to process stuff in clumps.

Edited by donlebeau
Link to comment
Share on other sites

For Storm I didn't have quite the same technical limitations, but I still tried to make the game play well on slower PC's. I think the drawing takes up the majority of the time, with much more time available for the logic than on the Atari. To speed things up further, all the collision detection is done with bitmasks in Storm. The levels are constructed from 'bitblocks' which are 32 x 32 sized masks (32 longs) which are used for the terrain. By using this system instead of a big bitmap or big bitmask we save memory and time, because we don't need to store all the empty spaces in the mask, letting us have bigger levels. Additionally the bitmask number is stored as 0 (empty), 1 (solid) or >1 for the individual bitblock. This lets us vastly speed up collision detection as most of the time the check will result in 0 saving us 32 long int checks foe each block.


These bitblock codes are also used for the rough LOS which saves us having to do many individual pixel (or bitmask) checks at the expense of accuracy. The bitblocks are also written to in creating holes in the terrain, and since they are used directly to draw the level, there is no need to update any other gfx for the level. This code required the use of some specialised drawing cases, but works fast enough to allow a 60 fps update on slow PC's.


Hope that snippet proved interesting!

Link to comment
Share on other sites

Has anyone asked how much it costs to get a registered copy of Storm? I know there is no site, not currently for sale, and you are waiting a year to honor the current buyers of the real game, but just to let you know I was neccessaily looking for a freebe. SOME games are worth paying for.


Still kinda wanna pay for Gauntlet. :(


Got an idea (sending PM to Don.)

Link to comment
Share on other sites



I majored in computer design in college and worked first as a hardware and then a software engineer. At the time I wrote Gauntlet, my job was writing time critical controller firmware for single-board controllers in terminals, laser printers, and typesetters. I would design the software and optimize the hardware to get the best performance. On these single board controllers, you wrote *everything* - the multitask system, all the hardware and communication drivers, display handlers, etc. Most of this stuff I learned from books or by a lot of experimentation. One of the reasons that it took me over two years to write Gauntlet was that I kept hitting technical roadblocks that I didn't know how to solve. So I had to dig and ask around and learn ways to get around the limitations. It took over a year and a half before I could have more than ten objects on the screen at once!


Since one of my main reasons for writing Gauntlet was to "learn programming", it was a great experience. It forced me to dig pretty deeply into stuff that you could never learn from books or by a writing couple of small test programs. Even if I didn't make a cent with it, I came out of it with four years of solid realtime embeded programming experience and a knowledge of some very esoteric techniques to handle data blindingly fast. In fact I got my laser printer job because I had Gauntlet on my resume and in discussing it in the interview my boss realized that I knew more about real-time task managers than he did. :) I also landed two consulting jobs that I got because they saw Gauntlet on my resume and brought me in just to explain how I got the Atari to do so much with so little horsepower. They were impressed enough with the architecture that they hired me on the spot.


Some of the "Gauntlet" techniques I'm currently writing up are very generic to high speed data processing applications. In fact, I just convinced my group to use a sliding ring buffer approach for tracking products in a new $250k book binding machine that they're designing. It was much faster and cleaner than any other approach they tried. I didn't bother telling them that it's the same one that I initially designed for Gauntlet. :)


I pretty sure I still have a stack of listings, just haven't had a chance to look for them. I'm currently moving and won't be able to sort through my stuff for a couple of weeks. I might post some screenshos if I find them. Or maybe autograph them and sell them on eBay. :)




Interesting approach. I like how your ships ingore friendly fire. I was playing Storm (great game!) and noticed two things right off:


First, if there was ever a spiritual successor to Gauntlet, this is it!! I immediately had that "Gauntlet feel" that I haven't had for like fifteen years. It's strange - like meeting an old friend in a different body. I started rubberbanding things and doing the other stuff like I used to do. I've got to try it with a gamepad though because the keyboard control, well, just plain sucks. That was the biggest issue I had with trying to rewrite Gauntlet for the PC - nobody ever came out with a simple 8 direction joystick, and any other control scheme just doesn't work with that kind of game.


The second thing that I noticed was that your missiles don't explode when you run them into each other and you ships don't shoot each other to death. I found that out the hard way. :)


Interesting design decision. It does force you to play more aggressively, which is a good thing. Not sure if that was the reason why, but I know that it you allow friendly you have to spend a ton of effort in the AI just to keep your ships from killing each other. Half of the effort that I initially put into the Gauntlet AI was just to keep the ships alive long enough to make them challenging. But once I had done that, I had laid the framework for making them *really* smart and able to react to a lot of changing conditions. Almost like a natural selection process...


The weird thing about the approach that I took for collision detection is that objects knew they hit *something*, they just never knew *what* they hit. So I couldn't do things like ignoring friendly fire. And it created a bunch of self-destructive behavior that I had to account for. For instance, because of the explosion "walk back", if a ship just sat there and started firing it would usually kill itself. So when a ship fires, it checks the range to the player and monitors how far it's shells are traveling. If the player ship is far away and it's shells are exploding too close, it will stop firing and start sidestepping so it doesn't get killed by the "walk back".


I'm going to do a writeup on how the AI works right after I get the current stuff I'm writing posted. You pretty much need to understand the framework that the AI operates in before any of it makes any sense, so I'm laying out the framework first.

Edited by donlebeau
Link to comment
Share on other sites

The objects do have various variables (including who is the owner of the shots), that does help! I can't remember all of the design decisions now as I haven't really looked at the code for about 4 years. I should have put more work into the AI, it's not that good (and certainly less sophisticated than yours). But with scrolling levels and with such a lot of work involved the AI didn't need to be as tightly focussed I think.


Interestingly on a previous PC I used to play Gauntlet under emulation with a microswitched Saitek joypad as the arrow key controls weren't good enough. This was a problem I also experienced when starting Storm, and probably influenced sales dramatically. However, after developing Storm and playing it a lot, I got used to the cursor keys and got really good with them. So it is possible! ;)


I look forward to reading about the AI in more detail! I still don't quite get what ring buffers are though. :)

Edited by happymonster
Link to comment
Share on other sites

Here's how I did the LOS calculation. It's pretty straight forward, but I had to use some tricks to make it fast enough to be usable.


There's four colors on the screen, black is zero. To check LOS, I basically draw a straight line between the sighting ship and the player ship. If I see any non-zero pixels, it's an obstruction and I stop looking any further. The problem is that it's expensive to check every pixel. There are four pixels per byte (arrainged horizontally). Instead of checking each pixel within the byte, I just look at the whole byte. Since the playfield is much wider than it is tall, I save a ton of time doing it this way. The screen is 192 pixels wide, so I can span that by reading about 40 bytes since the ships aren't allowed near the very edges.


The second trick is in the terrain design. When checking LOS, I'm more worried about seeing if there's TERRAIN in the way than just random small flying objects. If I don't ignore the small objects, ships wouldn't fire at you if there were shells in the air between you and them. So I made each terrain feature a minimum of 9 pixels wide and 3 pixels high. (In case it's not obvious, 9 pixels wide ensures that each terrain featue occupies at least three bytes - 4 pixels in the first byte, 4 in the second, and 1 in the third.) Now I can check every 3rd byte and I'll still see any terrain in my way. I also tend to skip over most of the ammo that's flying around. It's now down to about 13 reads to span the screen.


I can save a little more because all ships have a look-ahead scan that they use whenever they move. It looks in the direction they are going to move in and uses the byte reading trick to see if there anything directly ahead and 45 degrees to the left and right of it's movement direction. As a result, ships tend to stay a minimum distance from any terrain. That means that I don't have start checking LOS right near the firing ship, I can start checking further out. I also don't have to check right near the player ship because if he's hiding behind cover shooting through it is actually a good thing. Now I'm down to about 10 reads to span the screen and I tend to ignore the ammo both ships are firing.


In order to test this feature, I made the LOS logic draw the bytes it was scanning and turned off the collision detection in the game. Then the ships would fly all around the screen drawing these little dashed lines between themselves and the player ship. I could see exactly what they were scanning and it made it pretty easy to tune the algorythm.

Link to comment
Share on other sites

Don, nice to read... such work in a little game... ;) i love to read your comments...maybe sometime we really see the source code...


I am personally interested in your ringbuffer que system as right now I am not sure how you determinated how many enemies plus shots you can handle per frame. you mentioned your engine decided how many cpu cycles are available and spend the time wisely on your tasks. so did you meassured how many shots plus enemies you can handle per frame and made penalty decisions on that or is there a better way?

Link to comment
Share on other sites

Don, that's really very clever. :)

I love these kind of optimisations. I forgot to say that in Storm all the objects mark the bit tiles reference map they cover as occupied. This stops ships moving into each other, and shooting through each other to get to the player. Also, the occupied bit tiles are only updated when the enemy will move over a new bit tile (32 x 32) alligned. This means that no checks need to be done to see if the object has collided unless he moves over a new tile boundary, saving some time.


This means that my approach is not as accurate as yours, but probably a bit quicker because less checks are needed per frame.

Link to comment
Share on other sites

Thanks for all the insight into the inner workings of the game Don. Very interesting stuff! I'm with Heaven in that I'd love to see source code. Even some small snippets would be great. Any chance you might break out the cross-assembler and create something new???



Link to comment
Share on other sites

Glad you're finding this stuff interesting. Let me know if I start boring people. :)


As far as source code goes, I'm pretty sure I have a stack of listings packed away somewhere. I currently in the process of moving - shortening my three hour a day commute down to less than an hour. I'm going to msee if I can find the listings and any disks I might have kept after I get settled in.


I wish I had the listings right now. I'm still not too clear on how some of the basic framework worked and I'm trying to be as accurate as possible when I describe stuff.


I'll probably draw an architectual diagram just so everyone can see how the major blocks fit together. Pretty hard to describe it without that.




The player ship's functions are handled during the video sync interrupt. Everything else in the game is handled in the background. During the video interrupt I scan through all my active objects and decrement down all of their countdown timers. They have timers for every major function, font rotation, moving, shooting, thinking, etc. There is also a ring buffer queue for each of these functions and a handler attached to each of them.


Say that an object's think timer gets decremented down to zero during this video interrupt. That means that it's time for that object to run it's think module. This doesn't happen during the interrupt. What happens is that the object's id is stuffed into the think queue.


Except for the player ship, the only thing that the video interrupt routine does is determine when an object needs to do a certain function and then stuffs that object's id into the appropiate queue.


The real work is done in the background, and that's where I can also do load balancing.


Basically I have a work overseer that checks each queue for work. Because I know how many object id's are stuffed into each queue, I know how many objects want to move, fire, think, get cleared, or have their fonts rotated. Say that there's 10 ships that want to move, 6 that want to fire, and 2 that what their fonts rotated. The overseer looks at this workload and compares it to it's priority list (like moving is more important that firing because the user will see slow movement updates but won't notice if an enemy ship fires at him "late".)


So in the above example the overseer will divide the work down and will probably call the move handler 5 times, the fire handler 3 times, and the font manager once. Each handler will take one object id out of it's queue and process it.


Now there will be 5 objects left in the move queue, 3 in the fire queue, and 1 in the font rotation queue.


Now the overseer will look at it's workload again and re-evaluate it. This is because while it was calling the work handlers another video interrupt may have happened and stuffed more work into the request queues. Suppose for instance that an interrupt occured and it stuffed 10 requests into the font rotation queue. My queues now look like:


Move: 5 Fire: 3 Font Rotation: 11


The overseer now sees that there's a LOT of work that's time critical - anything related to the video is top priority. So based on the rules it was given, it will call the font handler 11 times and the move handler 5 times to catch up. Then it will re-evaluate the workload. If no other requests were put in the queues, it will finish off the 3 fire requests and then wait for more work.


During the video interrupt I keep a running total of how many objects are on the screen. I use that to ensure that there's not too many for the engine to handle. There's a "high water mark" and if that number of objects get put on the screen I set a TooManyObjects flag. The think modules check this TooManyObjects when determining if they should fire. If it's set, they won't fire but will manuver instead. They will not fire again until the TooManyObjects flag is cleared when the number of objects falls below a "low water mark".


The second way that I control the max number of objects is when I initially populate the screen. Each ship holds a maximum number of ammo that it can have out on the screen at once. For instance, the Torpship holds two homing missiles, so I know that when I put one on the screen, it can have a maximum of three objects in play. The routine that randomly populates the screen knows how many objects each ship will control, so it will populate the screen up to a set limit. That's a pre-emptive way to avoid workload problems. The rest of the load balancing code (like what I described above) is just focused on shifting the workload around in time so that there's no visible slowdown.


The focus is always on VISIBLE slowdown. Sometimes things will bog down, but it's handled in such a way that the user shouldn't ever see it.




Sorry, but there's probably not a lot of a chance that I'll be writing any new game stuff. Based on the record-breaking sales of Gauntlet and Storm, it's just not something that I can justify.


(TMI Alert!)


I just went through an eight year high-stress live-at-work situation and am basically going to focus on my family for the next few years. I've got six kids and four grandkids and my younger kids really never had the same family life as my older ones did. When my older ones were young, I was home a lot and we did a lot of normal family activities. My younger kids see the videos of everyone playing in the yard, going on hikes and cookouts, and they realize that they've never done any of that stuff with the family. Ever since they've been around, we've been moving (6 times!) and fixing up old houses. We've just never had a real family with them and they've suffered for it. So we're just focusing on that until they're out of the house.

Edited by donlebeau
Link to comment
Share on other sites

Object data:


This discussion pretty much lays the foundation for how I handled each of my objects and sets the stage for understanding the ring buffers. I took advantage of a feature of the 6502 instruction set and used it to optimize all of my data handling. (Sorry if this is pretty basic for you 6502 programmers, but it lays the foundation for some of the exploits that I used later on.)


The 6502 has index registers (X and Y) and can address memory locations using a base address and adding the offset in one of the index registers. For example, then instruction sequence:


LDX AnIndex

LDA MemoyLoc,X


Will first load the X index register with the byte value stored in AnIndex. Since this is a byte value, the index value

can be from 0 to 255. Then it will load the A register with the value stored in the 16 bit address MemoryLoc plus the offset. So if MemoryLoc equals 2000 and AnIndex equals 7, the A register will be loaded with the value stored in memory location 2007.


What this effectively does is allow to set up memory as arrays of bytes. For instance, the same functionality could be

written in the C language as:


i = AnIndex

a = MemoryLoc


(Even though Gauntlet was written entirely in 6502 assembly language, I'm going to describe a lot of the constructs in C. One of the reasons is that when I get to the ring buffer descriptions, the C code makes what is happening clearer and you can actually use the code snippets in today's programs.)


In Gauntlet, I had to keep track of the data for up to 100 objects at a time. The 6502 was not suited for normal approaches like having an array of 100 structures (or the modern equivalent of having an array of 100 objects). Instead I had to take advantage of the 6502's indexing features.


The best way to handle data for 100 objects is to create an array for each separate byte of data and then access them

using a common index. In Gauntlet this index is refered to as the ObjectID. The object's data is layed out like this in C notation:


#define MAXSHIPS 100


byte XLocation[MAXSHIPS]

byte YSpeed[MAXSHIPS]

byte YLocation[MAXSHIPS]

byte YSpeed[MAXSHIPS]

byte Damage[MAXSHIPS]



In all I had something like 40 variables for each object, organized as 40 arrays of bytes. When I wanted to access an

individual object, I just needed teh ObjectID. For instance, the ObjectID of 3 would get me all the data associated with

object number 3. So if I wanted to find the damage for object 3, in 6502 I would use the code:



LDA Damage,X


Which is the equivalent in C of:


a = Damage[3]


Every routine in Gauntlet that assesses any object data takes an object index ID as a parameter. The Player Ship is

always object index 0, so it's data occupies the first byte of every one of these arrays in memory. A byproduct of the

Player Ship occupying the first byte of all these arrays is that I have two ways to address it's data, the normal





LDA Damage,X


and also:


LDA Damage


...which is addressed directly and doesn't need an index. This method of addressing is twice as fast as the indexed

method, so I was able to optimize a lot of routines that addressed the Player Ship by making copies of the general purpose routines and rewriting them to address the Player Ship directly. Since the Player Ship moves and fires in interrupt space, having seperate routines made it so that the general move and fire routines didn't have to be re-enterant. The Player Ship versions ran in interrupt space and the general version ran in the background.


The important things to get out of this description are:


1. Data is stored in memory as byte arrays.

2. It is accessed using an index which is a byte value.

3. All data at the same index is related to the same object. That index is the object's ID number.


In Gauntlet, it's important to understand that every object is identified by an ID number, and that that ID number is an index into all these object data arrays.


Hopefully this is pretty clear. If not, let me know. If you don't understand this part, you won't understand the ring buffer discussion because it builds on this framework.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...