Basic Component Based Entity

Started by
67 comments, last by crancran 12 years, 4 months ago
Let us assume we have 3 types of components: spatial, mesh, and render. The spatial holds my position, the mesh contains a list or reference to a mesh for the entity, and the render is where the actual rendered content is maintained in the scene graph via a render scene node.

I assume that my spatial subsystem would create a scene node at the specified position in the spatial components. As the component's position changes, the spatial update() would reflect those changes to the referenced scene node. The mesh component would load whatever mesh information from the resource system and prepare it for the rendering phase. The render component would request a reference to both of these components (mesh/spatial) during initialization and then during the render system's update() loop, the we'd check if a scene node for the mesh has been added as a child to the scene node referenced by the spatial component. If so and the mesh has changed, the render component would update the mesh on the render component's child scene node. If a child scene node hasn't been created, the render system creates one off the spatial component's node, and then applies the specified mesh. Am I on track?
Advertisement
I'm using MinGW so that might be my problem because I made the changed you've said and added a class that inherits the handleEvent function but no go..

I'm using MinGW so that might be my problem because I made the changed you've said and added a class that inherits the handleEvent function but no go..

Show me what that inherited class looks like.
#ifndef CSTATEMACHINE_H
#define CSTATEMACHINE_H
#include "IEventHandler.h"

#include "CState.h"
#include "CMenuState.h"
#include "CGameState.h"


class CStateMachine: public IEventHandler
{
public:
CStateMachine();
virtual ~CStateMachine();

void switchState();
void init();
void update();
void draw();

void handleEvent(const Event* e);

CState* state;
protected:
private:

};

#endif // CSTATEMACHINE_H


#include "CStateMachine.h"


CStateMachine::CStateMachine()
{
}

CStateMachine::~CStateMachine()
{
//dtor
}

void CStateMachine::switchState()
{

}

void CStateMachine::init()
{
state = new CMenuState();
state->add();
}

void CStateMachine::update()
{
if (state!=NULL)
{
state->update();
}
}

void CStateMachine::draw()
{
if (state!=NULL)
{
state->draw();
}
}

void CStateMachine::handleEvent(const Event* e)
{

}




Hot pancakes and syrup I got it. I added #include "IEventHandler.h" to CEventDispatcher.cpp and it compiled.

[quote name='smr' timestamp='1320274090' post='4879912']
Just a word of caution: ...


Isn't this where being able to build templates in the game editor would play a vital role?
[/quote]

Yes, templates would make things easier for the designer, but what about the developer? Let's take your example of separating vital stats out into each their own subsystem and component type: HealthComponent, WeaponComponent, ArmorComponent, StrengthComponent, DexComponent, AttackComponent, etc. What would combat look like for an entity like this?

I attempted to provide a code sample, but it was so complicated that I didn't think I would be able to accomplish it without actually opening up my IDE and formally coding something. I can say it would involve a lot of asking systems if the two entities involved had certain stat components, passing messages around to receive damage, cooperation between stat components to try to figure out how much damage should be taken, whether a hit is even made, etc. It just seems like adding complexity just because you CAN and because somewhere down the line someone told you that you SHOULD loosely couple EVERYTHING. Loose coupling is great but loose coupling for the sake of loose coupling is just another way to shoot yourself in the foot.
[color="#1C2837"]I attempted to provide a code sample, but it was so complicated that I didn't think I would be able to accomplish it without actually opening up my IDE and formally coding something. I can say it would involve a lot of asking systems if the two entities involved had certain stat components, passing messages around to receive damage, cooperation between stat components to try to figure out how much damage should be taken, whether a hit is even made, etc. It just seems like adding complexity just because you CAN and because somewhere down the line someone told you that you SHOULD loosely couple EVERYTHING. Loose coupling is great but loose coupling for the sake of loose coupling is just another way to shoot yourself in the foot. [/quote]

I was thinking the same thing myself. To me a single vital's component would be best. While my game isn't an RPG neither does it have a complex stats system but even if it was an RPG don't 90% of entities that might interact in away that involves vitals all have basically the same set of stats, given different values of course but that should be taken care of with the factory that put the entity together in the first place potentially with a data table or an external Init script (What I plan on using)

My whole purpose of using this system is to get away from hardcoding my entities so I don't have recompile when I want to add a new type making it easier.

Like when I parse my level and encounter an AnimatedMeshSceneNode (The mesh type I'm going to make all entities out of) I want it to extracted the name from the node (Yay Irrlicht!) and use that to build the entity by loading the external scripts with the same name. I also want to be able to just give the factory a name to manually create an entity if I need too.


[color="#1C2837"]I assume that my spatial subsystem would create a scene node at the specified position in the spatial components. As the component's position changes, the spatial update() would reflect those changes to the referenced scene node. The mesh component would load whatever mesh information from the resource system and prepare it for the rendering phase. The render component would request a reference to both of these components (mesh/spatial) during initialization and then during the render system's update() loop, the we'd check if a scene node for the mesh has been added as a child to the scene node referenced by the spatial component. If so and the mesh has changed, the render component would update the mesh on the render component's child scene node. If a child scene node hasn't been created, the render system creates one off the spatial component's node, and then applies the specified mesh. Am I on track? [/quote]
[color="#1C2837"]

To me it seems too broken up. If I may ask why not just use the entity's scene node directly as a way to store and access the positional and rotational data? Do everything directly it? Removing the need for a spatialdatabase by just having a subsystem that contains all the entity node components with the given IDs?


I also want to thank everyone who has responded. This has probably been one of the most fun topics I've been in on a forum.
On 11/3/2011 at 7:18 AM, smr said:

separating vital stats out into each their own subsystem and component type: HealthComponent, WeaponComponent, ArmorComponent, StrengthComponent, DexComponent, AttackComponent, etc. What would combat look like for an entity like this?

 

On 11/3/2011 at 9:17 AM, jaeg said:

To me a single vital's component would be best. ...don't 90% of entities that might interact in a way that involves vitals all have basically the same set of stats

If we think about componentized entities as being a data oriented approach, the guiding principal is to separate the entity into chunks of data which will be processed together.

If we envision all those stats being used for the purpose of producing a feature (like combat) through some sort of complex interaction, then we're envisioning processing all the stats together, so they should form a component. Breaking each stat into it's own component is a violation of data oriented design. Well formed components make it relatively easy to write the code, as well as letting that code run more efficiently.

Now if you find that you have various different types of entities which actually only need subsets of those stats, then you'll find it pretty difficult to code those interactions which process all the stats together, because those interactions would make no sense for entities which you've decided don't need those stats. In that case, you've identified some subsets of the stats which should form smaller components.

Rather than thinking of it as data oriented, I like to think of it as feature oriented. Entities have features, or aspects, or abilities, etc., like the ability to be placed in the 3d game world, to be rendered, to animate, to participate in a physics simulation, to collide with other entities, to give and receive damage, etc. Each of these features involve it's own (mostly) unique data, and the code which operates on it. In general, a component should contain the data (specific to a given entity) which a subsystem processes. If it doesn't make sense to create two subsystems, it probably doesn't make sense to create two component types.

One area of stickiness is when multiple features are equally dependent on a common piece of data (e.g., AI, physics, and rendering all depending on entity position). The only two approaches that come to mind for dealing with this are either to factor that data out to a separate component (which breaks data orientation, forcing components to look it up while processing), or to duplicate that data (forcing components to synchronize it, and opening the door to copies being out of sync). At the moment, I tend to lean heavily towards the first approach, especially in the case of entity position, since there is a sub-system which makes sense for dealing with position data only.

Should I make separate classes for the subsystems or could I just have a single subsystem class that has functions that let you decide what events they should receiver for the components they update?
Short answer, they should be different.

Whenever you are coding a particular class/object, you should always refer to two principles.

The first is called Separation of Concerns. This principle is often used when it becomes evident that an object needs to be re-factored into smaller distinct features that should overlap as little as possible. The term concern can be defined as a focus, interest, feature, or behavior depending upon your context. The second is called Single Reponsibility Principle. This principle basically outlines that every object/class should have a single responsibility, and that all its services (methods/functions) should be narrowly aligned with that responsibility.

So if we think back to what we're trying to do with a component-based design, we are trying to isolate and narrowly defined set of functionality or feature/behavior into classes that are as self-contained within reason. This way should we need to change the behavior of a component and its managing subsystem, we can with as little risk or need to decipher additional lines of code that have no relevance to the feature we're trying to enhance or bugfix :).

Those two principles should always be relied upon and you will find it is much easier to make modifications over the life cycle of any programming project. Of course it's my opinion and others mileage may vary in how strongly they feel about those two principles. :).

Short answer, they should be different.

Whenever you are coding a particular class/object, you should always refer to two principles.

The first is called Separation of Concerns. This principle is often used when it becomes evident that an object needs to be re-factored into smaller distinct features that should overlap as little as possible. The term concern can be defined as a focus, interest, feature, or behavior depending upon your context. The second is called Single Reponsibility Principle. This principle basically outlines that every object/class should have a single responsibility, and that all its services (methods/functions) should be narrowly aligned with that responsibility.

So if we think back to what we're trying to do with a component-based design, we are trying to isolate and narrowly defined set of functionality or feature/behavior into classes that are as self-contained within reason. This way should we need to change the behavior of a component and its managing subsystem, we can with as little risk or need to decipher additional lines of code that have no relevance to the feature we're trying to enhance or bugfix :).

Those two principles should always be relied upon and you will find it is much easier to make modifications over the life cycle of any programming project. Of course it's my opinion and others mileage may vary in how strongly they feel about those two principles. :).


Exactly! I think these two principles pretty much define a component.
Does any one know why the inheritance obsession became so widespread that the new term "component based entity" had to be invented?

I personally blame online tutorials. :D

EDIT: I just noticed this might be misread. No offense intended. I'm just wondering why there seem to be so many paradigm shifts in game development.

This topic is closed to new replies.

Advertisement