Component Initialisation question

Started by
3 comments, last by Andrew Kabakwu 12 years, 8 months ago
Hi,
Am working on an Entity component system similar to the outboard system described here and other places.

I have subsystems like Renderer, Physisc, AI etc that hook into events that trigger in the scene.

One such event is EntityAddedEvent which triggers when a new entity is created.

The subsystems get this event and create their own type of component (Renderer -> RenderComponent, Physics -> PhysicsComonent) for the entity.

I'd like to be able to pass initialisation data to the subsystems for use in setting up there component eg. Mesh data, initial positiion etc

At the moment, I have created an EntityParameter object which gets passed to each subsystem.
The EntityParameter object hold a table of values per each component type it wants created eg.
table ["Renderer"] = <Mesh, "Cube.obj">
table ["Physics"] = <Scale, "1.0, 2.0, 3.0">
table ["Physics"] = <Rotation, "45.0, 0.0, 0.0">

So each subsystem can then issues commands like - EntityParameter->GetValue ("Renderer", "Mesh") and uses that data to initialise its component.

Is this a good approach?

How do you guys handle this issues of passing data to subsystem for use during their component creation and initialisation?

Thanks.
Advertisement

Hi,
Am working on an Entity component system similar to the outboard system described here and other places.

I have subsystems like Renderer, Physisc, AI etc that hook into events that trigger in the scene.

One such event is EntityAddedEvent which triggers when a new entity is created.

The subsystems get this event and create their own type of component (Renderer -> RenderComponent, Physics -> PhysicsComonent) for the entity.

I'd like to be able to pass initialisation data to the subsystems for use in setting up there component eg. Mesh data, initial positiion etc

At the moment, I have created an EntityParameter object which gets passed to each subsystem.
The EntityParameter object hold a table of values per each component type it wants created eg.
table ["Renderer"] = <Mesh, "Cube.obj">
table ["Physics"] = <Scale, "1.0, 2.0, 3.0">
table ["Physics"] = <Rotation, "45.0, 0.0, 0.0">

So each subsystem can then issues commands like - EntityParameter->GetValue ("Renderer", "Mesh") and uses that data to initialise its component.

Is this a good approach?

How do you guys handle this issues of passing data to subsystem for use during their component creation and initialisation?

Thanks.


I'm using c# right now, so my method of handling this might be somewhat different, because I lack the ability to use RAII.

Regarding attributes, I don't store attributes at the entity level, instead I use the public interface of my components.

My entities undergo the following lifecycle:

1) The constructor for the individual entity is called. There are two types of constructor contents - some are remnants from my older class heirarchy stuff. New ones add components to the entity. Following this stage, the entity has instances of all its components but nothing is linked up.
2) The entity is told to "link references" and it is at this point that components cache local references to other components they are interested in on that entity, and components of the world. (The world has a dedicated entity for all its components, and this is where the physics, ballistics, and scripting interface lie)
3) The entity is added to the world, and enterWorld is called. This call is passed to all components.
4) The entity is updated every frame.
5) The entity may be de-activated at some point, and then re-activated, in order to achieve LOD in world behaviour.
6) The entity is told to remove itself from the world. This is also delegated to components.
7) The entity might be reinserted into the world again later. I do this to recycle transient entities and avoid the overheads of a new initialization, or allocation.

Because I am using a garbage collector, I have to be very cautious of resource leaks, and I do this by ensuring that the world is the only bridge to anything outside of the entity system - entities can occasionally reference things external to the world, but things outside the world storing references to entities is strictly forbidden. Thus, when I delete the world at the end of a level, it becomes a single big island which can be collected.


So, in summary, this call sequence happens:

At initialization time:
constructor for Entity, and constructors for Components
link references

At runtime:
add to world
activate
update
update
update
possible deactivate
<entity is now idle and not updated, but can respond to events still which may wake it>
activate
update
update
leaveWorld

From here it may be recycled.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

I'm using c# right now, so my method of handling this might be somewhat different, because I lack the ability to use RAII.

Regarding attributes, I don't store attributes at the entity level, instead I use the public interface of my components.

My entities undergo the following lifecycle:

1) The constructor for the individual entity is called. There are two types of constructor contents - some are remnants from my older class heirarchy stuff. New ones add components to the entity. Following this stage, the entity has instances of all its components but nothing is linked up.
2) The entity is told to "link references" and it is at this point that components cache local references to other components they are interested in on that entity, and components of the world. (The world has a dedicated entity for all its components, and this is where the physics, ballistics, and scripting interface lie)
3) The entity is added to the world, and enterWorld is called. This call is passed to all components.
4) The entity is updated every frame.
5) The entity may be de-activated at some point, and then re-activated, in order to achieve LOD in world behaviour.
6) The entity is told to remove itself from the world. This is also delegated to components.
7) The entity might be reinserted into the world again later. I do this to recycle transient entities and avoid the overheads of a new initialization, or allocation.

Because I am using a garbage collector, I have to be very cautious of resource leaks, and I do this by ensuring that the world is the only bridge to anything outside of the entity system - entities can occasionally reference things external to the world, but things outside the world storing references to entities is strictly forbidden. Thus, when I delete the world at the end of a level, it becomes a single big island which can be collected.


So, in summary, this call sequence happens:

At initialization time:
constructor for Entity, and constructors for Components
link references

At runtime:
add to world
activate
update
update
update
possible deactivate
<entity is now idle and not updated, but can respond to events still which may wake it>
activate
update
update
leaveWorld

From here it may be recycled.


Sorry for delay in responding, been away for the weekend.

Thanks for your response.
I don't have a base Component class so there is not public interface. Your approach is totally different from what am planning, but can help with some ideas.

Am sure other people have their own methods for initialise components by subsystems at creation time.
Please share.
I think your EntityParameter idea is good and data driven.

But what's the reason that you don't have a base class for your components?
A single-root hierarchy will make your life easier.

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.


But what's the reason that you don't have a base class for your components?
A single-root hierarchy will make your life easier.


Am doing this to avoid issues raised in the topic linked to above.
I dont have a base Component class because in general, components have little in common. There is also NO component type enum/string. Also as am not going to be using one system to process all components, there is little to be gained.
Adding new component "types" is easy, as each component "type" is managed by its corresponding subsystem.

I was expecting more discussion on this topic.....

This topic is closed to new replies.

Advertisement