Entity component system
Entity-Component-System (ECS) is a software architectural pattern mostly used on video game development for the storage of game world objects. An ECS follows the pattern of "entities" with "components" of data.
An ECS follows the principle of composition over inheritance, meaning that every entity is defined not by a "type", but by the components that are associated with it. The design of how components relate to entities depend upon the Entity Component System being used.
History
In 2007, the team working on Operation Flashpoint: Dragon Rising experimented with ECS designs, including those inspired by Bilas/Dungeon Siege, and Adam Martin later wrote a detailed account of ECS design,[1] including definitions of core terminology and concepts.[2] In particular, Martin's work popularized the ideas of "systems" as a first-class element, "entities as IDs", "components as raw data", and "code stored in systems, not in components or entities".
In 2015, Apple Inc. introduced GameplayKit, an API framework for iOS, macOS and tvOS game development that includes an implementation of ECS. Although it is agnostic to the graphics engine used for rendering a game, it includes convenience support for integrating with Apple's SpriteKit, SceneKit and the Xcode Scene Editor.[3]
In August 2018 Sander Mertens created the popular ECS framework called "flecs".[4]
In October 2018[5] the company Unity released its famous megacity demo that utilized a tech stack built on an ECS. It had 100,000 audio sources, one for every car, every neon sign, and more – creating a huge, complex soundscape.[5]
Characteristics
The data layout of different ECS's can differ as well as the definition for "components" and how they relate to an "entity".
The Unity game engine implements two of the most popular layouts.
The most common layout used in the Unity game engine has entities called "GameObjects" that each hold onto a list of components.
The other data layout resembles the design of databases often found in Web Development. The layout has tables each with columns of components. In this system an entity "type" is based on the components it holds. For every entity "type" there is a table (called an "archetype") holding columns of components that match the components used in the entity. To access a particular entity one must find the correct archetype (table) and index into each column to get each corresponding component for that entity.
In a database styled ECS, processes called "systems" act on all entities with the desired components. For example a physics system may query for archetypes (tables) having mass, velocity and position components, iterate over the columns, and do physics calculations on the sets of components for each entity.
The behavior of an entity can be changed at runtime by systems that add, remove or mutate (change the state of) components. This eliminates the ambiguity problems of deep and wide inheritance hierarchies often found in Object Oriented Programming techniques that are difficult to understand, maintain, and extend. Common ECS approaches are highly compatible with, and are often combined with, data-oriented design techniques. Although an entity is associated with its components, those components are typically not necessarily stored in proximity to each other in physical memory.
Debate
A popular blog series by Adam Martin define what he believes to be an Entity Component System.
Martin's definitions and terminology:[2]
- Entity: The entity is a general-purpose object. Usually, it only consists of a unique id. They "tag every coarse gameObject as a separate item". Implementations typically use a plain integer for this.[6]
- Component: the raw data for one aspect of the object, and how it interacts with the world. "Labels the Entity as possessing this particular aspect". Implementations typically use structs, classes, or associative arrays.[6]
- System: "Each System runs continuously (as though each System had its own private thread) and performs global actions on every Entity that possesses a Component or Components that match that Systems query."
Martins ECS
An entity only consists of an ID for accessing components. The idea is to have no game code (behavior) inside of the components. The components don't have to be located physically together with the entity, but should be easy to find and access using the entity. It is a common practice to use a unique ID for each entity. This is not a requirement, but it has several advantages:
- The entity can be referred using the ID instead of a pointer. This is more robust, as it would allow for the entity to be destroyed without leaving dangling pointers.
- It helps for saving state externally. When the state is loaded again, there is no need for pointers to be reconstructed.
- Data can be shuffled around in memory as needed.
- Entity ids can be used when communicating over a network to uniquely identify the entity.
Some of these advantages can also be achieved using smart pointers.
Apparatus ECS
Apparatus is a third-party ECS implementation for Unreal Engine that has introduced some additional features to the common ECS paradigm. One those features is the support of the type hierarchy for the components. Each component can have a base component type (or a base class) much like in OOP. A system can then query with the base class and get all of its descendants matched in the resulting entities selection. This can be very useful for some common logic to be implemented on a set of different components and adds an additional dimension to the paradigm.
Common patterns in Database styled ECS
The normal way to transmit data between systems is to store the data in components, and then have each system access the component sequentially. For example, the position of an object can be updated regularly. This position is then used by other systems. If there are a lot of different infrequent events, a lot of "flags" will be needed in one or more components. Systems will then have to monitor these "flags" every iteration, which can become inefficient. A solution could be to use the observer pattern. All systems that depend on an event subscribe to it. The action from the event will thus only be executed once, when it happens, and no polling is needed.
The ECS architecture has no trouble with dependency problems commonly found in Object Oriented Programming since components are simple data buckets, they have no dependencies. Each system will typically query the archetype of components an entity must have for the system to operate on it. For example, a render system might register the model, transform, and drawable components. It will then check each entity for those components, and if the entity has them all the system will perform its logic on that entity. If not, the entity is simply skipped, with no need for complex dependency trees. However this can be a place for bugs to hide, since propagating values from one system to another through components may be very hard to debug. ECS may be used where uncoupled data needs to be bound to a given lifetime.
The ECS architecture uses composition, rather than inheritance trees. An entity will be typically made up of an ID and a list of components that are attached to it. Any type of game object can be created by adding the correct components to an entity. This can also allow the developer to easily add features of one type of object to another, without any dependency issues. For example, a player entity could have a "bullet" component added to it, and then it would meet the requirements to be manipulated by some "bulletHandler" system, which could result in that player doing damage to things by running into them.
In the original talk at GDC [7] Scott Bilas compares C++ object system and his new custom component system. This is consistent with a traditional use of this term in general systems engineering with Common Lisp Object System and type system as examples. Therefore, the ideas of "Systems" as a first-class element is a personal opinion essay. Overall, ECS is a mixed personal reflection of orthogonal well-established ideas in general computer science and programming language theory. For example, components can be seen as a mixin idiom in various programming languages. Alternatively, components are just a small case under the general delegation (object-oriented programming) approach and meta-object protocol. I.e. any complete component object system can be expressed with templates and empathy model within The Orlando Treaty[8] vision of object-oriented programming.
The merits of using ECS's for storing the game state have been proclaimed by many game developers like Adam Martin. One good example is the blog posts by Richard Lord where he discusses the merits and why ECS designed game data storage systems are so useful.[9]
References
- Martin, Adam. "Entity Systems are the Future of MMOG Development". Archived from the original on 26 December 2013. Retrieved 25 December 2013.
- Martin, Adam. "Entity Systems are the Future of MMOG Development Part 2". Archived from the original on 26 December 2013. Retrieved 25 December 2013.
- "Introducing GameplayKit - WWDC 2015 - Videos". Archived from the original on 2017-10-06. Retrieved 2017-10-06.
- "SanderMertens - Overview". GitHub. Retrieved 2021-09-06.
- "Unity unleashes Megacity demo - millions of objects in a huge cyberpunk world". MCV/DEVELOP. 2018-10-24. Retrieved 2021-06-24.
- "Entity Systems Wiki". Archived from the original on 31 December 2019. Retrieved 31 December 2019.
- Bilas, Scott. "A Data-Driven Game Object System" (PDF). Archived (PDF) from the original on 18 September 2013. Retrieved 25 December 2013.
- Lynn Andrea Stein, Henry Liberman, David Ungar: A shared view of sharing: The Treaty of Orlando. In: Won Kim, Frederick H. Lochovsky (Eds.): Object-Oriented Concepts, Databases, and Applications ACM Press, New York 1989, ch. 3, pp. 31–48 ISBN 0-201-14410-7 (online Archived 2016-10-07 at the Wayback Machine)
- "Why use an Entity Component System architecture for game development?". www.richardlord.net. Retrieved 2021-11-18.