Game Object Creation System

Started by
18 comments, last by CrazyCdn 15 years, 11 months ago
Exactly and it's fairly easy to get going in a simplistic manner. I think it took me 4 hours including reading most of the links fully and coding up a few test cases.

Hope it helps :)

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Advertisement
Interesting topic! Those two links you provided, Mike2343, sounds really interesting, I'll have to read up on those!

I've been working on a component based entity system myself for some time, and I've landed on a component based thing for data driven xml definitions of entityTypes that I can then use in my code as a prototype to copy other entities of the same type from.

To prevent many to many relationships between countless components, I've also used a publish/subscribe event system, sigslot, for communication between components, which have worked really well for me.

Here's a link to my code with some explanations (though this is a slightly old version, so the entity factory isn't as safe to use as it is now, and the entityType concept hasn't been implemented in this version):

http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=27319
Here is another cool thing about these types of systems and shows how versatile they are.

Say you have a tree, it could be made up of a SeasonComponent that physically changes the look of the tree as the seasons of the game roll by. Even allowing a growth period where the tree expands, etc. You could also make it have a BurnableComponent that allows it to be destroyed, or partially. Then the SeasonComponent could start to regrow it after x seasons, etc.

The above idea came to me after one of our designers was asking how we could add seasons easily to the engine a few months ago. I then happened upon a thread on here about scene graphs where dmatter (sorry no link @ 3:40am) mentioned something like the above solution but which was contained in the scene graph. I rolled it into a component/entity system way of doing it.

It's easy to make a decent system if you have a nice communications system that doesn't make things interdependent. Otherwise the beauty of this system is completely lost. I've not looked over Trefall's event system but what most people call event systems I decided to call a message system ;-). From the sounds of it, his communicates between components (I've been wrong before) where mine is the engine communications system, though my system uses subscription to templated messages so you don't get every listener in the engine getting every message.

Ok, it's late and I likely rambled and made little sense.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

By interdependent, do you mean that components depend on each other through #include, or that they talk to each other via an event/message system?

I've managed to keep my components #include independent, but I'm using the event/message manager to channel events that updates multiple components for an entity.

With my event manager I can update components that subscribe to events per entity or all subscribers. I find myself using the per entity events more than the global one though. I also subscribes member functors instead of switching through enums.

I read briefly over T=Machine's blog, and it looks interesting. I'll have to read through it more thoroughly, but my impression was that there are one system class per component type. So if you have an InputReceiver component, you'd have an InputSystem to manage the component, or if you have a physicalBody component, you have a PhysicsSystem that manages every instance of that component.

I have that in my system too, only that in addition, the components can talk to each other through an EventSystem, or MessageSystem. I like to call it an Event System because a subscriber's functor to an event describes a logical reaction to that event for the component to perform.

If there's an entity that holds a SceneNode component, an InputReceiver component and an OverTheShoulderCameraController component (practically a player controlled entity), then if the SceneNode component subscribes it's onMoveForward functor to the event "OnKeyWPressed", and the OverTheShouldCameraController component subscribes it's onFollowTarget functor to the event "OnMoveForward", then that results in a logical chain of events and reactions to those events, at least in my mind, that result in a completeness of the system, where each component plays out it's designated functionality to an event.

Of course, I could also have had both the onMoveForward functor of SceneNode com and the onFollowTarget functor of OTSCamCtrl com both listen to the InputReceiver com, but then that would be a breach in logical reaction in my mind, because the camera doesn't logically react on an input event, but rather on the event that the scenenode's position changed.
No I don't use #includes between components that would defeat the whole system in my mind. No component should directly know of another (it might know how to request information through the messaging system of course) otherwise you need to re-examine your component(s) to see if they need to be merged or something.

I call things messages within the engine because anything can message something else if it knows how to listen (I use templated messages). I reserve the term "events" for input from the player or anything in the game (a door opening event, etc). But it's basically tomato, toMATo :)

****

If I have an ogre that is AI controlled it has an AIComponent and that gets passed on to the AI system (a separate DLL in my case, that expects to take in an AIComponent) and controlled from there. The AIComponent just holds data values for the object in question. I read over my posts above and decided how they were handled in my system wasn't overly clear.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Ah, I don't include either, but use publish instead of request. So I do an operation then emit a new event with any data I might have created in the current functor, as I made an example of in my last post here.

I think it's quite interesting how you describe the system - component relationship though. So, the component are only holding properties, so to speak, while the system holds the actual logic that it performs on the properties of the component? That sounds very abstract.

In my approach, each component holds on to their own logic, and since it's the components that get instanced, while the system is a singleton (in my framework anyway), I'm sure you save some resource and optimize it better doing it your way.

But for different kinds of AI, or different levels of AI, for example, would you then have to have two or more AISystems? Or would the AISystem's logic be so generic that you only have to change the properties/data in the component? Or isn't this an issue at all?

I'm getting close to the point where AI will be implemented now, and I'm not sure yet if I want to do it using a base AIComp to inherit from and then make a hierarchy of different types of AI behaviors, or if I want to make it more modular. I generally prefer modular approaches though... but I'm not even sure if I will have to go any of those directions. Maybe just changing the properties/data of the component would be good enough.

Oh, and I actually call Messages for Actions, keeping the Events reserved for the same purpose as yourself.

It's quite complex to break up components though, especially when you're using this approach on top of other thirdparty libraries and can't integrate it completely with the engine. So in some occassions I've failed to find optimal clean solutions for component seperation, but I strive to keep it as seperate as possible. Like, my PhysicalBody component needs the SceneNode component's node pointer to do some initialization and to store it in the body's userData (using NewtonDynamics). But this dependency is handled through the init function on the component, so I've defined it as alright to pass in variables from other components here, but that's it. I know that's not an optimal solution though.
I just got home now and don't have the mental energy to reply. I'll reply on Friday hopefully either give you ideas for your AI or at least shed light on how we do it. Long days suck! :)

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This seems eerily similar to the Spring Framework (for Java)?
Spring Framework, according to the wiki is just a collection of tools basically. The Inversion of Control container seems to have some features similar to Component-Based System Architecture but if you click on the link in the Sprint Framework to Inversion of Control it's actually not. So... *shrug* no idea. Not a java guy :)

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Quote:
I think it's quite interesting how you describe the system - component relationship though. So, the component are only holding properties, so to speak, while the system holds the actual logic that it performs on the properties of the component? That sounds very abstract.


