Since I try to do video games for a living, it might seem very odd for me to go home and then do the same thing again. I call it recreational programming and in all honesty it's a little bit whacked. I'm not alone in this though, I know a lot of people do the same thing, or similarly taking their day job home and doing it as a hobby. Either we're really lucky or just retarded. Any given day I'm in the balance which. Anyhow, this article starts at a lunch with a friend where we start reminiscing about old games and what we played back in the day before monster processors and even consoles more powerful than the NES 8-bit system. Several games came up but one stuck in the conversation and kind of expanded. The game was Chopper Duel, for the old DOS computers. The game is not that old, but the idea came up to do a revamped version of the game, in full 3D and with destructible environment. Well, suffice to say I didn't make that game.
The power of caffeine
I did get very excited about programming some however and after the lunch I got my laptop and went to Starbucks for a cup of coffee and some programming. After about two hours I had an initial version of the game up and running. In about 300 lines of code I had a chopper flying on the screen with some semblance of a city. 300 lines of very straightforward, blunt C++. The bad part about this was that I had no source control so I made very small changes all the time and the code had become a little messy. It did the job, but I had side effects all over the place. So I decided to go home, get the laptop hooked up to a regular Internet connection and commit the whole thing to a source control repository. In the process I tried to clean the whole thing up a little. Bam. Suddenly my one file program had exploded into about 7 files, some classes and a whole lot of compiler settings. The program didn't do anything different in the end result, but the code was a whole lot easier to read now without all the globals, partitioned code modules that had clear responsibilities etc. The code wasn't really that good yet, but I felt the cleanup was necessary for the next step, adding features. There were several things that I wanted to add, among them destruction of the houses, multiplayer and proper collisions. For all that you need to keep the whole program in your head, but it becomes really hard for me when the code looks like crap.
The merits of cleaning up
The whole problem is that up until a point you can cope with bad code. Some people are really good at this, I am not. There is a really good point to it as well, if you think there will never come to the point where you actually go beyond the limit of how much context you can load into you brain about the code and you will still be effective in making changes (or there will be no changes, yeah right) then writing messy straightforward code that just does the job is not that bad. It does the job. You don't have to look it again. Move one to the next problem. In reality the only thing that works on are one off perl-scripts and leaf functions. What's a leaf function? It's something that is clearly defined through it's inputs and outputs, have no side effects and doesn't call anything else. It's a clearly defined chunk of code and it can be as messy as you would like. Chances are you will get away with this during development (unless there are bugs in there of course). The code works and it's done. Unfortunately this doesn't translate to whole applications that easily. Coding is changing. You add something here and there, realize that it doesn't play nice with the rest of it and then you change something else to cope with it. Constant little changes. Now imagine if you had to add a feature, say fire shots for the chopper game. Changing little things to manipulate global state at 5 or more places doesn't sound like an ideal situation. That's the point where I go if I need to make any change after this one, let's refactor a little bit to clean up the mess. If this is a one off change, then leave a comment in there that if you read it, before making a change, then you need to clean it up before. It's kind of leaving cookie crums and if you find one then you're obliged to clean the whole mess up. And don't close your eyes.
There is a problem with the whole cleaning up though. The code grows. The ratio of useful code that actually does stuff and code that just tries to overcome abstractions and glue code falls significantly. The final prototype was about 1300 lines of code, the initial one was under 300. In all honesty there is not 4 times more functionality increase between the two, which is sad. This said, I'm doubtful if I would have continued on if the original coding style had prevailed, I would probably been too disgusted with the code that next time it had a bug I would have tossed the whole thing :)
The game is simple, you are in control of a attack helicopter and you can fire horizontal shots to hit the other guys as well as the buildings. For some strange reason if you hit the end of the screen you die. Even stranger is the fact that when you die, you get respawned two times and then you die. Without an explosion. You can connect XBOX 360 controllers to you PC and then play with them. If there is one slot open of the maximum four choppers, that slot is controlled by a keyboard.
The game is quite unpolished, the graphics are all very funny bitmaps I made, there is no sound and no effects like particle trails or explosions. All those things could probably have made the game a little better or more fun. There are no menus or any kind of state changes apart for my debug pause (F1).
So what do you use for getting up and running quickly? The libraries I prefer to use the most for prototyping are
- SDL Low level C library that handles cross platform window management, input and 2d graphics.
- OpenGL It's just so simple to draw triangles. A couple of minutes. Yay!
- Xinput Connect to the xbox controller with two function calls!
With these libraries you can get up and running pretty quickly and they are fairly low level so that you have total control of the application. Why not use GLUT? I don't really like to give away control of the main loop to a library. SDL lets me keep control and then ask the library what happens.
The little game just rekindled my passion for writing games, usually I just write low level libraries and rewrite slow parts of games. This was an adventure in instant gratification. Oh, I'd like for the buildings to break when I shoot at them. Hm. Bam. 10 minutes later the buildings are breaking. It doesn't get much better than that. Now I'm going to retire this little project and think about how I might do this in a 3D environment with just programmer art...
If you want to run the game yourself, you can download it here. You will need a fairly recent DirectX installation (for XInput.dll) and possibly an Xbox controller if you want to play multiplayer.