Entity system pondering (yup, yet another)

Started by
16 comments, last by Foxostro 15 years, 10 months ago
Quote:Original post by redmilamber
Quote:Original post by Kylotan
Quote:Original post by virus-
I've read pretty much everything I can find about entity/component system and while I earlier had a bit different implementation in mind Adam's posts about entity systems made me think of a bit different solution.


I cringe every time I see someone cite that URL. I find issue with so much of what is in that blog, sadly.


Have you raised your specific objections on the blog? Lots of other people have. If you keep quiet, no-one can help you.


I don't need help.

Quote:OTOH, when I say "entity system" in the office, so far *everyone knows what I mean*, which is a compromise I'm willing to accept.


I think some terminology is worth fighting to change. It's better to have a term that actually carries some meaning.
Advertisement
I use component based entity system, for what it's worth. It may as well be aggregation but the word component carries some extra meaning of late.
[size=2]
Quote:Original post by Ubik
Quote:Original post by virus-
Have subsystems register with other subsystem for messages, that way we can send messages to those subsystems that care about them but this requires knowledge of those subsystems so adding a new system might require changes to others.


An alternative to this is that you have a messaging module, and the other modules register themselves only with it, telling what kind of messages they want to send and receive. This way a module need knowledge of only one other module, and I think that in a messaging based system a dependency to messaging system is acceptable.

Though now that I think about it, messaging could be arranged so that the messaging system is the one that asks the modules what kind of messages they want to send and receive, this way only the messaging system needs to know anything about other modules. And if the modules have generic enough messaging interface, even the messaging module could be pretty ignorant about whose messages it is delivering.


My vote is against messaging systems. It tends to introduce implicit and hidden dependencies. If A is delivering a message to B, then either A needs to know how B would like to have it's message, or B has to know what kind of messages are passed around by A (ie: the direction of the dependency is a design choice). So (conceptually) there is a dependency. And if there is, it better be explicit.
Having the messaging system in the middle can introduce strange behavior when some subsystem is not hooked in the system. Some expected or required messages may not be received, or synchronization between sender and receiver of a message may pose a problem. If I had to chose between having to pass a few extra references around and add some include files, or hunting down obscure problems caused by messages not being passed around, I'd chose the first.

Perhaps you can eliminate the inter-subsystem communication entirely. Your subsystems are only working on the data, and your "data" is responsible for notifying others that it has changed.
In terms of animations and rendering, your animation subsystem works on an animation, and once the animation is ready to be rendered the animation component itself tells all the interested subsystems, rendering, it has changed.


Quote:You can probably draw rest of the system out and it'd fall perfectly to number 5. on Adam's list, excessive use of observer pattern

I don't quite understand why this would stand in the way of a component system, other than just being a design challenge and PERHAPS a performance issue. (Note: I never implemented a component based system, only read about it, so I may be wrong).
The idea is that a subsystem is notified of changes of the data in a component. An observer pattern would be able to fulfill that purpose just as well as a messaging system. The design challenge is how to get the subsystem subscribed and unsubscribed to the component as it is loaded or unloaded.
The performance issue might be with excessive subscribe and unsubscribe actions. But then again, you're not going to do thousands of subscriptions every frame, are you?

From the top of my head: I'd probably use the approach of having a component factory to tackle the design challenge. Have the subsystems tell the component factory in which type of components they are interested, and the factory can notify the subsystems if a new component is created or loaded.



In short, when reading the original post it seems to me that the messaging system is the cause of the problem. I believe that the messaging system can be eliminated to create an easier to understand system that can solve your problems in a much easier way, and still be considered a component based system.

Again, I have no experience creating a component based system, so I may have missed something.
STOP THE PLANET!! I WANT TO GET OFF!!
Quote:Original post by Trefall
I've learned that there's a lot of debating on what exactly a component should be though, and what exactly a system should be. In adam's approach, referred to in the OP, I get the impression that a component is just a container of data, but that each type of component also comes with a complimentary system that can process that data in some logical form.


Yes, it's about the separation of logic and data. i.e. the antithesis of Object Oriented Programming - and this is a large contributory factor to why so many game devs switched to doing it (at least for mainstream games dev): OOP has turned out to be almost pathologically bad for modelling game-logic systems as they've grown to the complexity they are at these days.

I think there's a certain amount of guilt that no-one wants to slag-off OOP, because it's not so very long ago (maybe a decade) that many games industry teams were refusing to use OOP at all. There are even some (I know of at least one) well-known large game development studios that only code in C still - for all aspects of the game (the vast majority of modern game programmers consider such behaviour ... odd).

