24 comments

[ 3.6 ms ] story [ 71.3 ms ] thread
Interesting to see the evolution from the original game loop to the final system, kind of reminded me of these drawings "from ape to modern homo sapiens". One thing that bothers me with the final result, though, is that you end with a system where you can't tell the difference between two kinds of entities. If in your system infantry can climb aboard a spaceship but not the reverse, you can't guarantee that statically, unless you have a separate layer for this kind of logic.
You'd define a climbing behaviour by a component on the entity.

So your spaceship might have a 'Climeable' component on it and your infantry might have a 'Climber' component. So only a 'Climber' could go onto a 'Climeable' , but not the reverse.

You will also need to qualify these interactions beyond the "class-compatible" test, using flags or exclusion groups or a similar technique to say which climbers can climb atop which climbables. This happens in many areas of interaction between entity components: damage, physics, visibility, etc.
I've always wondered if this idea was usable in general purpose application programming. It is very similar to DCI.
Dynamic and mixin inheritance cover most of what entities are doing. Given a more expressive language where these inheritances could be expressed succinctly, you would probably find them very useful.
It's a sort of interesting divergence from what you'd expect, though. (There's no "one way" of course, but) The Components (mixins) have all of their logic centralized in Systems which get called by the simulation tick. Adam Martin (t-machine.org) writes about how it's similar to a relational model, and even suggests the Entities and Components be stored in an RBDMS when its feasible for performance (MMOs). If you're not using a database, then you're sort of replicating the relational model in your code.

  entity: id
  component: id field1 field2 field3...
  entity_component: ent_id com_id

Then your tick iterates the Systems, each does a query for the relevant components, applies transformations, and puts back in the datastructure. So your logic is very centralized, and the entity behaviors are basically declared by a combination of choosing its Components and choosing the active Systems.
Driving behavior via time is easy once you have your object plumbing. You may also requisition events for this purpose and allow for them to be plumbed separately, if that's useful. I just wrote a paper on such a system, coincidentally:

http://research.microsoft.com/apps/pubs/default.aspx?id=2112...

Entity component systems are not true behavior systems: they do not implement subsumption of behaviors as reflexes. Check out Rodney Brooks' subsumption architectures which is 20+ years old now and used heavily in robotics. The Kodu team used this heavily and I adopted it to one of my own languages once:

http://research.microsoft.com/apps/pubs/default.aspx?id=1793...

Elephants don't play chess indeed!

Thanks, I'll give them a read.
managed time sounds a lot like how FRP (Functional Reactive Programming) and even things as simple as Rx (Reactive Extensions)
Yes, those are both covered in the paper (back in Section 5).
Idea we played with was one step further--take the entities and have their components/state data backed as atoms, and create separate buffers. During update, read from buffer A and write state to buffer B, then swap. This should allow for fairly trivial use of a worker pool to handle concurrent updates.
Really cool idea! This scheme also facilitates a immutable-centric engine.
Yep. We ended up thinking in terms of entities passing messages to each other and being described in terms of functions mapping their current state to their next state.

And then we'd badly reinvented Erlang, in C++. :(

greenspun's tenth rule?
What happens with concurrency was the area I was thinking about too. Particularly what happens if you want a render thread accessing various nodes while the rest of the engine could be in another thread updating the same data.
That's how I wrote the inner core for one of the Tiger Woods PGA games for EA.
Ha! That's awesome, you're awesome. :)
This is interesting, reading some of the linked documents, my naive generalization is that it pushes the entities into using things like maps and dictionaries instead of static properties. The "system manager" stuff just pulls things out of the maps and feeds them to functions to do work, so it is very much 'data-driven' and I must assume more work is put into "configuration" of the entities, just like a data-driven business process requires "configuration" of the order processing pipeline.

i.e. Can some of the complexity of a 'true' entity component system by simply reduced to favoring dictionaries and maps instead of static properties?

Definitely. ECS feels very functional, in that it purposefully eschews OO in favor of something more dynamic.
ECS is very OO. OO vs. functional is orthogonal to dynamic vs. static.
Sorry, yeah, should have said something not class-centric.
What would be an ES-friendly way of modeling relationships between entities? It's hard to give up the speed of pointers in say C++ and use instead handles for example (tho they would come with other advantages like lifecycle handling).
What's cool about this architecture is that it lets you define your game objects in terms of data, not code. You're able to change your game objects at runtime.

I made a small C++/QT implementation here:

https://github.com/surjikal/cbgos-experiment

And here's a screenshot of a game I built with it:

https://raw.github.com/love-rollercoaster/space-game/master/...

This is supposed to be an 3d asteroids clone, but the asteroid and spaceship graphics components were swapped. So you're controlling an asteroid, and your goal is to destroy spaceships.