Shard Engine / Dead By Destiny
[Note: this page is probably out of date, see my blog for what I'm currently up to]
Dead by Destiny was originally intended to be a final-year university group project, for which I was going to be the lead programmer. The game was to be a combination sci-fi/western incorporating rudimentary 3rd-person combat and exploration on the ground and inside spacecraft, combined with sections of space combat using a Newtonian flight model. To allow for smooth transitions between sections, the game was designed from the outset to run parallel "shards" in a cooperative multi-tasking environment, the idea being that as the player approached an airlock (or similar) the engine could begin to load the shard on the other side and set it running without disrupting any global state that the current shard was using.
External circumstances prevented the project from going ahead, and the engine has since become a project in which I test out interesting techniques that I read about in the context of a full game engine. By placing it in this larger context I prevent myself from resorting to quick hacks and pave the way for the new technique to become a permanent part of the project.
At startup, a single shard is created and runs a Lua script to load whatever objects are needed - this would usually take the form of a menu object in which the buttons either run scripts themselves to create new shards or have hardcoded behaviour. Shards run concurrently, and can be commanded externally to run, pause, load and unload. The resource manager stores graphics assets in containers that are reference counted by the number of shards that use them, meaning that a temporarily paused shard can have its assets unloaded to free up space. Depending on the way the objects inside are simulated, it could even be possible to leave the shard running without its assets, so long as the player did not enter it.
Example object -"elvenbuilding.xml" <Object name="ElvenBuilding"> <Component name="CmpGraphics"> <Model name="elvenbuilding"/> </Component> <Component name="CmpSimplePhysics"> <Position>0,0,0</Position> <Rotation>0,0,0</Rotation> <Velocity>0,0,0</Velocity> <Spin>0,0,0</Spin> </Component> </Object>
Game objects are specified in an XML format which is then compressed into a binary format designed for easy reading. Some object types are component based, allowing the XML to select what kind of physics, graphics, etc the object will use, while others such as the player object are restricted to using a fixed method.
An offline tool processes models and XML-based material files into a convenient runtime format. The material files specify shader, parameters, and any texture files used. Textures are specified with their desired colour format, compression and gamma, and are converted then saved into the runtime directories in DDS format. At render time, objects enqueue each sub-mesh into a list, which is then sorted for minimum state changes by each render system that needs them.
Physics is provided by the Newton Game Dynamics SDK, inside an object oriented wrapper, with each shard managing its own independent physics world. Game entities that wish to influence each other call functions during their update step to add forces and torques to each other, and have a separate post-update function called after the physics update to allow them to react locally to any changes before rendering occurs.
The engine itself compiles as a static library, in order to avoid discrepancies between demos, guaranteeing that a project like PreProcess will always produce compatible output and provide an accurate preview of its output.
Other features include:
- User-customisable key bindings
- Node-based render pipeline including HDR rendering and fullscreen postprocessing
- BSP environments loaded from Zalsoft Getic