Live data from Hacker News

A Thought Experiment: Using the ECS Pattern Outside of Game Engines

adventures.michaelfbryan.com

51–60 of 75 posts

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#52
post #34

Earlier quoted context omitted.

I have gone down the exact same line of thinking. I think there is value in creating a simple relational data structure to have simple select and insert functions but not the overhead of sqlite. Many times when I think about it, the state of most programs could use a handful of the same structure and be done.

Yeah, I think so too. My goal after hopefully making a completely playable game running on SQLite is to eventually rip it out and replace with my own ECS, based on gained experience. I start with explicit SQL queries, and am slowly building an interface on top of it. Or rather, I'm moving towards the interface I abandoned prior to switching to SQL. Before SQLite, I was working on my (yet another) own implementation,…

I've never written a game where I needed to query for entities (except spatially). Have I just not created the right type of game? If I needed to find certain types of entities they'd get added/add themselves to some list on creation. Querying things at runtime seems anathema to game dev if you want perf which most game devs obsess over

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#53
post #11

Isn't this usually referred to as the decorator pattern when used this way outside of a game loop?

Short answer is no. Decorator is an OOP design pattern, ECS is an architectural pattern. In that sense it’s a more abstract concept. One could say decorator is an OOP form of it, but I think the data oriented design crowd would balk at doing so in a mainstream OOP language like Java or C#.

I suppose you're right. ECS explicitly calls out a system that separate from the components while most of the decorator examples run code in the components. I've written decorators that are closer to ECS but I guess its fair to say ECS implies a specific implementation.

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#54
post #9

Which ECS? :). Despite "clear" definition from Wikipedia, ECS as a pattern suffers from multiple personality disorder. There are several different goals that all share the same name, and different implementations pick a different goal set, ending up looking not quite the same, and getting different kinds of benefits. So outside games, if you pick "ECS as composition over inheritance", you get something like here, or…

> or Clojure's "let's use maps for everything".

Small world. I'm writing a roguelike in Clojure and indeed use maps for everything. Datascript seemed promising, but it is hard to beat Clojure's builtin data selection functions.

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#56

Earlier quoted context omitted.

Yeah, I think so too. My goal after hopefully making a completely playable game running on SQLite is to eventually rip it out and replace with my own ECS, based on gained experience. I start with explicit SQL queries, and am slowly building an interface on top of it. Or rather, I'm moving towards the interface I abandoned prior to switching to SQL. Before SQLite, I was working on my (yet another) own implementation,…

I've never written a game where I needed to query for entities (except spatially). Have I just not created the right type of game? If I needed to find certain types of entities they'd get added/add themselves to some list on creation. Querying things at runtime seems anathema to game dev if you want perf which most game devs obsess over

> If I needed to find certain types of entities they'd get added/add themselves to some list on creation.

From the point of view of the code operating on these entities, this is a query. That it happens to return results in constant time because it's being continuously executed in the background - that's just an implementation detail.

The example I've pasted doesn't execute a full query every frame either. The first time it's called, it ensures that there exists an array within ECS system that stores entities which match the :components part of my query. That array is then continuously updated when appropriate components are added or removed from entities. Multiple different queries using the same :components part (which gets canonicalized, so you can write them in any equivalent order) reuse that array.

The above is equivalent to a typical System in ECS, except I don't create a class or a global instance for it - I just shove a call to select-entities in the place I need it. This makes the architecture a bit more flexible conceptually, resolving some discomfort I had with Systems.

The :where and :order-by parts get executed each time, on the aforementioned array. I could've made them execute when components are added or removed, at the cost of increased memory usage (no more sharing of the filtered entities array); I chose against it in this project. But this isn't really a problem; :where and :order-by subsume the code you'd typically put in your System - processing entities matching a particular condition (e.g. hp Finally, if I pass an array as :into, the result set is stored in that array (which I've statically allocated previously), instead of allocating new memory.

So in the end, this does the same stuff you'd write in your system, but it handles book keeping for you. The interface lends itself for extra optimizations (this is Lisp, I could parse and process the code I put in :where and :order-by clauses, though I don't do that right now). And because it's not a System, not a Thing, I end up using it more often. Say I need to code a spell that picked weak NPCs and healed them automatically. Writing a System that's responsible for handling this effect is something that wouldn't even cross my mind. But a query like in the example above? Sure, why not? So I use it, and it executes almost the same code that I'd written otherwise, except I get some optimizations handled to me automatically. It's a deep interface, and pretty clean conceptually.

(There goes the other half of the blog post I wanted to write. I guess I have no excuse but to do it now.)

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#57
post #9

Which ECS? :). Despite "clear" definition from Wikipedia, ECS as a pattern suffers from multiple personality disorder. There are several different goals that all share the same name, and different implementations pick a different goal set, ending up looking not quite the same, and getting different kinds of benefits. So outside games, if you pick "ECS as composition over inheritance", you get something like here, or…

> or Clojure's "let's use maps for everything". Small world. I'm writing a roguelike in Clojure and indeed use maps for everything. Datascript seemed promising, but it is hard to beat Clojure's builtin data selection functions.

Small world indeed. I work a bit in Clojure from time to time, so I have a passing familiarity with the coding style.

FWIW, for the same game I described above, I also ended up cloning half of Stuart Sierra's famous Component library to use it as my half-baked Dependency Injection framework. This was motivated by the fact that - due to various life reasons - I do a good chunk of my development from a sidearm machine via SSH to my desktop, so I need an architecture where I can develop and test the game in headless mode (no graphics, mock inputs) as much as possible. I write a lot of unit tests now.

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#58
See also: Richard Fabian's "Data-Oriented Design" book. The fourth chapter is about component-based objects, and the preceding chapters about relational databases and existential processing are relevant.

http://www.dataorienteddesign.com/dodbook/

Prior HN discussion: https://news.ycombinator.com/item?id=20380397

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#59

Earlier quoted context omitted.

I'd earnestly like to hear the responses to this from the down-voters. I had the same thought and suspect there is a good reason not to use mixins. One problem off the top of my head is run-time changing of components. An entity that inherits from multiple mixins can't inherit from new mixins (or lose existing ones) at runtime.

Yes, ECS is usually about runtime changes in behavior. It also uses IDs rather than hard references, like in a database. Deleting an object makes references to it invalid, rather than references keeping objects alive like in a functional or object-oriented object graph.

But the complaints about OOP in the article are all about the difficulty in modeling orthogonal traits in a single-inheritance hierarchy. That is definitely addressed with mixins.

Nothing in the "Inheritance isn't Always the Best Tool for the Job" section talks about runtime changes in behavior.

Re: A Thought Experiment: Using the ECS Pattern Outside of Game Engines

#60
post #55

So many of these kinds of OOP modeling complaints and solved by mixins.

Are you saying that this is different from mixins?

Absolutely. Single inheritance is a degenerate form of mixin inheritance, where a subclass has a single, fixed superclass.

Mixins simply fix single inheritance so a subclass's parent class is parameterized, and so concrete classes can be composed of several non-related mixins (which will often seem like multiple super-classes).

ECS is a much different and bigger beast. It's a runtime composition pattern, and has almost basically to do with classes or objects.

If you're only complaint about OOP is with single-inheritance, ECS is probably overkill.

Post reply on HN