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!
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 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:
- Kyle Wilson's article on Game Object Structure lists the major problems of using a class hierarchy for game objects.
- Mick West, who worked for Neversoft, explains Entity Systems and how he changed the minds of the developers of the Tony Hawk series.
- Adam's series on Entity Systems and MMOGs are in-depth articles regarding Entity Systems and the future of MMOGs.
- Michael A. Carr-Robb-John's article gives a few examples of commonly used components that can be reused on many games.
- Megan Fox's article on the Entity-Component Model - another way to implement an Entity System. (Also, this is not that one Megan Fox. This one is from Glass Bottom Games.)
- The Artemis Framework by Arni Arent - a Java implementation of an Entity System.