A Simple Entity Component System (2019)
austinmorlan.com
austinmorlan.com
- Avoid the inheritance vs. composition issue
- Entity as a first-class concept (no more Object vs. "Just Value Object", confusion regarding equality of objects, object hash methods)
- System as a first-class concept (not just a consequence of a call stack between multiple inter-dependent objects)
- It serves much of the same purpose of the Flyweight Pattern
- Naturally conductive of functional programming
This particular implementation is interesting, it introduces some additional pieces (Component Manager, System Manager).
But... I realize every time that I forget what an entity, component and system really "is" (i mean to be fair the naming is almost satire of genericness), and the abstraction doesn't stick to my brain in a way that I had hoped. Kinda similar to how monads don't stick, and fades away over time (if you're not doing FP). Usually, this is a red flag for abstractions, but perhaps the material I've read has been poorly written. Does this feeling go away when you're used to it? Does it just feel natural and obvious after a while?
An attempt to hide private pieces of data may be counter-productive when an entity system tries to globally optimize the handling of state. A lack of protection though may result in inadvertently depending on parts of data that are a fleeting implementation detail; tight coupling has its own problems.
https://www.gamedev.net/blogs/entry/2265481-oop-is-dead-long...
> I've been a long-time ranter in many "ECS" threads on the forum, partly because I don't think it deserves to exist as a term (spoiler: it's just a an ad-hoc version of the relational model), but because almost every single blog, presentation, or article that promotes the "ECS" pattern follows the same structure:
> 1. Show some terrible OOP code, which has a terribly flawed design based on an over-use of inheritance (and incidentally, a design that breaks many OOD rules).
> 2. Show that composition is a better solution than inheritance (and don't mention that OOD actually teaches this same lesson).
> 3. Show that the relational model is a great fit for games (but call it "ECS").
> This structure grinds my gears because:
> (A) it's a straw-man argument.. it's apples to oranges (bad code vs good code)... which just feels dishonest, even if it's unintentional and not actually required to show that your new architecture is good, but more importantly:
> (B) it has the side effect of suppressing knowledge and unintentionally discouraging readers from interacting with half a century of existing research.
Sorry for the lengthy quote, but I reckon this article is a classic.
But the origin of ECS is Data Oriented Design, also known as DOD, that emerged as a reaction to the bad properties of OOP.
DOD is more general and IMHO more interesting than ECS.
I have not yet seen a satisfying implementation of ECS, it can be extremely fast compared to OOP approach, but also cumbersome when dealing with dependencies between systems and the ways to handle structural changes.
My take would be : learn the principles, do some benchmark, but do not consider any ECS implementation as gospel, this is not mature yet.
Use the ideas and principles to build a fast simulation in your own way.
And for the multithreaded usage, a parallel_for can be used to update systems.
There are good technical arguments for making systems into first-class values, of course, but this interpretation will always be in competition with the older one.
0: https://brochington.github.io/ecstatic-doc-site/docs/example...
What I do wonder about is being able to use a data oriented system that does reflect this neat ability. E.g. if the data in an ECS system is viewed as a simplified relational database, what would happen if we replaced it with a simplified graph database?
Trees are not arbitrary graphs; a tree-based database may have nicer propertied than a web of objects, while allowing to describe nesting in a natural way.
The main mechanism seems to be for 'systems' being able to iterate over tuples of 'components' of a specific type for all 'entities'. I can't help but wonder if there isn't a more elegant way of doing this than trying to keep the set of entities for each system up to date. Though I suppose it depends on what you want to optimize.
An alternative approach, which does not sacrifice the more common OOP style: https://www.doc.ic.ac.uk/%7Escd/ShapesOnwards.pdf
Not that I know an easy way to keep a lists of components that ensure that iterating over them is anywhere close to cache-efficient. Perhaps some kind of self-ordering system would work? (you could for instance move components to consecutive positions as a system uses them, ideally in way that's stable so you don't mess up the ordering of other systems)
It's basically free to do one stripe of bubble sort while iterating, and for games, you'll iterate everything once or more per frame, but introduce and delete things less.
Note that merely ordering isn't quite enough, let's say a particular system needs components ABC and component C is rare, then the ideal situation would be to sort A and B such that those entities with component C are close together.
https://www.gamedev.net/articles/programming/general-and-gam...
See post on C struct composition: https://arpitbhayani.me/blogs/inheritance-c
Because of those, the systems can't really be considered truly independent, can they?
Doesn't this cause complexity to go through the roof?
The shared mutable reference to this message bus would be provided to each system requiring it. It's easily achievable in Rust with Bevy, or with Unity DOTS.
When I don't use Unity DOTS and simply good old MonoBehaviours, I call the message handlers as soon as the message is published instead.
ECS are more similar to the relational model than OOP is, and do not necessarily suffer the same 'object–relational impedance mismatch'.