Introduction
It seems clear to me that this game will live or die by the amount of systemic gameplay it can offer. By that, I mean that a lot of the emergent narrative potential, as well as the game’s replay value, will come from individual parts of the game interacting with each other. I want the player to feel like their character exists within a deeply simulated world, where other objects and characters have just as much impact on the world as they do.
To enable that level of systemic gameplay, each object needs to have the potential to interact with other nearby objects. And in the finished game, there will be a massive number of object types and even more types of possible interactions between those objects. Therefore, creating a unique system for each type of interaction just isn’t possible. Instead, I need a single, flexible system that each type of interaction can build upon to create unique outcomes. And, I am calling what I’ve come up with the Game Entity System (GES).
High-Level Overview
The general idea is that all of the interactable and dynamic game objects within the simulation will have a shared architecture so that when any kind of communication between entities occurs, there is an established set of variables and logic that can be manipulated or expanded on.
A ‘game entity’ could and will be almost anything; the simplest case being something very static (like an interactable building or tree), and the most complex types of entities being things like characters and even vehicles. Different types of entities will, of course, require their own unique logic, but the GameEntity.cs
component will serve as a reliable base that entities can use to talk to one another.
Anatomy of an Entity
The number one rule of the GES is that every Unity game object that has the potential to impact the gameplay must have its own GameEntity.cs
component. This is the component that other entities will look for and use as a reference for any communication. On its own, the GameEntity.cs
class is fairly barebones to avoid bloat as well as unnecessary memory consumption. But, each type of entity will expand upon the base class through both inheritance and composition.
Currently, the only attributes that all entities must have are a physics collider and an array of all the possible interactions that the entity has. On top of this, the GameEntity.cs
class has some logic to help keep things tidy. For example, getting a reference to its own components, some commonly needed public methods, as well as some events that are invoked within those methods.
All other components & logic that an entity might have will be optional. The GameEntity.cs
class might check to see if they exist, but none of them will be required by default. Some examples of these include optional components include:
- Two different types of health components which both implement a C# Interface called
I_Damagable.cs
. The first of these health components isCharacterHealth.cs
, and the other isBasicHealth.cs
. The reason these two are separate is that I plan to simulate characters’ health in more detail than other entities down the line (which will include things like individual limb damage). - An inventory component which will be used for all the game’s characters, but also any other entities that need the ability to store other entities (e.g. bags & chests). Again, this might also be split into multiple basic and complex variants down the line if needed.
Also, going forward, I anticipate needing to add two more aspects to the game entity system: a way of storing tags/attributes, as well as some kind of status modifier system. Having a set of tags on each entity would make it much easier to check if an entity meets whatever condition the game is currently looking for. And, having a system that handles modification will also be required to adjust the attributes of the entities in a modular way.
For example, any entity that can be set on fire should have an easily readable ‘flammable’ tag. Then, once that entity is set on fire, a new ‘burning’ modifier could be added to the entity, which handles the logic for things like reducing the amount of health over time and spawning the correct flame particle effects. However, right now I am sure where to draw the line between modifier and an interaction, so I will need to think about that some more. But permanent changes to an entity (like a character’s traits and skills) would definitely be a modifier and not an interaction.
How’s it going so far
Now that I’ve developed a lot of the core functionality in the game entity system, I hope that it will allow me to focus more on gameplay going forward. On the other side, I will be doing everything I can to ensure that the GES doesn’t become too unwieldy to work with. One of the ways I’ll do this is by ensuring that Game Entities only require the core aspects of the system by always choosing composition over inheritance wherever possible. But I’ll go more into the system architecture in more detail below.
Lastly, another reason I’ve decided to go with my game entity system is that I hope that it will make it easier for modders to create their content on top of the existing systems (rather than forcing them to make their own).
System Architecture
I’ve given a lot of thought to the architecture of my game entity system, as it is likely going to be the most important system within the entire game. I am lucky that it is not my first time making this kind of system. I attempted to make something very similar when I was still learning how to program. I also made a very similar system in my first job after graduating from university.
Both those attempts taught me a lot of different things, but the main lesson I learnt was how quickly these kinds of systems can become bloated. That’s why I’ve decided to heavily lean towards composition over inheritance this time. The reason for that is that, in my past attempts, my entities always ended up with properties that weren’t needed, which led to wasted memory space and just made everything more bloated than it needed to be.
Another hard rule I’ve made, is that game entities are not allowed to make use of Unity’s Update()
callback. I might break in very, very rare circumstances, but my system is currently structured around more of an event-based architecture. When logic needs to be run on a frame-by-frame basis, those functions will be called by the Entity Manager. That way, the number of updates per frame can easily be controlled. This entity manager will also control a lot of the ‘external helper functions’ that game entities might need (for example, finding the nearest other entity that meets a specific set of conditions).
Although I’ve done my best to build a clean, structured architecture from the jump, I am sure that changes will need to be made as development progresses. I am anticipating that, eventually, having each game entity be its own Unity game object and a collection of monobehavior might start to impact performance. However, for now, I’ve seen no real impact from having hundreds of game entities loaded at the same time (apart from the overhead associated with instantiating them). But its important is that with a project of this scale, to stop myself from optimising too early or getting too obsessed with trying to make the perfect architecture.
Entity Interaction
Enabling interaction between entities is the most important feature in the Game Entity System, as I am banking on it being the system that creates memorable systemic gameplay moments that have an impact on the player's unique emergent narratives.
I am using the term ‘interaction’ pretty loosely; within the context of GES, an interaction could be anything from one character picking up another entity off the floor to a lever entity turning off and on the bulb of a lamp entity. In that lever example, that might have even been a chain of interactions that starts with a character interacting with the lever, which then prompts the lever to interact with the entities connected to itself. Because I am planning on using entity interaction in such a broad sense, I have ensured that I create a system that is simple but can easily be expanded upon by other entities to create unique outcomes.
Interactions are scriptable objects that can be added to an array on the Game Entity components. I decided to use scriptable objects over monobehavior, so there is only ever one instance of any interaction type loaded in memory at any one time. Essentially, Interaction is a collection of methods that can be overridden by each type of interaction, as you can see in the following images.

Going Forward
In conclusion, the Game Entity System is not really a single system. But, instead, it is more a collection of sub-systems where each system is aware that the other systems might exist on any given entity.
Going forward, I plan on building on top of this system to create some actual gameplay. I am not going to do that in a procedurally generated space, which will make it easier to reproduce any bugs. The goal will likely be to turn that sandbox into the first playable demo, so I can get some people to play test it.