Wednesday, July 4, 2012

The Entity-Component Model

Most game programmers, when they start thinking of their game structure, will usually go the Object-Oriented route: have an Entity abstract base class from which to derive every game object. It starts out great: "I want some objects to be affected by physics, so I'll make a PhysicsEntity abstract class and derive them from it. Cars are affected by physics, so obviously I should extend Car from PhysicsEntity." But then, things start to get out of control. "But wait, my cars are destructible, so I should make them composed of several breakable pieces. How about extending Car from DestructibleEntity? Or maybe make the car composed of several DestructibleEntity parts? And how is the player supposed to control it? Should I subclass Car? PhysicsEntity? Or should I create a Controller class and extend it to handle Player input and... ARGH!"

You can easily see where this is going. There are several ways to solve the problem using OO, but none of them actually solve the cause of the problem, which is the fact that game objects are not easily represented as a hierarchy of classes. In the above example, how would you make the car controllable by the players?
  • By making a Controller or Player entity that tells the Car what to do based on player input?
  • By extending the Car such that it responds to player input?
  • By implementing player input handling on the Car itself? (Please don't do this. Ever.)
  • By creating a superclass of entities that can be controlled by the player and have the Car or PhysicsEntity extend that?
  • ... seriously, there are so many ways to "solve" this!
There are also many other problems with this. For instance, what if the game designer goes crazy and decides to let players drive rocks and tree trunks? This is suddenly very hard, if not impossible to do.

So, how do you really solve this problem? If you're reading this, you already know the answer. Hint: It's in the title!

The solution is to use an Entity-Component model.

What is an Entity-Component model?

Entity-Component models take advantage of aggregation instead of inheritance to represent game objects. There are three key concepts of an Entity-Component model:
  • The entity, which is nothing more than an identifier that represents one instance of a game object in the game world;
  • The component, which contains data regarding one feature of the entity;
  • The subsystem, responsible for executing the game logic with the components.
Each entity really is nothing more than an identifier. This could be an integer number, a string, a UUID, a key in a database, or anything that uniquely identifies a single instance of a game object in the game world. Entities do not contain any kind of logic or data in them (though you may keep a list of components in them for performance reasons). These are instead stored in an entity manager, which not only keeps track of every entity existing in the game world, but also the components attached to each entity, and lets subsystems query for entities that possess a particular set of components.

Each component represents one singular feature of the game object, such as "position in game world", "physics-related data (velocity, mass, density, etc.)", "able to wear equipment", "wearable", "shoots projectiles", "has a health meter", "has a mana meter", and so on. One important restriction is that each entity may possess only one of each component type. It doesn't make sense for a car to have two positions, right? The beauty of this model is that you can attach absolutely any kind of component to any entity, so you can do really silly stuff like having a camera that has a mana bar and is wearable by rocks that can shoot more cameras with mana bars. Even better: you can do this while the game is running. No need to recompile everything because you added one new feature to the camera. That's because the responsibility of performing the game logic is delegated to the subsystems.

Each subsystem performs one small part of the game logic based on a set of required components. Rendering the scene is one of them, as is physics processing, combat calculations, player input processing and many others. Subsystems act on components rather than entities, which means that it doesn't matter what "kind" of entity it is (there is no such thing anyway), the subsystems will work on every entity that possess the required set of components. So, if a physics processing component requires Position, Velocity and Acceleration components, every single entity that possess all three components will be processed by it, be it cars, rocks, stars, the track itself, cameras, or anything - so long as they have Position, Velocity and Acceleration components. Since you can add them while the game is running, as soon as you attach these components to anything, that anything will get processed by the physics subsystem and begin moving around.

There are many other advantages to using an Entity-Component model that goes beyond the modeling itself. Since components and subsystems are very small and (usually) independent, they can be processed in parallel, taking advantage of multi-core CPUs. Also, game designers are free to try all sorts of crazy stuff as mentioned above, and it's very easy to implement new features and subsystems. Try adding a regenerating shield to your cars and make them work with everything else (yes, Rocks, TreeTrunks, Cameras and the track itself too) in the hierarchical model. You'll probably end up with either another bloated superclass or adding the shield functionality to an already super-bloated Entity base class. With the Entity-Component model all you need to do is modify the Health component and its subsystem to be able to handle shields. Now everything that has health may also have shields. You could even make health optional if you wanted to. But don't try to make Shield a separate component in this case, as it will lead to some difficulties later.

By the way, guess what you need to do now to make anything in the world controllable by the player? Yes, create a Driver component and the corresponding subsystem. (Of course, you're still going to need to implement the logic, but it is certainly much faster and easier than before.)

These are the basics of an Entity-Component model. There will be many questions from now on. For instance, how do you instantiate entities that resemble a car now? What about the track, the rocks, the tree trunks? I'll leave this as an exercise for the reader, and explain about it later.

Over the next few posts I will be presenting my own implementation of the Entity-Component model while developing a simple space shooter game.

Read more about Entity Systems:

No comments:

Post a Comment