What Went Right
1.Realistic Goals. At the start of many game development projects, it's easy for designers to become overzealous when setting their goals for the game. As five graduate students working on our first independent game, we initially had grand ideas of creating an incredible game full of state-of-the-art graphics algorithms and rendering techniques. When we finished laughing, we scaled back our goals for BHX and came up with a realistic plan that could be accomplished in a few short months of work.
To determine what features BHX needed, we put together a list of key components for an action game. We considered the following high-level features necessary for BHX:
As soon as we had these main categories, we began to fill in details and divide up the work. Our initial goal was to get the engine running as quickly as possible. This meant no heavy algorithms in the engine. For example, the objects in the scene were stored in a list, rather than a spatial partitioning data structure.
It was challenging to restrict ourselves to use only simple implementations for the first pass of the required components. If we had taken the time to build components that are more complex, we would never have finished the entire engine.
Setting realistic goals from the start motivated us because we knew we could accomplish the tasks at hand.
We used object-oriented design to abstract these components, so that we could return and replace them as needed without breaking the engine. After we had laid the groundwork and had a prototype game running, we were able to add more features to the engine, such as environment mapping, sound effects, dynamic lighting, improved artwork, enhanced A.I., and an improved control model.
Setting realistic goals from the start motivated us because we knew we could accomplish the tasks at hand. We've seen too many over-ambitious projects with unrealistic goals, and we found that a mixture of realistic goals and a love of games pushed us to exceed our expectations.
2.The Code Nazi. Five programmers working together part time can easily lead to difficult situations. Add to the mix different work schedules, and it's bound to be rough at times. For example, it is often a problem to find people to answer questions about their code especially when you need to modify or decipher it. Perhaps you're sure that there is a bug in the code somewhere. When that time comes, and the other programmer is AWOL, you're sure glad you have a Code Nazi on the team.
The Code Nazi has a zero tolerance rule for poorly written or designed code. He looks over the new code submitted to the project, and ensures that the class definitions are well formed; member variables and functions are following naming conventions, etc.
Now, everyone knows that it is best not to check in code without testing it first. Checking in broken code will cause your team to quickly team up against you for a good pounding. However, even "working" code isn't always good enough. It may contain problems that will not be noticed for a while. Small performance hits can build up, and memory problems are especially tricky. Cleaner code will assist in working those out. Most of all, the code must be easy to understand and reworkable by others.
We didn't officially select our Code Nazi; he just assumed the position (no pun intended). However, no matter how painful it is to have someone there to rip your work to shreds, it's much better in the long run.
3.Flexible Programmers. Before each milestone, the team would meet to decide exactly, which parts of the game and engine we planned to complete before the next milestone. Once we had a clear list of tasks, we assigned individuals or pairs of programmers to complete them. This assignment process could easily have been a major problem — if group members felt that they were stuck doing grunt work on uninteresting parts of the game, the whole project would quickly have lost all of its fun and become just another class assignment.
We prevented this by being flexible and giving every person a chance to work on the parts of the system that interested him. If more than one person wanted to work on a task, we would resolve the problem in several ways. If the task was large, spanning more than one milestone, different people would take over the task for different stages of the project. If a task was small, pairs of programmers could work together on it. The goal was to give as many people as possible the chance to work on parts of the game engine that they wanted to learn about, and make the entire process a worthwhile learning experience for everyone.
DirectX 8 proved to be everything we had hoped, allowing us to make BHX and the HyperX engine into more than we had expected to build in a single semester.
There were instances when it was impossible to give everyone the task they wanted. In these situations, team members had to be flexible, perhaps settling for their second choice, and then getting their first choice of task after the next milestone. Even in these situations, since the group would often meet to discuss approaches to the problems we encountered, any member could make suggestions or raise issues in order to lend a hand on a problem he wasn't directly working on. At the end of the project, we all felt that we had the opportunity to tackle interesting problems and learn about aspects of game programming that we had never encountered before.
4. DirectX 8. We decided right away to use DirectX 8 rather than the OpenGL API with which we were more familiar. We made this choice for two reasons. First, DirectX looked to be more than a low-level API for graphics and sound — it was rife with utility functionality that might prove valuable under our constrained schedule. Second, we saw the value of learning an important tool of our prospective trade.
DirectX 8 proved to be everything we had hoped, allowing us to make BHX and the HyperX engine into more than we had expected to build in a single semester. On the graphics front, D3D and the D3DX toolkit were highly useful. D3DX provides extensive X-file model loading and rendering support. Coupled with the sample X-file exporter for 3DS MAX, this allowed us to build a basic model rendering engine within a week or so. On top of our rendering engine we built our own powerful shading framework ("HyperFX") around the D3DX "Effects and Techniques" infrastructure. Using HyperFX, we could modify the shading of objects in the scene without changing code. D3DX allowed us to easily incorporate features such as multi-texture, texture compression, and cube environment maps. Content creation and testing was made easier through built-in support for multiple image formats, which allowed us to immediately get textured models into our fledgling engine.
There is more to a game than graphics, though, and DirectX seemed to do it all. Besides Direct3D and D3DX, we used DirectInput to automatically detect input devices and to allow the user to easily reconfigure the game controls. Also, we were able to quickly add sound effects to our game during the end-of-semester crunch using DirectSound and DirectMusic.
It is worth noting that while DirectX 8 is an extremely powerful API, it is more than enough rope to hang oneself. Fortunately, we decided early on to design a useful and flexible set of classes around DirectX, and we stuck hard to that decision. By carefully creating a design for the HyperX engine that abstracts DirectX, we avoided being overwhelmed with complexity that wasn't needed for our game.
5. Dedication and Communication. One of the strongest qualities of our team was the common hunger to succeed. The game course did not provide hard deadlines and a blueprint to follow; we all came together as a team and set weekly deadlines for ourselves, deadlines that we consistently kept. It was very important that we not simply plan together as a group, but also set goals together as a group. Working on the game had to be a consistent and pervasive priority to each one of us for the entire semester.
BHX had little to nothing by the way of design documentation. The class was offered on short notice, and did not provide us with the luxury of casual meetings to refine documentation that would clearly map out the direction the game would take. Without documentation, a crucial step in the game design, it becomes incredibly difficult to align the gun sights of each programmer to aim at the same abstract target. Because the game was not simply a goal but a priority, the five of us regularly scheduled time for group meetings outside of class whenever we could. We discussed each and every step of progress that was made, to ensure each programmer was clear on the current state of the game, and to decide where, as a group, we needed to go from there. These meetings took a lot of time, but helped with both our bond as a group, and our focus and direction as individual programmers. Setting up a private newsgroup solved our daily communication needs. We used a free nntp server to host our technical discussions and code check in log. Some technical topics will span an entire project, and being able to refer back to a discussion thread is very useful. Further, each code check in was accompanied by a post to server describing what had been done and any outstanding issues.