You, of course, are free to do whatever you want. With simple logic (e.g. to power a basic FPS like Doom or Quake) I'm sure you'll be fine. Those of us who have first-hand experience with the nightmare of intertwined logic/data game-object systems and never want to go there again will happily go on our way with a cleanly separated system. But if you want to build the complex logic that underpins a modern FPS, with all the world-simulation stuff, then I'd advise you join us. If you want to work on an MMO, god help you if you decide to persist with mixing up logic and data - that way (at least on any MMO that survives more than a couple of years) lies madness. IME. YMMV.

Quote:
In my approach I have the logic handled in the components themselves, but since it's the components that get instanced, and not the component systems, I'm sure there's quite a lot to save doing the logic system side if one can generalize enough to do it that way.


I'm afraid I cannot see any way in which what you write here differs from standard OOP. That's fine, I've nothing against that. Am I missing something? You have instanced "things" which contain code and data - that's a standard Object, no?

But if I'm not being dumb, and that is the case, why you don't just use the standard game-industry terminology, call your components "GameObjects", and have done with it?
Quote:Original post by redmilamber
Quote:Original post by Trefall
I've learned that there's a lot of debating on what exactly a component should be though, and what exactly a system should be. In adam's approach, referred to in the OP, I get the impression that a component is just a container of data, but that each type of component also comes with a complimentary system that can process that data in some logical form.


Yes, it's about the separation of logic and data. i.e. the antithesis of Object Oriented Programming - and this is a large contributory factor to why so many game devs switched to doing it (at least for mainstream games dev): OOP has turned out to be almost pathologically bad for modelling game-logic systems as they've grown to the complexity they are at these days.

I think there's a certain amount of guilt that no-one wants to slag-off OOP, because it's not so very long ago (maybe a decade) that many games industry teams were refusing to use OOP at all. There are even some (I know of at least one) well-known large game development studios that only code in C still - for all aspects of the game (the vast majority of modern game programmers consider such behaviour ... odd).

You, of course, are free to do whatever you want. With simple logic (e.g. to power a basic FPS like Doom or Quake) I'm sure you'll be fine. Those of us who have first-hand experience with the nightmare of intertwined logic/data game-object systems and never want to go there again will happily go on our way with a cleanly separated system. But if you want to build the complex logic that underpins a modern FPS, with all the world-simulation stuff, then I'd advise you join us. If you want to work on an MMO, god help you if you decide to persist with mixing up logic and data - that way (at least on any MMO that survives more than a couple of years) lies madness. IME. YMMV.

Quote:
In my approach I have the logic handled in the components themselves, but since it's the components that get instanced, and not the component systems, I'm sure there's quite a lot to save doing the logic system side if one can generalize enough to do it that way.


I'm afraid I cannot see any way in which what you write here differs from standard OOP. That's fine, I've nothing against that. Am I missing something? You have instanced "things" which contain code and data - that's a standard Object, no?

But if I'm not being dumb, and that is the case, why you don't just use the standard game-industry terminology, call your components "GameObjects", and have done with it?


Most definitions of OOP are tied closely to polymorphism and inheritance, of which don't factor heavily in component based systems. At any rate, bag of components is definitely a lot different than the conceptions "GameObject" conjures up. The system Scott Bilas described in no way mentions components contain only data.

Seperation of logic and data seems like a diffent concept entirely. What was described here as an "outboard" component based systems would be the melding of the two.
[size=2]
Quote:Original post by wild_pointer
Most definitions of OOP are tied closely to polymorphism and inheritance, of which don't factor heavily in component based systems.

OO is a *lot* more the polymorphism and inheritance... Aggregation is just as important, and all that these ent/component systems are doing is giving you run-time control over aggregation.

Separating out the logic and data as much as possible is *not* the antithesis of OO. In fact, it is a sign of *good* OO...

Wheras if it was all hard-coded, you would write your entities like the following snippet, these systems allow you to do this at runtime (which is what makes them so great). Though IMO, saying that this is a fundamentally different paradigm to OO just seems like you're missing the point of OO (which is why I think the blog linked in the OP is complete rubbish).
class CEntityNumber12 : public CEntity{private:   CTransformationComponent m_trans;   CSceneGraphComponent m_scene;public:   virtual void GetComponentListing( vector<CComponent*>& out )   {      out.push_back( &m_trans );      out.push_back( &m_scene );   }};World->Insert( 12, new CEntityNumber12 );
Quote:Original post by redmilamber
Quote:
In my approach I have the logic handled in the components themselves, but since it's the components that get instanced, and not the component systems, I'm sure there's quite a lot to save doing the logic system side if one can generalize enough to do it that way.


I'm afraid I cannot see any way in which what you write here differs from standard OOP. That's fine, I've nothing against that. Am I missing something? You have instanced "things" which contain code and data - that's a standard Object, no?

But if I'm not being dumb, and that is the case, why you don't just use the standard game-industry terminology, call your components "GameObjects", and have done with it?


