A while back I started work on building a vertical shooter using various high-profile libraries. The work is done in somewhat sophisticated C++11, and I thought it would be nice to add to my growing list of tutorials.
So without further ado, I present the Overdrive Assault Tutorial – how to create an extensible game engine and a simple game with it. The focus will be mostly on the technology aspect. When the engine is complete (or at least usable) I may write a bit about actual game design, but that is a tale for another time. In this installment I will start by laying out a plan and exploring available options. First things first, I’m going to list a couple of things that I’d like to include in the game (sort of a design document, but not quite).
* Tech wishlist *
- – Modular, extensible
- – Multithreaded, reasonable performance
- – Multiplatform, Windows/Linux/OSX
- – 3D
- – Procedural graphics
- – Physics
- – Scripting
* Gameplay wishlist *
- – High speed
- – Frantic shooting
- – Swarm opponents
- – Bosses
- – Upgrades
- – Stats
Ok, step back and let this sink in – this is probably already aiming a bit too high. Obviously, getting this to work will either involve using a readymade engine or *gasp* rolling your own. A quick visit to Wikipedia shows a pretty impressive list of available engines. While these are fine projects, the purpose of this tutorial is to show how you yourself can create an engine like that, while keeping the list of things I want to achieve in mind.
Do realise that it’s in your own best interest to make some concessions and make use of existing libraries – it will save you an enormous amount of work and effort. Mostly the graphics part will warrant a library of itself, but audio, physics, threading and platform abstraction are also good candidates for outsourcing (ha!). Note that *nothing* is set in stone and everything is subject to change as the project grows.
The basic concept of this tutorial is going to be how to actually make a coherent framework out of mostly existing technologies, adding stuff of our own as needed. I prefer hardcore c++ as the main programming language, but it may also be advantageous to use scripting for game logic. At the very least it’s important to make use of a programming language you’re comfortable with; while you’re working on a major project like this you’ll definately end up knowing a lot more about programming along the way, but if you attempt to make something with a language that’s too complicated you’ll end up spending a lot of extra *years* to make up for something that’s probably not relevant anyway.
So let’s look at some options for base technology: Graphics, Audio, Input, Physics, Scripting and Platform. A comprehensive list of just about all options can be found on the GDWiki or GameMiddleware (not particularily up-to-date), and I’ll briefly look at some of them in order to make a sort of informed choice.
* Graphics *
A graphics engine is different from a game engine, although some people confuse the two. Graphics engines focus on making it easy for a programmer to create pretty graphics, while a game engine should have the focus on making it easy to create fun games. Graphics are usually the most obvious front end of a game – it’s the first thing people notice. There are some exceptions to this, such as Audio games or Alternate Reality Games, but I feel it is fair to assume that for this game we’re going to need some graphics. At the moment of writing, there are two major 3D API’s available, DirectX and openGL. All flame-wars aside, the multiplatform constraint means that DirectX isn’t really an option. If this game was intended for the Xbox360 it would be pretty much required to make use of DirectX, but I’d like the game to be playable on my Linux server, which pretty much means it has to be openGL based.
While this choice may steer in the right direction, I also feel that it’s too low-level to be practical at this time. So let’s look at some other options that are either based on openGL or API-independant (I only consider stuff that’s available for free):
The code quality from this is very impressive, although at the same time it is difficult to fully grasp. Also, some of the more exotic features are not really relevant for current-generation graphics. Special support for VR-related stuff and suitable for serious, scientific simulation. Not really lightweight, although not really heavy either. Does feature some nice multithreading features, notably a paged database system for background loading. Specific questions will be answered by the community in a quick fashion, although complete projects based on this library are a slightly uncommon. The documentation is primarily doxygen reference and a big stack of example code. Tutorials and guides pretty rare, and pretty complicated. There is a scene editor available, as well as bindings to various physics engines and scripting systems.
I find the code structure less impressive than that from openscenegraph, but the community is much more active – loads of completed projects. Also with better documentation – in addition to doxygen references loads of guides and tutorials. This library actually wraps the entire 3D API and should be compatible with both DirectX and openGL. While there is some threading support, it’s mostly experimental. Featured in Runic Games’ Torchlight, and gaining in popularity because of it. Not really lightweight, although it scales pretty well. Various scene editors available, as well as bindings to various physics engines and scripting languages.
– Visualization Library
A relative newcomer to the graphics engine scene, this one looks like it’s primarily intended for scientific visualization. The author seems to dislike the tendency of other graphics engines to use a single directed acyclic graph (DAG) as the basis for rendering a scene, and as such this library is structured in a different manner. It’s a very lightweight, thin wrapper for openGL. Being so new does mean that there is virtually no community to speak of and the documentation purely exists of doxygen reference material. No threading support, would require additional infrastructure. No scene editor available, no bindings to speak of. Minimalistic, but in a good way.
Another newcomer, this is actually still in beta at the time of writing. It’s a pretty lightweight engine from the University of Augsburg, with an interesting approach to defining the rendering pipeline. The engine seems to be designed with crowd rendering in mind, but has not been used in many projects yet. Also, while it is being maintained it seems that the community around this is either dormant or just not that active. Mostly API reference as documentation, but this engine is small enough that it doesn’t really matter. No explicit threading support, needs a lot of extra work, but scales extremely well. Basically, this is a very young engine with a limited set of features. Actually has a scene editor available, as well as physics bindings and scripting.
An object-oriented wrapper around openGL, making heavy use of C++11 features. So heavy in fact that it is difficult to use with MSVC, which is a no-go for me personally. I spent some time trying to get it to work but failed miserably 😛
– Roll your own
While using a graphics API is pretty much mandatory, it is generally advisable to add a thin layer on top, as both openGL and DirectX are quite error-prone to use. As long as the objective is to only provide wrappers for stuff you actually use, this looks like it is a feasible option. I want to develop in a cross-platform manner, so this would mean either direct openGL or a renderer-interface with multiple backends.
* Audio *
For cross-platform audio the choices are a lot more restricted. Basically there are only a couple of options, openAL, FMOD and SDL. OpenAL has a bit of history to it, but is being maintained by Creative, Apple and the like. Its use is completely free; in contrast FMOD is a more business-like endevour where non-commercial usage is free, but a paid license is required for other uses. Another option is to make use of SDL, which has the distinct disadvantage that it’s a lot less sophisticated than the other two options. I’m going to go ahead and pick openAL to provide audio capabilities.
* Input *
Most game engines just make use of the platform API to receive input, but there are a couple of other libraries that provide dedicated input handling support, such as SDL and OIS. I don’t really like either, but I’m not looking forward to sifting through platform-specific input handling code. SDL has some licensing issues and OIS is rather limited in their cross-platform support. The choice of library here has a couple of consequences which may not be entirely forseeable. This is because on most operating systems the processing of keyboard keys and mouse events and such is rather tightly coupled to the concept of a window, which is inherently a pretty platform-specific thing. So it turns out that picking a style of handling keys actually also determines how you create and maintain your program window (and its capabilities). I’m planning to use GLFW to create my window, so I’m also using it to handle my input.
* Physics *
Physics is something that is feasible to do yourself as long as the interactions are *really* simple, but as soon as things get complicated you’re better off with a specialized product. Note that using a physics library adds a different set of problems in return – the amount of detailed data required for any sort of physics calculation is pretty surprising and even then it’s difficult to get predictable results. You may end up with stuff falling through walls or violently bouncing off-screen if it isn’t tuned quite right. Ok, so there are basically four major options for a decent physics library – ODE, Bullet, Havok and PhysX.
I’m not really an expert on physics engines, so I’m going to play this one safe and choose PAL, an abstraction library that allows me to change my mind at any time. The only major engine that is not supported by PAL is Havok and I can live with that.
* Scripting *
Again, various options available (LUA, Python, Ruby etc.). I’m leaning towards Ruby actually, as I have not completely mastered that language yet and this should prove to be a good opportunity to create a decent Domain Specific Language. Another option is a variant of Python called Stackless, which should scale very well. At the moment I have never worked with Python before, but I have heard good things about it so I’m going to attempt to integrate Stackless in the project, with Ruby as a fallback.
* Platform *
While there is no explicit need for a platform abstraction system, I feel it saves you a lot of hassle and confusion. I’m going to make use of the infamous Boost library. It’s definately complicated in use, but there is *no* library that has a higher standard for code quality. That alone makes me want to use it. There are other options that I considered, namely dlib, Loki and PoCo, but I’m not going to use those directly (although some of my code may be inspired by these).
Phew, that was more than I expected. But now I’m ready to make an informed choice and start coding. Next time I’m doing the basic design for the core framework, and the first core services will come online. I’m attempting to limit my library usage to Boost and STL, at least for the core framework. One last warning for C++ beginners – this tutorial is not meant for you. If you have problems following the code snippets, you’re probably better off doing an easier tutorial.
This tutorial is more suited to people who know C++ but are interested in learning how to develop frameworks, and as such I’m attempting to adress difficult or otherwise interesting problems and issues. The early tutorials will be very abstract, very generic and only distantly related to making games, but as more of the framework is finished more and more game-specific problems and solutions will be handled in this tutorial. Whenever there’s some design choice to be made, I’ll try to mention it and then proceed to implement one possible solution. While this means that the solution proposed is probably not optimal, there is just so much to do that it’s best to just pick something and go with it. I’m looking forward to this, I hope you are too 😉
See you next time!