@toolforger said:
I have a couple of questions myself; hopefully there are good answers to these:
The “OO mindset is bad and needs to be broken out of when doing ES” - I’m missing the argument here. You need to say what exactly the downside was when applying some particular OO idea (or other idea that does not go well with an ES); without that, you’re just arguing ideology and won’t reach anybody who hasn’t already made your experiences.
I will try to remember specific cases where this happens… for now I can only state that it has. It seems especially common at the point where the ES meets with the scene graph where I try to take some shortcut only to realize later that it was a longcut.
If I catch myself in this design hole again or can remember a specific instance then I will post it.
@toolforger said:
What IS the precise definition of data-oriented? data-driven?
Data oriented design is an approach that extracts the operations on the data from the “objects” and flattens the things that they need to run in order to be cache friendly. According to the literature (I got my first exposure in Game Engine Gems 2, Chapter 15), in many cases it actually simplifies the code. I’m not sure I can properly illustrate that feature but I will attempt to show a relevant example at least.
Let’s say you want to implement a physics loop (just the integration of velocity for simplicity), you might structure the data like:
[java]
struct Body {
vec3 pos;
vec3 vel;
}
Body data…
// Then to loop over the data
Body *body = data;
for( int i = 0; i < DATA_SIZE; i++, body++ ) {
body->pos.x += vel.x * tpf;
body->pos.y += vel.y * tpf;
body->pos.z += vel.z * tpf;
}
[/java]
It’s cache friendly because you can fit a lot of “bodies” in a cache line. It’s also friendly to parallelization since various steps are already broken down into stages (another loop might integrate acceleration to velocity, another might transfer velocity to body, etc.). Furthermore, you can interrupt it at any time and keep going if you need to.
There is a whole page of performance justification in that chapter… most of that is largely irrelevant to us in Java.
I fall back on the data oriented patterns because a) it’s the father of entity component systems and b) it helps think about the proper decomposition of logic given that state of mind.
I don’t know if the book is worth the price in general but if you can find/borrow a copy just to read that chapter it might be interesting. I wish it was available online but I can’t find it.
Data driven, on the other hand, can mean a few different things. A common usage is one you may already be using. For example. abstracting something like:
if( a == 0 ) doFoo()
else if( a == 1 ) doBar()
into:
Command commands…
commands[a].doIt()
…is a data-driven design.
State machines are a pretty classic example. There are other approaches. The strictest definition would be where the program is operating on data in a stream and choosing what to do next based on the data in the stream. Wiki-pedia lists awk and sed as examples and those might have been the ones I would have chosen, too.
However, it’s frequently applied to abstract state as well, like in my case above. When the data drives the code versus the logic driving the data, I guess it is “data driven”.
@toolforger said:
What does FRP stand for? I know functional programming (FP) and functional programming language (FPL), and I know most of the FP lingo, but I haven't seen FRP yet.
I thought she meant “Functional Reactive Programming” but I could be wrong. Functional programming could be nice for defining the transforms of a loop in a data oriented design, but FRP always seems more push-based to me.
@toolforger said:
I'm not 100% sold on the performance argument that ES is cache-friendly. You'll get cache-friendliness only if you have "hot" (often-accessed) and "cool" (less often accessed) data, and split the cool data off into a separate data set.
An ES does that automatically, but in typical uses, all components seem hot (because you typically don't put the cool data into the ES). Cachewise, it shouldn't matter whether hot data is in one list or in multiple lists, except that the list data structures themselves are more and do contribute to cache pressure.
Am I missing something?
I think you put cool data into an ES all the time… things like a Name component or a Description component may not be touched by these sorts of data oriented flows at all. They are taking advantage of the other benefits of the ES (decoupling, etc.).
…but the cache friendliness legacy is sometimes just a way to see if an approach is “right”. If you find yourself in an inner loop doing lots of grabbing of other entities or data then there is likely a data-oriented-style step missing somewhere. It’s just a matter of rethinking the problem. The linked thread with the example of the frequent “in range of towers” query is an example where it turns out such a query may not be necessary at all.
I keep meaning to go back and research if the data-oriented literature has anything to say about the many-to-many style problems like collision detection between moving bodies. The gems book hints at some things but isn’t very meaty in that area. I suspect that will always be an ugly problem. It’s not like physics engines suddenly started doing magic here.
I will try to think of some examples where some OOP in the wrong place got me in trouble. Sorry that I’m drawing a blank.
I started out with ESes as a pretty big skeptic. Normen mentioned it to me one day offline and I initially poo-pooed the whole idea. I read the t-machines articles and still didn’t get it… then I read all of the comment threads. I started to see how it could solve some of my problems and so tried to apply it to Mythruna that weekend. By Monday, I’d cleaned up a bunch of code. Furthermore, I no longer had to think “Hmmm. feature X, where exactly should I put that now?” The answer was almost always obvious.
Additionally, I started gaining features as positive side-effects. For example, the fact that entity names and positions where in the ES meant that when I converted my in-game map over to also use the ES, I got moving map markers for free. Just for the cost of adding the entity set query + update loop and deleting a whole mess of map-specific code. I was deleting so much code that I even made a branch because I started to get scared.
It’s a new concept and it’s so easy to get wrong. We carry a lot of OOP baggage that serves us well in every other area all the time. That’s why I try to accumulate tricks to cut through my OOP prejudice. But that’s also why when someone says they tried it and didn’t like it, it’s reasonable to assume that maybe they didn’t do it 100% right. Like if someone says “Oh, I tried sex. It was a horrible mess and I will never do it again.” Immediately questions are brought to mind. Sure, there’s always a chance that is true but it’s worth drilling into.
And that’s also why it deserves experimentation. When some of the other core devs started playing with ESes in their own projects there was almost a general consensus that you couldn’t properly “get it” unless you’d tried to build your own once. I delayed releasing my code for a year or so largely because of this thinking.
But sometimes you just need to give the jedi a light sabre and see if he likes it better than blasters instead of making him construct his own.