Vengeance Of XZAR was a game made to demonstrate the capabilities of our C++/OpenGL game engine – Centurion Engine. This project was undertaken as part of the university unit “Advanced Games Design and Programming”, as part of a 3 person team. Despite the unit name, the unit emphasis was on designing and coding a game engine, rather than the game itself.
The Centurion Engine project focused on making an extensible C++ game engine of our own design. We placed great emphasis on designing engine components and interfaces before proceeding to code them, as we realised that starting with a decent design would save time later on in the project.
Engine components were designed to be independent of implementation where applicable. This would allow clients, and other engine components, to interact with engine component interfaces regardless of how the functionality was implemented.
- Component/Composite architecture: expanding on our previous experience with this design paradigm from past projects, we were able to implement a robust, flexible component/composite architecture for the Centurion Engine. Game objects are composed of a set of components, which allows for behaviour to be altered by altering composition. Component managers are used to organise, execute and manage the memory of all relevant components.
- Scriptable Game Asset Factory: A fully Lua-scriptable factory was made, which could easily and effectively construct game objects by creating components, pushing them onto a stack, and loading them into the base game object. The factory was made extensible by adding “creator” functors that took care of creating a specific type of component.
- Encapsulated type system and type streams: Past projects used a raw bit flag type to represent object and component types. Centurion Engine implements an encapsulated version of this system, so the client need not worry about the bit flags themselves. Multiple streams, or “types of types” are possible, and can be easily added to by clients.
- Generic State Machine: A generic state machine was designed for use in the controller system, but was applied in a number of other cases also. The state machine leverages the power of the type system to be scalable and reusable.
- Lua Scripting: Lua was used as the scripting language of choice. A simple scriptEngine class was used to retrieve values and tables from Lua scripts – this proved to be invaluable when writing creator functors for the game asset factory. More advanced scripting features were included for use with the Asset Factory itself, and also with scriptable state machines.
- Handle System: Instead of having related components hold naked or even smart-pointers to each other, we opted for the much safer Handle system. Handles acted as indirect references to assets, objects, and components, and helped to avoid issues that would normally arise when an object is referred to by a number of pointers.
- Terrain Texture Generation: The terrain texture is a procedural combination of 1-4 source textures, with a slope-lighting algorithm to produce a terrain shadow map. The source textures, heightmap input image, and lighting parameters are all fully customisable by using scripting.
- Custom Rendering Engine: As we were not allowed to use 3rd party rendering engines, we had to implement our own. We opted to use GLFW and OpenGL for low-level rendering, initialisation & windowing implementation. VertexBuffer objects were utilised for rendering efficiency, in conjunction with a custom-made Mesh class. This all occurred behind a set of facades, separating the implementation from the Rendering Engine interface.
- Custom Font Engine: A simple texture-based number font was implemented behind the engine’s Font facade. The custom-made number font automatically determined the region of the number-font-texture to draw, depending on what number was required, how many numbers were in the texture, and their associated sizes.
- Custom Animation Engine: A simple custom animation engine was created. Keyframe and Interpolated animation techniques were implemented by reading in a series of model files, and constructing the appropriate animation.
- Modular Particle System: We implemented a highly modular, pluggable particle system. The extensible nature of this particle system allowed for a wide range of particle effects to be created. Particle system examples in the video below include a variety of explosions (shells exploding, tanks exploding), and the waterfall.
- Intelligent Enemy Agents: Utilising the power of our scripted state machine, intelligent enemy behaviours were implemented. Agents navigate using a dynamic nav-mesh, and are able to answer their comrades’ calls for help as the player attacks them.
- No-Fuss Input: The input classes, like many in our engine, were designed to be facades, such that any implementations could occur behind the scenes without breaking the interface. The keyboard and mouse input was implemented using GLFW. Controls could then be specified using scripted effectors to perform any desired actions.
- Amazing Loading Screen: Self explanatory, really.
When it came to designing a game to show off our engine, we again decided that simplicity would be the best option. The game was to portray all major elements of the engine; the game was to serve as a demonstration of the engine, as opposed to the engine being designed around a specific game.
- Rendering engine development
- Script engine development
- Asset importers (RAW, TGA, .obj, .obj animations)
- Animation engine development
- Resource Manager development
- Renderer components and scripts
- Spring Physics Camera
- Terrain system development
- Skybox, HUD and Font creation and implementation
- Creating, sourcing, modifying, texturing, rigging and animating 3D models
- Save system development
- Debugging, gameplay balancing, component integration
See the demonstration video below:
Source Control Video
The following video illustrates the Git source code control activity logs over time: