Thoughts on this component system for a game engine.

Started by
29 comments, last by Antheus 14 years, 10 months ago
I have this design in my game:

IEntity contains a map of IComponent instances. IComponent could be GameLogic, Physics, or Graphics (stores texture file, mesh file, the IRenderable instance) and other components needed. Each IComponent implementation has it's own manager, like GameLogicManager, PhysicsManager, RenderingManager.

There are two types of managers, the game update managers and rendering manager. The rendering manager only needs to know the position, the IRenderable instance (handles the rendering of each entity depending on its implementation whether mesh or texture), and the bounding information (AABB or sphere or whatever). The GraphicsComponent is the suited component to have these data. It's up to the rendering manager whether to use octree culling, view frustum culling, and so on.

So the game loop will look like:

void update() {  gameLogicManager.update(); // performs logic on GameLogic components  physicsManager.update(); // performs logic on Physics components  // other update managers calls update}void render(){  renderingManager.render(); // it's up to the renderingManager how to render stuff}


I also have a concept of IEntityTemplate objects, like ShipEntityTemplate. This class loads the required components a certain entity needs.
Advertisement
Quote:Original post by Matt Sloan
Quote:Original post by swiftcoder
An implicit message passing system works pretty well - I find explicit messages to be too expensive for inner loop calculations. By implicit I mean that each piece of data is visible to all sub-systems, but many only be written to by exactly one (predefined) sub-system.
This is the other option I was thinking about, and seems to be one of the more popular routes.

Few questions..

1) Tell me if I have your implicit system understood based on this example. The position component contains data that needs to be read by both render and physics components. When physics wants to change position data, it sends out a message that is handled by the position system. The position system in turn locks the data, makes changes, then releases the lock. If the renderer wants to read that position data it would do so via a const Vec3& getPos() function which would be accessed through entity properties so you end up with no coupling between render and position systems.
How does that sound?
I meant a whole lot more implicit. In particular, I have never seen the point of trying to de-couple the position component, because every entity has one, and most other components need access to it.

So there is no position component, just a position attribute (which resembles a component in terms of API) attached directly to the entity. The physics component writes directly to it (using minimal locking), and all other components read directly from it.
Quote:2) How inefficient did you find explicit message passing to be exactly? Is there anyway it could be viable even if it was slower than implicit?
It depends how you arrange it. Your system requires a message to be passed every frame, per-shared-attribute, per-entity, and that is one hell of a lot of messages. Still, with intelligent caching of data, you can probably get away with it.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I know that Singletons are not recommended but i am starting to think that the best option for the main Engine class would be for it to be a Singleton. Thoughts on this?

Quote:
So there is no position component, just a position attribute (which resembles a component in terms of API) attached directly to the entity. The physics component writes directly to it (using minimal locking), and all other components read directly from it.


Actually how i am planning it this might not work because i don't want there to be any physical Entity class. An Entity is just a label that is a member of the Components.


Thanks for all the help so far.
Check out my new blog: http://beefmachinegames.wordpress.com
Quote:Original post by Wizecoder
I know that Singletons are not recommended but i am starting to think that the best option for the main Engine class would be for it to be a Singleton. Thoughts on this?
Why would it need to be a singleton? I very much doubt that every class in your code is going to need to access the Engine class (and that is the only truly justifiable reason to use a singleton/monostate).
Quote:
Quote:So there is no position component, just a position attribute (which resembles a component in terms of API) attached directly to the entity. The physics component writes directly to it (using minimal locking), and all other components read directly from it.
Actually how i am planning it this might not work because i don't want there to be any physical Entity class. An Entity is just a label that is a member of the Components.
Ja, I took that approach initially as well, but I ended up reverting to storing a few pieces of very fundamental data in the entity.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:original post by swiftcoder:
Quote:Original post by Wizecoder
I know that Singletons are not recommended but i am starting to think that the best option for the main Engine class would be for it to be a Singleton. Thoughts on this?


Why would it need to be a singleton? I very much doubt that every class in your code is going to need to access the Engine class (and that is the only truly justifiable reason to use a singleton/monostate).

It might be necessary for the Systems to be able to access some of the functionality within the Engine. I guess i could just store a pointer to the Engine inside the Systems but i was thinking a Singleton would be better.

Quote:
Quote:
Quote:
So there is no position component, just a position attribute (which resembles a component in terms of API) attached directly to the entity. The physics component writes directly to it (using minimal locking), and all other components read directly from it.

Actually how i am planning it this might not work because i don't want there to be any physical Entity class. An Entity is just a label that is a member of the Components.

Ja, I took that approach initially as well, but I ended up reverting to storing a few pieces of very fundamental data in the entity.

I think i will still stick to as separate as possible. I can try to enforce creation of a position component if i make any level editor tools.
Check out my new blog: http://beefmachinegames.wordpress.com
Quote:Original post by Wizecoder
Quote:original post by swiftcoder:
Quote:Original post by Wizecoder
I know that Singletons are not recommended but i am starting to think that the best option for the main Engine class would be for it to be a Singleton. Thoughts on this?
Why would it need to be a singleton? I very much doubt that every class in your code is going to need to access the Engine class (and that is the only truly justifiable reason to use a singleton/monostate).
It might be necessary for the Systems to be able to access some of the functionality within the Engine. I guess i could just store a pointer to the Engine inside the Systems but i was thinking a Singleton would be better.
That is not a good justification for a Singleton. As I said, unless *every* class in your code needs access to the Engine, then global visibility is a bad thing™ (especially if you plan to have multi-threading).

But a bigger question is why most of the systems would need access to the Engine class? That sounds like it may be an issue with your design.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I tried my hand at this game engine stuff. Here's what I got:


It's an RTS. It has an AI framework built in too and I had some of my friends make computers to play against. There's one main class that regulates the callings to many smaller classes that handle each aspect of the game.

Everything's in the early stages of development though.
Quote:That is not a good justification for a Singleton. As I said, unless *every* class in your code needs access to the Engine, then global visibility is a bad thing™ (especially if you plan to have multi-threading).

But a bigger question is why most of the systems would need access to the Engine class? That sounds like it may be an issue with your design.


I guess i am just not totally sure how to implement the message system. So i was thinking that the Engine class would have the Message System built in and so the Systems would need access to the Engine to be able to post messages. Any advice on this?
Check out my new blog: http://beefmachinegames.wordpress.com
Quote:Original post by Wizecoder
Quote:That is not a good justification for a Singleton. As I said, unless *every* class in your code needs access to the Engine, then global visibility is a bad thing™ (especially if you plan to have multi-threading).

But a bigger question is why most of the systems would need access to the Engine class? That sounds like it may be an issue with your design.


I guess i am just not totally sure how to implement the message system. So i was thinking that the Engine class would have the Message System built in and so the Systems would need access to the Engine to be able to post messages. Any advice on this?


What if the Engine had a messaging system, and when the engine created any of the sub-systems that requires messaging registered to the messenger (so the messenger has a pointer to the sub-system, and the sub-system has a pointer to the messenger). Now each sub-system that requires messaging already have access to the messenger.

I have used a similar method in the past and it tends to work well.

However I have yet to find a fast method of storing any type of message data while preserving simple code while dealing with messages. In the past I have done a Message base class an static_cast to the inherited Message class when receiving the message. This was a little messy and I'm not certain if it was any faster than using boost::any.
Quote:Original post by c_olin
However I have yet to find a fast method of storing any type of message data while preserving simple code while dealing with messages. In the past I have done a Message base class an static_cast to the inherited Message class when receiving the message. This was a little messy and I'm not certain if it was any faster than using boost::any.
This is one of the primary reasons I advise against fully de-coupling the various sub-systems. There is no real reason to accept the overhead of message passing for Physics -> Rendering, for instance, because the position data that must be transfered is always needed.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement