• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Sneftel

Outboard component-based entity system architecture

106 posts in this topic

Quote:
Original post by dmatter
Quote:
Original post by Tesshu
In my system I handle these problems at construction time. All components are added to the object then coms can do discovery when onConstruct() is called on the object. For example, I might have a ComCamera1st that follows the head of the ComSkinMesh3d, if ComSkinMesh3d isn't found then it looks for a ComPhysics and if that isn't found it looks for a ComStaticFrame etc... I really can't see how else to do this sort of thing. Coms that do anything non-trivial pretty much have to talk to other coms.

Perhaps that behaviour belongs elsewhere, such as the scene-graph, rather than the component system. You would have a camera node and attach to it an entity.


I don't see that as much of a solution since you still need to follow the head position.
0

Share this post


Link to post
Share on other sites
Cool, I've always used a component system for game entities. I figured I wasn't the only one. I just treat game entities like I would my GUI. I create the basic components and the basic events. When an event affects a top level component (usually a container) it passes the events down to the components that are registered to them. Along with this components register themselves to be updated and are able to run event easily.

My event system is rather different in that I use a packet. Event ID followed by parameters serialized. So when an event gets activated it just passes the packet to the event manager which uses a FSM to break apart the packets from front to end.

It's much easier to the think of a tank as a an object that once the player gets in just runs the "get in" event and registers events to the keys and mouse. Very flexible at least.

Not sure how you guys handle the child components. But I give put them in an associative array which allows them to be accessed via their names. Plane2.GetComponent["weapon1"].GetProperty["ammo"]. Get's complex I guess, but for some reason I don't really see any speed decreases so far.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by Tesshu
Quote:
Original post by dmatter
Quote:
Original post by Tesshu
In my system I handle these problems at construction time. All components are added to the object then coms can do discovery when onConstruct() is called on the object. For example, I might have a ComCamera1st that follows the head of the ComSkinMesh3d, if ComSkinMesh3d isn't found then it looks for a ComPhysics and if that isn't found it looks for a ComStaticFrame etc... I really can't see how else to do this sort of thing. Coms that do anything non-trivial pretty much have to talk to other coms.

Perhaps that behaviour belongs elsewhere, such as the scene-graph, rather than the component system. You would have a camera node and attach to it an entity.


I don't see that as much of a solution since you still need to follow the head position.


Well it depends on exactly what you need, but a simple solution might be:
ROOT
|
\---Group Transform Node
|
\---Camera
|
\---SkinnedMesh

The camera is set up to hover about 4 meters above ground and to look-at the point where the mesh's head is known to be. If the transform node changes then the camera and the mesh both move together thus the camera follows the players head.

IMO, a camera isn't really a good candidate for the component system.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
I'm still not too keen about the PhysicsComponent knowing about the AnimationComponent. IMO in the ideal component based system no component would rely on another.
You said that the PhysicsComponent feeds blending data to the AnimationComponent, is that were you stop the dependency chain?
A theoretical worst case scenario could be:
CollisionComponent -> PhysicsComponent -> AnimationComponent -> ScriptComponent -> UserInputComponent -> entity.setPosition(x, y, z);
That seems rather contrived. The only time a component depends on a different component is when it requires that component's services. With that said, relationship chains like this are in the realm of bad OOP design in general, not specific to this architecture. Deciding that no component should depend on any other component because it makes chains like this possible would be throwing the baby out with the bathwater.

Quote:
If you wanted an entity without a ScriptComponent for example, then how does the AnimationComponent detect this so that it can feed its data into the UserInputComponent instead?
I'm not sure what you're asking here... though I also have no idea what AnimationComponent would have to say to UserInputComponent.

Quote:
Alternatively you could have each component interact with a common block of state data - The entity itself is a good candidate for this, and infact you seem to imply you do something similar with positional data.
Yes, this is the system as it stands. The only time components interact with other components is to carry out a specific action.

I think you have the wrong idea about how common component-component relationships are in my design. The physics/animation thing is literally the only place it happens. Component->outside subsystem relationships are much more common.

Quote:
Quote:
Presumably there is still a factory of some description for informing (or firing off the adequate events to) each relevant subsystem that an entity requires a representitive for?
Sort of. That happens when the entity is added to the World, not when it is created; so the creation of Components is separated from the creation of Entities. The World contains an event for Entity adding, which each subsystem hooks to.

If subsystems just respond to an EntityAdded event then won't each entity will end up with every type of component whether it wanted it or not?[/quote]
The entity certainly doesn't decide whether it gets these components or not. It's not responsible for them. The subsystem can choose to create a component or to ignore the addition event completely, based on its appraisal of whether that particular entity is interesting to it or not.

Quote:
Just to throw in a thought, depending on the type of bookkeeping you're referring to, which makes the most sense: An is-a relationship via inheritance or a uses-a relationship via composition/aggregation.
It's a very good point, and in a more civilized language composition would clearly be the way to go. In C++, however, the lack of lexically scoped inner classes make this sort of thing extremely annoying to do without direct inheritance.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
The only time a component depends on a different component is when it requires that component's services.
Quote:
I'm not sure what you're asking here... though I also have no idea what AnimationComponent would have to say to UserInputComponent.
Quote:
I think you have the wrong idea about how common component-component relationships are in my design. The physics/animation thing is literally the only place it happens. Component->outside subsystem relationships are much more common.

Yes, I hadn't realised this was the only occurance.

My understanding had been that the PhysicsComponent produces data affecting, for example, the entity's position; the AnimationComponent also has data affecting the position, thus to get the final net-position the PhysicsComponent passes its data directly to the AnimationComponent which then also has the responsibility of calculating the overal net-position.
I was only taking that to one (albeit contrived) situation where any component which contributes to the net-position needed to also be dependant on other components, which kind of defeats their purpose.

However as this is apparently a minority occurance then you wouldn't overly benefit from separating them, and it's hardly a big problem [smile].

Quote:
Quote:
If subsystems just respond to an EntityAdded event then won't each entity will end up with every type of component whether it wanted it or not?

The entity certainly doesn't decide whether it gets these components or not. It's not responsible for them. The subsystem can choose to create a component or to ignore the addition event completely, based on its appraisal of whether that particular entity is interesting to it or not.

I was a bit misleading there, I didn't mean to imply that the entities choose which components they're comprised of. You did give the answer I wanted though; that there is some mechanism to control which subsystems will respond to a new-entity event.

Quote:
Quote:
Just to throw in a thought, depending on the type of bookkeeping you're referring to, which makes the most sense: An is-a relationship via inheritance or a uses-a relationship via composition/aggregation.
It's a very good point, and in a more civilized language composition would clearly be the way to go. In C++, however, the lack of lexically scoped inner classes make this sort of thing extremely annoying to do without direct inheritance.
[grin]
0

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Quote:
Original post by Tesshu
Quote:
Original post by dmatter
Quote:
Original post by Tesshu
In my system I handle these problems at construction time. All components are added to the object then coms can do discovery when onConstruct() is called on the object. For example, I might have a ComCamera1st that follows the head of the ComSkinMesh3d, if ComSkinMesh3d isn't found then it looks for a ComPhysics and if that isn't found it looks for a ComStaticFrame etc... I really can't see how else to do this sort of thing. Coms that do anything non-trivial pretty much have to talk to other coms.

Perhaps that behaviour belongs elsewhere, such as the scene-graph, rather than the component system. You would have a camera node and attach to it an entity.


I don't see that as much of a solution since you still need to follow the head position.


Well it depends on exactly what you need, but a simple solution might be:
ROOT
|
\---Group Transform Node
|
\---Camera
|
\---SkinnedMesh

The camera is set up to hover about 4 meters above ground and to look-at the point where the mesh's head is known to be. If the transform node changes then the camera and the mesh both move together thus the camera follows the players head.

IMO, a camera isn't really a good candidate for the component system.


I guess this is a perfect example of how it's not always easy to determine what should be in the com system or not :)

I have a Sim_ComFollowBone that, well follows a bone on a skinned model. So I can use this com to put a weapon in a hand, make a halo appear over a head or make a camera follow a bone. Keep in mind that some of my coms, such as Sim_ComCamera, are really wrappers for more lower level systems. I really can't see why you wouldn't want it to be com. One of the features of the system is sharing code. Using this method I can create many different types of objects that can be used as a camera.


0

Share this post


Link to post
Share on other sites
Quote:
Original post by Tesshu
I guess this is a perfect example of how it's not always easy to determine what should be in the com system or not :)

I have a Sim_ComFollowBone that, well follows a bone on a skinned model. So I can use this com to put a weapon in a hand, make a halo appear over a head or make a camera follow a bone. Keep in mind that some of my coms, such as Sim_ComCamera, are really wrappers for more lower level systems. I really can't see why you wouldn't want it to be com. One of the features of the system is sharing code. Using this method I can create many different types of objects that can be used as a camera.


It is certainly possible to have such things in either the component system or the scene-graph system and I'm sure there are pros and cons to both.

The way I tackle it is to have BoneSockets in the scenegraph that reference a specific bone in a skeleton so that other scene-graph entities can be attached to it:

ROOT
|
\---Group Transform Node
|
\---Camera
|
\---SkinnedMesh
|
\---RHandBoneSocket
| |
| \---SkinnedMesh (Weapon)
| |
| \---ParticleSystem
|
\---LAnkleBoneSocket
|
\---SkinnedMesh (Annoying clingy person that won't let go)


It's been on my todo list for some time to ponder whether it's possible to combine the scene-graph and component system together into a single concept, clearly there is cross-over between them. Failing that, I'd atleast like to change the paradigm of my current scene-graph, those BoneSockets were just an ad-hoc means to an end, I'd like to see a more elegant solution in my next code iteration.
0

Share this post


Link to post
Share on other sites
I realize this was said a while ago:
Quote:
Original post by Sneftel
One limitation of the design is that components are limited in the amount of state they can hold. Since they persist only when the Entity is in the World, they can't be seeded with any state as part of the creation process. Any data that the Component starts out with has to come from the Entity's preexisting state.

Not sure what you mean there. Could you explain that?

I am really curious how you guys do your event systems. I go for a soft coded method that's very flexible at run-time (to the point scripts could be changed and loaded in at run-time to add events). I mean my event system revolves around simple input to output. Every form of input has a way to be linked to an event to produce any output.

A good example is that having a packet allows you to produce extremely dynamic effects. Like clicking on an object can run a packet ID that spawns a GUI window with choices and fills in event ID's and information dynamically. Good for interacting with the world.

I figure you guys do something similar would I be correct in saying that?

A big part is passing down the events to the registered componenents that have focus over the input. (Again thinking of the game entities like a GUI is a perfect way to look at it).
0

Share this post


Link to post
Share on other sites
Quote:
Original post by Sirisian
I realize this was said a while ago:
Quote:
Original post by Sneftel
One limitation of the design is that components are limited in the amount of state they can hold. Since they persist only when the Entity is in the World, they can't be seeded with any state as part of the creation process. Any data that the Component starts out with has to come from the Entity's preexisting state.

Not sure what you mean there. Could you explain that?

Consider that a few months down the line, I decide that every Entity should have a WeightComponent, which tracks the entity's weight, increasing as it overeats and decreasing as it diets and exercises regularly. Suppose that previous to this, the Entity had no concept of weight or mass at all. The difficulty I would run into (assuming that I stored the weight in the WeightComponent) is that since Entity has no member called "weight", I would have no way of knowing what its initial weight should be. Likewise, if for some reason I temporarily removed a particular Entity from the simulation and then added it back in, the weight would no longer be the same; the original WeightComponent would have been destroyed and a new one created. What this all means is that outboard components aren't useful for adding state, only for adding behavior.
0

Share this post


Link to post
Share on other sites
The way I have mine set up is that if I wanted I can use any types in the properties. I plan to revise my system more so that it will allow most properties, but under the circumstance that a component needs another property then it could be added dynamically to the object. Albeit the access of that property would have a little more overhead, but not enough that it wouldn't be useful.

I'd end up accessing it in my events. So like the onload event I might have to go through each object that needs it and edit it so that the new variable is created and able to be accessed (via the map of properties).

For a large upgrade where it would require all entities to have the update then I'd just rebuild the engine with it.

Currently I just list out each component and event such to allow for the dynamic creation of "any" object. Breaking everything up into the simplest ideas is the hard part. I mean the actual actions aren't very important and are pretty much "scripted" via event packets. It's the variables and rendering/boundary/data type info that tends to change. I work in 2D, so the implementation is probably different for 3D.

Like say I was making a tank. You'd break it down into the base, the two treads, 4 particle emitters for the front and back treads, the turret with the barrel, and the particle emitter at the end of the barrel.

So you have 5 particle emitter components, 2 animations (treads, the barrel is a translation based on the firerate, but is just a texture), 1 vehicle component(base) and a rotating component (turret) and finally a texture outside of the tank where the player pushes g to get into the tank so 1 texture. So like 11 components. Not bad, but the interactivity between them is high. Like textures are basically 1 frame animations with a rotation point and beginning translation. The vehicle base has tons of event handlers that can register keybinded input to events as said before. The animations register with the main container since they may only update every 50-200 ms and such. Events tell the tread animations whether or not to play and the list goes on.

Also, for clarification when I said, "multiGameEntity" I mean a container. It's the root of the object to which all components register events. When events are handled they are passed to it for a quick cull of events so components don't worry about what they don't need.

Due to my insane FSM system though the basic premise is again a flexible dynamic entity creation system. (I should probably make an editor...).

Still wondering how you guys handle events for your system. Maybe there's a more flexible way than mine. (I am hardcoding after all).
0

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel

Quote:
Quote:
Quote:
Presumably there is still a factory of some description for informing (or firing off the adequate events to) each relevant subsystem that an entity requires a representitive for?
Sort of. That happens when the entity is added to the World, not when it is created; so the creation of Components is separated from the creation of Entities. The World contains an event for Entity adding, which each subsystem hooks to.

If subsystems just respond to an EntityAdded event then won't each entity will end up with every type of component whether it wanted it or not?

The entity certainly doesn't decide whether it gets these components or not. It's not responsible for them. The subsystem can choose to create a component or to ignore the addition event completely, based on its appraisal of whether that particular entity is interesting to it or not.


Is that done with a dynamic_cast<> within the given subsysten? How would the subsystem determine which entity needs what?
0

Share this post


Link to post
Share on other sites
Quote:
Original post by dingojohn
Is that done with a dynamic_cast<> within the given subsysten? How would the subsystem determine which entity needs what?

What would you do with dynamic_cast?

A data-driven approach might see each subsystem with a string of meta-tags that it is interested in. When an entity is added to the world it too is given a string of meta-tags by the user.
Upon receiving an EntityAdded event, the subsystem queries the entity for it's meta-tags and searches it to see whether it's interested creating a representitive for this entity.

The meta-tags can be explicit: std::string("Physical, Spatial, Visual");
They can be implicit: std::string("Antelope");
Or a combination of both: std::string("Vehicle, AI"); -or- std::string("Vechicle, UserControl")
0

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Quote:
Original post by dingojohn
Is that done with a dynamic_cast<> within the given subsysten? How would the subsystem determine which entity needs what?

What would you do with dynamic_cast?

A data-driven approach might see each subsystem with a string of meta-tags that it is interested in. When an entity is added to the world it too is given a string of meta-tags by the user.
Upon receiving an EntityAdded event, the subsystem queries the entity for it's meta-tags and searches it to see whether it's interested creating a representitive for this entity.

The meta-tags can be explicit: std::string("Physical, Spatial, Visual");
They can be implicit: std::string("Antelope");
Or a combination of both: std::string("Vehicle, AI"); -or- std::string("Vechicle, UserControl")


I cannot believe I did not think of that. Thanks.
0

Share this post


Link to post
Share on other sites
Actually, dingo's hit on one of the other aspects of my Entity system: I am using inheritance to some degree. That is, there is a small but significant inheritance tree hanging off of Entity, and one of the main criteria subsystems use to decide whether they care about an Entity is that Entity's dynamic type (determined via dynamic_cast). This allows me to add extra properties to certain types of objects, at the cost of some of the flexibility that the standard component-based system allows.
0

Share this post


Link to post
Share on other sites
It sounds like I'm doing something that is somewhat different.

In data file for each different entity type that can be created I have a GameObjectType definition that contains a list of components and for each one a bunch of things that set variables in the component. A small example:

Monster
{
Physical
{
size = 4
}
Moving
{
speed = 10
}
}

Any variables you don't set get default values.
You can also derive from one of these classes

FastMonster : Monster
{
Moving { speed = 30 }
}


For each component I have something deriving from ComponentStatic and Component.

At load time when you parse these files for each type we create a list of ComponentStatic objects that belong to that type. A component static has functions for accepting variable definitions and a list of components that it requires services from. Moving for example requires Physical to be present (You need to be able to update the position of the object in order to move it). If you list a component and you don't include its dependency then the Type will fail to load and an error gets reported.

For each dependency you store a ComponentRef which is really just the index of the component for easy look up later.

A GameObjectType also remembers the sizeof for the non-static components corresponding to the static ones it contains and the sum of all of these.

So now each type of object we want has a ComponentStatic that contains dependancy indices and all of the type specific data that each component needs.

When we instantiate a GameObjectType as a GameObject we allocate all of the memory for all of the non static components in one call and use placement new to call of of the constructors for each game object. Each non static component has a reference to its static cousin so that it can easily access all of the object type specific data it needs.

The GameObject has a function that takes a ComponentRef and returns a pointer to the game object that you want. It does this by using a lookup table in the GameObjectType that contains the offsets of each Component for this type.

This may sound a little complex but it means that creating new objects is now pretty fast. You allocate all of the components in one go and this has the additional benefit that all of the components are located next to each other in memory to improve caching performance.

We also have a quick way of getting references to other components. All of the dependencies the component needs are stored as ComponentRef's so getting a pointer is just a constant time array lookup.

There is one other thing needed here though, and that is a way to publish messages to components that require info back from you. For example, you need a way of notifying any components that need to the fact that the object has stopped moving for example (required for animation).

I considered some kind of callback system and implemented some of it but it was fairly complex. So I settled with a much simpler solution. Each component has a ReceiveMessage virtual function and when a ComponentStatic is instantiated all of the components that it requires get an entry added to say that it is interested in messages from those components.

When a component wants to send a message it calls a function that will send messages to all of the other components that registered as listeners. So our animation controller lists the moving component as a dependancy and now it gets notified of any events that it needs to.

There are a few other issues I have not discussed here. The first one that is not yet implemented fully the ability to be able to load GameObjectTypes faster using a binary game object type format that contains a blob of binary data that each component can memcpy directly into a little inline struct during loading. You can compile all of the game object type files down into this format, number all of the components and then very quickly load a game object type. This is for distribution as it requires a locking down of the available components and you can't really edit the type files after that.

The other issue is network serialisation. I have a system that allows each component to be serialised and put into a network stream and come out whole on the other end, and a "dirty component" thing that allows components to say that they have changed and then only components that require changes to be serialised get sent (with a bitfield at the start to say which components the client needs to load.

That mechanism has a whole other list of strange things to do with Components being marked as Client, Server or Shared. Only Shared components get state serialisation and Client / Server components only actually exist on the sides that they need to.

All of the Shared components come first in the physical object to preserve that the component indices are always the same on both the client and server. (We don't send the indices in network traffic but its easier to get your head around sometimes)

I'm not totally happy with the networking part of the system honestly. It can be hard to say sometimes what should be serialised as part of the object state and what should be sent as a standard message packet. I've been considering some kind of Object -> Object network message thing but haven't implemented it yet. That would be so that the server can notify the client of events without actually sending it as object state.

Anyway, this ended up being a pretty long post. Any suggestions and comments welcome.

0

Share this post


Link to post
Share on other sites
My design is based somewhat on the gems article, and the links posted earlier. Main design principle is flexible and readable code. My terminology is a little different but that shouldn't be a problem(3 says that it belongs in a 3d world, entity=>object). This is pseudo C++.

An object is built from components:
class Object3 {
map<string, shared_ptr<Component3>> mComponents;
Component3* getComponent(string iName);
};

class Component3 {
virtual MessageResult handleMessage(Message& iMessage);
Object3* mOwner;
};

class Message {
MessageType getMessageType() const;
private:
MessageType mType;
};

class UpdateMessage : Message {
UpdateMessage(real iTime) : Message(MT_UPDATE), time(iTime);
const real time;
};




I tell the objects to render and/or update with messages.

The DisplayComponent3 wants to know where to display the mesh, and the current skeleton pose(among other things). This is done with some ugly, but flexible, code somewhat similar to dataports:

class DataBase {
};

template<class T>
class Data : DataBase {
T t;
T& getReference() { return t; }
// some virtual void setValue(GenericTypeSuchAsStringOrXmlNode)=0;
};

class DataContainer {
map<string, shared_ptr<DataBase> > mData;
DataBase& getData(string iName);
};

shared_ptr<DataBase> BuildData(string& iType); // probably some factory

template<class T>
T& GetDataBase(DataContainer& iContainer, string iName, string iType) {
if( !iContainer.hasData(iName) ) iContainer.addData( iName, BuildData(iType) );
return ((Data<T>& )iContainer.getData(iName)).getReference();
}

// vec3 is a vector in 3d
vec3& GetDataVec3(DataContainer& iContainer, string iName) {
return GetDataBase<vec3>(iContainer, iName, "vec3");
}

// usage
class MyComponent3 : Component3 {
MyComponent3(Object3& iOwner) : Component3(iOwner), mLocation(GetDataVec3(getDataConatiner(), "location")) {}
vec3& mLocation;
};




Since it's a lazy eval Objects only store what the components exchange, so if the object doesn't need the location, it doesn't have it. Since the varaible source is string-based theese can be read from a cfg and with this principle it was simple to apply the RandomMovement (pretty useless but fun), and the WithinRect component to the 2d cursor(location based), from the background-animation(uv based).

I'm thinking of adding some sort of layer system, so I can add components that (temporarily) remove others from some/all messages. Such components may be a Tranqualized, or ResurectAfterSomeTime component.

I'm unsure why subsystems are hard to access with components. If some component want access to some subsystem all it does is something like this:
class SomeComponent3 : Component3 {
SomeComponent3(Object3& iOwner) : Component3(iOwner), mSomeSystem( (dynamic_cast<SomeSystem&>(iOwner.getWorld()
.getSystem("SomeSystem"))) ) {
}
SomeSystem& mSomeSystem;
};
0

Share this post


Link to post
Share on other sites
Quote:
Original post by sirGustav
I'm unsure why subsystems are hard to access with components. If some component want access to some subsystem all it does is something like this:
class SomeComponent3 : Component3 {
SomeComponent3(Object3& iOwner) : Component3(iOwner), mSomeSystem( (dynamic_cast<SomeSystem&>(iOwner.getWorld()
.getSystem("SomeSystem"))) ) {
}
SomeSystem& mSomeSystem;
};

Or perhaps iOwner.getOwner().getWorld().getGame().getSomeSystem().getSomeSubSystem()? And even then, only if each level of the tree knows its parent. That won't always be the case; in fact, in a good design it should rarely be the case.
0

Share this post


Link to post
Share on other sites
It should probably be worth mentioning that I got two different systems, world and game. World is based in the world file(the pathfinding system as an example). Game is more globally based, as in file, state and window systems.

So we get the pathfinding like this:
mPathfinding( (dynamic_cast<PathfindingSystem&>(
iOwner.getWorld().getSystem("Pathfinding") )))

* so iOwner is the object that hold the datas, this component(and others) and most important
* the world that it belong to. The world can be render()ed tick()ed and frame()d (frame to frame update) and receives events. It also holds the game systems.
* at last you request the system you want. You might prefer .getPathfindingSystem(), I kinda like dynamic_cast<PathfindingSystem&>(.getSystem("Pathfinding"))

besides...

.. why do you need to access some system through another, or need components that use a "low-level" system?
Let's say we have a Render component. It interfaces with the Display system. The DisplaySystem gets some mesh and displays it according to some properties. The mesh is locally created(as in Mesh myMesh;) and loaded with the help of the 3d File System(as in mFileSystem.loadMesh(&myMesh);). The DisplaySystem is dependent on the Window System and the 3d File System is dependent on the File System, but none of the components should care.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by sirGustav
So we get the pathfinding like this:
mPathfinding( (dynamic_cast<PathfindingSystem&>(
iOwner.getWorld().getSystem("Pathfinding") )))

* so iOwner is the object that hold the datas, this component(and others) and most important
* the world that it belong to. The world can be render()ed tick()ed and frame()d (frame to frame update) and receives events. It also holds the game systems.
* at last you request the system you want. You might prefer .getPathfindingSystem(), I kinda like dynamic_cast<PathfindingSystem&>(.getSystem("Pathfinding"))

That means that the component depends on the owner, the world, and the subsystem. It also means that the world depends on the pathfinding system. It's a reasonable design, but I'm going for something a little more structured and compartmentalized. In particular, in my experience, the above design leads to an explosion in code length.

Quote:
.. why do you need to access some system through another, or need components that use a "low-level" system?

I've given examples of that above.
0

Share this post


Link to post
Share on other sites
Sneftel,
So in your system, you have each subsystem store a it's own component[s] that get updated as the subsystem see fit. Each component is responsible for one entity and stores the data it requires for manipulating that entity within itself? Or do you some how store the data for each component with in the entity which is open for all other component to alter if they wish?

I have been attempting to wrap my head around a component system, I was going to attempt to use boost::any to allow an extensible system which allowed any data to be stored in a map on the entity, but I wasn't sure what the limitations on boost::any were on what types of data it could actually hold(can it hold class/objects)?

Thanks for all your insightful information.
0

Share this post


Link to post
Share on other sites
Interesting, we have a lot of people using component based systems with a lot of differences. The downsides to components that Sneftel points out that it is a problem that components have trouble communicating with different (intra) components within the same entity (inter) or other entities.

There is another problem with the component based model that nobody has mentioned yet: for components that REQUIRE other components, you have to constantly check to see if you have the component...and what do you do if you dont find the component...do nothing? Also there is such a thing as over-generalizing...writing components that will not produce errors when used in combinations where components somehow conflict or dont work depending on what other components are in the entity

Possible solutions to inter-communication:

vtchill:
Quote:
For my design each component knows its entity parent and each entity has a HasComponent type function for querying on a specific component type which returns either a shared pointer to the component or an empty (NULL) shared pointer. The entities store their components in a map or hash map type structure for quick lookup. To get component specific information I am forced to cast the returned pointer to the type I requested


Pros: relatively fast lookup of components
Problems: requires dynamic casting, indirect lookup of components albeit constant time

Paladine:
Quote:
Essentially an entity is a container for components whose responsibility is to route events between components. The idea is that a component is a chunk of logic with a set of output events and a series of input events to which it responds.
Components then don't care explicitly about other components, they just use the more generic events which other components create and pass across the Entity bus. You could, therefore, throw any component into any entity and gain some/all of it's functionality (depending on what other components are also present).


Pros: modular
Problems: inefficient, requires a lot of virtual "bus snooping"

Sirisian:
Quote:
My event system is rather different in that I use a packet. Event ID followed by parameters serialized. So when an event gets activated it just passes the packet to the event manager which uses a FSM to break apart the packets from front to end.

It's much easier to the think of a tank as a an object that once the player gets in just runs the "get in" event and registers events to the keys and mouse. Very flexible at least.

Not sure how you guys handle the child components. But I give put them in an associative array which allows them to be accessed via their names. Plane2.GetComponent["weapon1"].GetProperty["ammo"]. Get's complex I guess, but for some reason I don't really see any speed decreases so far.


Cons: breaks rules of encapsulation, complicated, and lots of opportunities for failure if "weapon1" does not exist for example...if you depend on it being there, maybe you should not use an indirect referencing scheme?

--------

My view is that a hybrid scheme is best. Don't just make a single entity class that is completely generic. Define your entities based on the types of components they need and how they communicate with those components. This way, you know exactly what components EntityTypeA has. Put the logic for communicating between components into EntityTypeA, but put all the funcionality of the components into specific pointers held by EntityTypeA, so that you dont need complicated busses...hash maps...etc...you get the performance of a non-component design, but most of the modularity of a component based design. If the component cant really be separated, then youre probably not really adding any modularity by trying to write it so that it will work when it IS separated, since it wont really work then anyway!

As for "sub-components"...I dont think they should exist. Integrate into the component.

As for "inter-entity communication", this problem is also solved by the hybrid scheme.
0

Share this post


Link to post
Share on other sites
In regard to the component to component interaction debate...

So lets say you have a Entity that contains a Physical and Visual component. The Physical component needs to interact with a Visual component (ie whenever the physics subsystem updates the position/transform, the Physical component sends a update message to the Visual component). IMO for performance reasons, this communication should be direct (no 3rd party), so the Physical component should have a direct ptr to the Visual component.

The problem is, what happens if you want to use that Physical component in a Entity which has no Visual component (for example a 'invisible' cube that effects the physics simulation). It seems there are two very elegant options...

1.) Have the Physics component check for a null Visual pointer before trying to use it (since during Entity construction one wasnt assigned).

or

2.) Make TWO Physical components. Physical and PhysicalWithVisual. Modify the code accordingly for each.

Sound good or did I miss something?
0

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
So lets say you have a Entity that contains a Physical and Visual component. The Physical component needs to interact with a Visual component (ie whenever the physics subsystem updates the position/transform, the Physical component sends a update message to the Visual component).

The fact that Physical needs to interact with Visual does not imply that Physical needs to be coded to be aware of Visual's existence. This is the basis of signal/slot systems, and of the Observer pattern.
0

Share this post


Link to post
Share on other sites
Ah touche'

I wasnt too familiar with the observer pattern but youre right. A good article can be found here...

http://www.codeproject.com/cpp/observer.asp

So instead...

The Position Component would be a Subject, and as Visual or Physical Components are attached, they register to the Position as Observers. Then when Physical changes the Position, Visual will be notified indirectly.

And like youre already doing, I think its smart to just toss Position into the entity itself (since 99% of entities will have a position). No need for it to be a Component.

*edit

So im curious to hear more about how you implemented this. Are the components/observers polling their subjects? How do you control when this polling takes place? Or are you just having subjects notify all registered observers on a change?

[Edited by - ZealousEngine on October 24, 2007 5:37:29 PM]
0

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
Ah touche'

I wasnt too familiar with the observer pattern but youre right. A good article can be found here...

http://www.codeproject.com/cpp/observer.asp

So instead...

The Position Component would be a Subject, and as Visual or Physical Components are attached, they register to the Position as Observers. Then when Physical changes the Position, Visual will be notified indirectly.

And like youre already doing, I think its smart to just toss Position into the entity itself (since 99% of entities will have a position). No need for it to be a Component.

*edit

So im curious to hear more about how you implemented this. Are the components/observers polling their subjects? How do you control when this polling takes place? Or are you just having subjects notify all registered observers on a change?


Subjects notify all registered observers on the change that is the beauty of the observer pattern. It would be a pain if observers had to poll. Usually a subject has register and unregister functions along with a Notify function which just loops through registered observers and calls their action function which can either be a polymorphic function or a function pointer style callback.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0