Yes, it was more the way T=Machine described it and I like abstract like that. So its how I went. So far, very, very happy with it. With the GUI it's a bit different in that there isn't a "system" for each widget, instead a message is fired if a button is hit. The message is then dispatched to the function that requests its info and is passed the ButtonComponent which contains the needed info. With AI you just pass each AIComponent on each update to the AI System.

Quote:
In my approach, each component holds on to their own logic, and since it's the components that get instanced, while the system is a singleton (in my framework anyway), I'm sure you save some resource and optimize it better doing it your way.


That seems to be more the Component-Based System Architecture way, which is fine too. I just like simple and abstract when possible. You likely don't need it to be a singleton, likely a global might work a lot better. I won't get into my disdain for the singleton here lol.

Quote:
But for different kinds of AI, or different levels of AI, for example, would you then have to have two or more AISystems? Or would the AISystem's logic be so generic that you only have to change the properties/data in the component? Or isn't this an issue at all?


Actually, I'm not the one doing the AI coding butttttttttt I do peek at the code now and then ;-) So AIComponent holds a lot of data. Object type (grunt, orc, etc). It looks like once the AI System gets the AIComponent it fires off the data to different areas based on different criteria. Like, "Oh your an Orc, you are handled by this class/function, oh your a Human NPC, you are handled by this other class/function".

I'll finish up addressing the last two paragraphs either later tonight or tomorrow. Sorry, just one of those days.

*** EDIT ***

Just finishing up my reply:

Quote:
I'm getting close to the point where AI will be implemented now, and I'm not sure yet if I want to do it using a base AIComp to inherit from and then make a hierarchy of different types of AI behaviors, or if I want to make it more modular. I generally prefer modular approaches though... but I'm not even sure if I will have to go any of those directions. Maybe just changing the properties/data of the component would be good enough.


I would just store the information in data for different types and dispatch it off to the different handlers for those AI types. One variable like we have would work great. Could be a char or int depending on how many different types you have, or sub types.

Quote:
It's quite complex to break up components though, especially when you're using this approach on top of other thirdparty libraries and can't integrate it completely with the engine. So in some occassions I've failed to find optimal clean solutions for component seperation, but I strive to keep it as seperate as possible. Like, my PhysicalBody component needs the SceneNode component's node pointer to do some initialization and to store it in the body's userData (using NewtonDynamics). But this dependency is handled through the init function on the component, so I've defined it as alright to pass in variables from other components here, but that's it. I know that's not an optimal solution though.


Separation is great and something I always strive for. I use a layer between 3rd party libraries all the time, this way I can pass in my components easily. It's more work but means I can change say physics libraries very easily and only the layer code needs to be changed the engine has no clue or do the components.

Hope this helps. You can message me personally if you have more specific questions.

[Edited by - Mike2343 on June 1, 2008 3:09:00 PM]

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement