Game Engine Design
The Design
Choosing a focus
The first step in creating a game engine is designing it. To do that we must first decide on what the engine will do. This may seem simple, but it is the most common place for new game engine programmers to make a critical mistake, unfortunately dooming their entire project. That mistake is being to general. Game engines that try to do everything rarely get finished, and an unfinished engine often doesn’t do anything at all. We are going to try and avoid that pitfall by being much for specific in our design.
There are many different ways to focus the design of a game engine. Choosing one genre of games to design your engine around is a good start. It focuses the functionality of your engine down to a smaller subset of features. The less features that need to be implemented, the sooner (and therefore more likely) you will finish your game engine. We, however, will go a step further. Our engine will be designed to run just one specific game.
That may seem to contradict the idea of game engine reusability (which is the whole reason we are making an engine rather than just a game), but even two very different games often share a lot of the same code. There will still be a few parts of the engine that just will not fit in to another game, but if you were to design an engine to do everything, I can guarantee that there would be a lot more than a few parts that would go unused.
The game
Now it is time to choose what game we will build our engine around. It is a good idea to pick something simple (an MMORPG would be a very bad idea). Tetris and packman are common choices; however I am not going to use those simply because I find them rather boring. Instead I will be designing my engine around Asteroids.
Asteroids is a simple game, but it will provide an excellent example on how to design a game engine. We will be making a few changes to make the game more interesting and to learn about a few more areas of game engines.
Now it is time to define what features our game will have. This is a very important step because this will also define what our engine will need to do. I will make a simple list of the features that I want to include, but I encourage you to think of some additional features to try and include into your game.
- Vector graphics. I will keep the appearance of the game similar to the original Asteroids. Ships, asteroids, and aliens will be drawn with strait lines. There will also be text that will be displayed.
- Ship upgrades. The SS Triangle will no longer be limited to its singe line gun. There will be additional weapons, engines, and other upgrades available to the player.
- Shields. The game will incorporate a shield system to the ship. They will be able to deflect asteroids and block enemy fire.
- Believable physics. When your shields deflect a rock, it will bounce off in a reasonable direction. Your ship will also will accelerate and decelerate in a reasonable fashion. The same rules that apply to your ship should also apply to other objects.
- Infinite universe. Your ship will always be centered on the screen and you will be able to fly in any direction as far as you want. This will take some work dealing with the creation of new asteroids among other things, but it should add some uniqueness to the game.
Modules
We will be dividing our engine into a group of components called modules. Each module will have a specific function. We will try to keep the dependencies between modules to a minimum. That will make the engine more reusable. Here is a list of the modules that we will need.
- Graphics. Drawing and window control.
- Sound. This one is pretty obvious.
- Input. User input from the keyboard and possibly mouse.
- Physics. Something to deal with the simple physics in our game.
- Math. This will be important for a variety of area, graphics and physics in particular.
- Files/Resources. Saving and loading game data.
This is not necessarily the final list. More modules may be added, combined, split, subdivided, removed, bisected, circumscribed, blow up, and other things which I can’t even imagine.
Now another important decision, which module should we start with? I like to start out with the graphics module. The main reason why I usual choose to start out with the graphics is that many things are much easier to test if you can see them. Testing a physics engine is very difficult when you just have long lists of numbers pouring out. Being able to see the results gives you a much better sense of what’s going on (though you should test the numbers on occasion just to make sure they are what you really expect).
Coding conventions
My coding style falls pretty close to the general excepted conventions for Java. There may be a couple smaller differences, but rarely will you find something that looks completely unexpected. I would suggest to all programmers that they should (if you haven’t already) read up a bit on general coding conventions. It makes it much easier for others to understand your code when you need help.
I am also a very big fan of mutators and accessors. If you want to hear my long winded explanation then read the next paragraph. Otherwise you can skip it. Just know that I will be using mutators and accessors thoroughly throughout my code.
Here’s my long winded explanation of why I use mutators and accessors. I find that their biggest advantage is that it allows me to change the underlying implementation without changing everything else that references it. Sure you could give everyone direct access to that 3 by 3 two-dimensional array in your matrix class, but what if you want to change that to a 1 by nine one-dimensional array later. Now every class that uses that array must be changed. If you just used an accessor to get the value at (2, 1) in your array, there wouldn’t be that problem. I like mutators for the same reason (just in reverse). The only drawback to using mutators and accessors is there is more code. Well actually that’s not necessarily true. The class containing the values will be longer however, every class that uses them could potentially get shorter, so net you end up about even. Another complaint might be that they are slow. Regularly functions do have additional overhead however in modern languages such as Java there is usually no penalty to performance. I am not familiar with the internal workings of the hotspot compiler, but my suspicion is that for most mutators and accessors, the compiler knows that all you are really asking for is the data offset x bytes from the beginning of the class and compiles accordingly. That is the exact same thing that directly referencing a value. In conclusion, I like mutators and accessors and will be using them a lot.
And now we are back on track. Coding conventions are an important thing for every programmer to learn. You don’t have follow exactly what it says in some book, but following the common practices is important. What is also important is to be consistent throughout you code. Don’t make people guess. If one of your functions starts with a capital letter they all should.
Starting the actual code
We are now done with the basic design of our engine. Next stop, the graphics module.
-Eric