My point was targetted towards 1 instance of logic instead of N instances of the same logic. To me it just sounds more logical to have the logic in the components that I work with though, not in the sense that it would be more optimized or easier to debug, but rather in the sense that a health component treats health specific functionality. My health component doesn't just hold on to int _currHealth and int _maxHealth, but also the onHealthReduction, onHealthIncrease, onResizeMaxHealth. Of course I could seperate data and logic here, and say that the HealthComponent holds on to int _currHealth and int _maxHealth, while HealthComponentSystem holds on to onHealthReduction, onHealthIncrease and onResizeMaxHealth.

But then the HealthComponentSystem would need to hold a list of HealthComponents, or at least references to Entities' HealthComponents... I don't know. Maybe it's a better solution than the one I'm currently running with now.

I'm already defining my components in scripts though, and putting together Entity types in xml, defining which components with parameters each entity is built up of.

I guess I could split it more and add the component systems into the mix though... but I'm not sure I'd gain that much by doing so. I mean, it's not like each component stores a thousand different data variables or nothing.

And on the object orientation part, I wouldn't say it's not object oriented. Just storing derived components of the base component into a list that takes base components is object orientation. Also, in my mind, it makes sense in some occassions to have some hierarchial inheritance structure on components, though it will never get as deep as with deep hierarchy entities of course.

Quote:Original post by virus-
You can probably draw rest of the system out and it'd fall perfectly to number 5. on Adam's list, excessive use of observer pattern .

I've been looking for this part in his blog, but haven't been able to find it. As I'm using the observer pattern for component communication, I'd be interested in reading about it. For me it works really well, though it does create some soft dependencies which can be hard to debug if one doesn't keep a good orientation with what's happening. It won't crash though, since if the event published has no subscribers, the event simply won't be distributed to anyone and the program will move on. I'm sure there's more issues with the observer pattern when you throw multiplayer into the mix though, and surely it's not as optimized as direct references and C style messages, but to me it's been a trade for what I've experienced as a cleaner approach.
Quote:Original post by Trefall
Quote:Original post by virus-
You can probably draw rest of the system out and it'd fall perfectly to number 5. on Adam's list, excessive use of observer pattern .

I've been looking for this part in his blog, but haven't been able to find it. As I'm using the observer pattern for component communication, I'd be interested in reading about it. For me it works really well, though it does create some soft dependencies which can be hard to debug if one doesn't keep a good orientation with what's happening. It won't crash though, since if the event published has no subscribers, the event simply won't be distributed to anyone and the program will move on. I'm sure there's more issues with the observer pattern when you throw multiplayer into the mix though, and surely it's not as optimized as direct references and C style messages, but to me it's been a trade for what I've experienced as a cleaner approach.


Quote:


That’s not an Entity System!

Well … at least, that’s what *most* people I’ve worked with consider to be an Entity System. But even within a single project, I’ve found multiple different ideas of what an ES is, some of which are compatible, others of which are incompatible. Here are some of the other ideas I’ve come across that people thought were ES’s.

Alternative definitions of entity systems:

1. An ES provides a different model of class-inheritance to OOP, especially w.r.t inheritance of fields. For any given entity-class you declare which aspects that class possesses, and the actual class is looked-up at runtime by piecing together all the different aspects.

2. The same as 1., but taken literally for methods as well as fields, i.e. this provides an interesting way to mix-n-match inheritance of functions/methods. So long as methods are attached to the fields upon which they operate, and/or a “pre-requisite” system is implemented such that “having aspect X automatically causes you to also have aspect Y”, then this works quite smoothly. NB: this is implementing “modular objects”: the “aspects” are complete objects from the standard theory of OOP.

3. A variant on 1. or 2. where the aspect data is pre-compiled into a large number of OOP classes at compile time, so that at runtime you are just running “normal” classes, without any lookup cost of the dynamic “I’ve got an entity E which claims to have aspect X; just hold on a sec while I build a function table to find out what the heck to do now someone just tried to invoke function Z…”

4. A way of compiling standard OOP classes into runtime-data (note: disassociating them from their OOP-ness) specifically so that you can treat them as streamed data instead of chunked binary + data. The main value of this is to play nicely with hardware that has tiny tiny amounts of memory available in the code cache and/or very very slow access to fetch extra code, but has vast bandwidth to stream SEQUENTIAL data through the CPU. PlayStation consoles especially like this approach, as opposed to the typical PC approaches. Note that in this case, the idea is that the game-programmers and game-designers are UNAWARE that there’s an entity system - it’s a runtime/compile time performance optimization, not a design-feature.

5. A system design that revolves around excessive use of the Observer pattern, but does so using standard OOP techniques. I mention this because it’s a common (ab)use of the concepts of ES’s, but lacks much of the advantages. For what it’s worth … that’s the situation I was in when I first discovered ES’s. So, personally, I really don’t count these as ES’s. These are not an ES, but an: “OMG, I need an ES!”, but many people persist in thinking (and claiming) they’re a true ES.




This topic is closed to new replies.

Advertisement