[This is a repost from my blog doolwind.com and #altdevblogaday]
I've worked on three different game engines and all have had gameplay and engine intertwined throughout the source code. In Unity, all game objects inherit from MonoBehaviour giving them full access to the power of Unity (and forming a hard link between game and engine). Recently, I've moved away from this approach to a better "separation of concerns". I completely separate out the gameplay making it engine agnostic. This has worked well and I plan to use this approach for most of the games I create in the future. Today I discuss this separation of gameplay and why I recommend others make the switch.
Why would you want to separate out the gameplay from the rest of the game? There are a few main reasons for this:
- Gameplay code varies widely between different games. Whereas other systems like rendering, audio, animations and input have many similarities between different games. (Eg while Battlefield 3 and NFS: The Run share an engine, their gameplay is substantially different).
- Gameplay code has different ownership to the other systems in the game. Most teams are split into gameplay and engine divisions. These two areas require different skill sets which is why there is specialisation in each. Often the size fo the gameplay team will be similar in size to the engine team.
- Designers deal solely in terms of gameplay and so they should. Designers should not be concerned with shaders or specific input code. Separating this code out simplifies their job and protects them and the engine from each other.
- Allows unit testing specific to gameplay code. As the test suites are gameplay focused they are simpler and easier to maintain.
- "Finding the fun" is one of the hardest and most important parts of game development. By separating out gameplay developers can focus solely on this task without worrying about other engine related issues. By dealing with less code, developers have a better velocity to make changes and prototype new ideas throughout development.
We're using Unity and C# for our game development. We split the gameplay out into it's own library (a .dll specifically). This library has no reference to Unity and is completely engine agnostic. In theory, we could swap out Unity for XNA or another engine that is able to communicate with a .NET library.
The game engine then "includes" this library and uses it for simulating the game world. In Unity this is as simple as dragging the .dll into the project and you instantly have access to all it's public types.One option is to make all access from the game engine into the library through interfaces. This gives you the best separation of concerns and completely decouples the game engine from the implementation of the gameplay. I did this for the first game that used this technique but have since moved away from it. I highly recommend having all communication through an interface for larger games and teams.
I've also used this technique in an XNA project which was also a simple process. Simply add a reference to the gameplay .dll and start coding against it.
This separation is often achieved through scripting languages. Certain behaviour within the game is exposed to designers through a scripting language like Lua. I've done this on a number of projects and this separation works well. I've also spoken about why I think C# should be used as a scripting language.
Separation of gameplay is an extension to the regular scripting language breakup. Separation of gameplay flips the classic scripting language paradigm on it's head. Rather than exposing some functionality of the game engine to designers and gameplay programmers to create the game world. We let the designers and gameplay developers create the world and engine developers use this world. This frees both teams up to work at full velocity initially as they build the ground work of the game. Both have set functionality they must achieve and can communicate through a simple, well defined interface. Designers can focus on implementing fun gameplay while engine coders work closely with artists to get the look and feel they want from the game.
Engines like Unity and Unreal all gameplay code is already in a scripting language (Unreal Script and C# vs the engine's C/C++ code). However I'm arguing for taking this a step further and even within these scripting languages we create a separate library independent of any of the engine specific code. We then have three main domains within our game:
- Gameplay specific code (eg Player ship and Torpedo)
- Engine code specific to this game (eg Taking raw input and passing it in a nice form to gameplay specific code or shaders)
- Engine code (for Unity and Unreal this is the C++ code we generally don't access)
I did find a few down sides to this approach. For games where game engine and gameplay ARE tightly linked there can be a lot of duplicated data. As the gameplay code is unaware of the engine data structures like transform must be duplicated in the gameplay code. This increases memory usage and processing as the data structures are converted.
Another downside is that some useful features of the game engine are not accessible to the gameplay. Two key features of Unity that would have been great to use were triggers and coroutines. Once again, code duplication is required if the gameplay is to use these features. (See future plans below for a solution to these issues)
In effect, there are two instances of the game world. A gameplay specific instance and an engine/rendering specific instance. For complex games this separation is a good thing as it frees engine developers to store the world in their own optimized data structures. This decoupling also simplifies the process of multi-threading the game engine as there is a distinct breakup between gameplay specific code and rendering/input code. I've worked on a large project which made this split after a multi-year development and while it was painful to implement once complete the teams velocity increased significantly.
I spoke about unit testing in my last post and this is one of the major advantages of separation of gameplay. You can easily unit test the gameplay itself and have a suite of tests specific to making sure the gameplay is "correct". When unit tests deal only with gameplay they can be simpler and higher code coverage can be achieved. One area I am looking at in the future is formally turning the game design document into a suite of gameplay specific unit tests. The gameplay team have complete ownership over the gameplay code and the test suite that tests it.
There are a few areas I plan to experiment with in the future that I haven't had the opportunity to yet. The first is solving the issue of duplicated data between the gameplay and game engine. My thoughts on solving this problem are for the gameplay to have a reference to the game engine data structures where appropriate. For Unity3D this would be as simple as including the UnityEngine.dll. Spatial data structures (Vector3, Quaternion, etc) can then be used directly in the gameplay. This breaks some of the abstraction between the gameplay and game engine but if done sparingly I think it will add a lot of value. Specific to Unity I'm going to experiment with creating MonoBehaviour entities within the gameplay as well to see whether this works and how badly it breaks the abstraction.
As I mentioned with Unit Tests, I'm going to look at ways of formalising the game design itself into a suite of unit tests. I'd like to experiment with Domain Specific Languages (DSLs) to make this as simple a process as possible for game designers. A DSL would also let them speak in their own language. I've experimented with fluent game design in the past and this is another area of interest for me.
What are your thoughts on separation of gameplay from the rest of the game code? Is this already achieved with scripting languages or do you see extra value with allowing gameplay developers to create the entire gameplay model themselves and have engine developers use world through an interface?