Outboard component-based entity system architecture

Started by
105 comments, last by qingrui 16 years, 4 months ago
Quote:Original post by vicviper
hmm... don't you think this is going a bit too far? I mean, by now, we already have: entities, components, systems and subsystems, and with that, people is clearly having problems understanding mutual relationships between these different elements. I myself don't know very well in which direction to go, because, so far, many of the solutions presented here would not allow some things I want to do.

Remember, one of the theorical good things about componentized entities was to avoid the traditional, bloated hierarchical entities. And I think we should move in the direction to see how everything fits in a real scenario.

For example: many have said that only allow one instance of a given component type inside a single entity; but, given that a "weapon" would be a component, what if I want an entity to have multiple weapons?

In a game like Quake, I think a player entity could be broken in the next components:

-quake player entity
-spatial component (position, rotation)
-physics (velocities, collision detection) component
-user input component
-AI component
-3rd person character mesh component (mesh id, animation frame)
-3rd person weapon mesh component ( mesh id, character mesh bone)
-1st person character mesh component (mesh id, animation frame)
-1st person weapon mesh component ( mesh id, character mesh bone)
-health component (health value)
-weapon1 component (ammo)
-weapon2 component (ammo)
-weapon3 component (ammo)
-weapon4 component (ammo)
-Shield component (remaining time)
-cloaking device component (remaining time)
-Score component (num of kills, num of deaths, etc)

Somehow, I know I would need all that stuff for a quake like entity, but they're already quite a number of components for a single entity... and we're talking about the ultra simple old quake guy... modern games might need much more than that.

Agree? disagree? how to handle them? what happens if the guy receives a shot? who is notified first? the shield component if enabled? or the health component that looks for the shield component?, or should the mesh render components be aware that there's a "cloaking device" component enabled to render in a different way?

I think this is worth discussing.


Conceptually, I don't think of components as something you'd really want to be adding and removing at runtime. Practically, there tends to be a lot of overhead involved in doing so.

At any rate, there's no clear advantage to having weapons and ammo be components. If I were doing something like Quake I'd probably just have an "Inventory" component which contained weapons, ammo, shields, etc. Maybe another component to keep track of what's currently equipped and proxy onTakeHit and onFire events.

[size=2]
Advertisement
Quote:Original post by vicviper
***snip large post***


Another thing I've noticed is a split between 'engine components' and 'game components'. So the first 4 on your list are engine components (they're directly related to a capability of the game engine). The next 4 should really just be one render component.

The rest however, are game components (i.e. implement game logic/content) and I still haven't figured out what to do with those.

Regarding the component/subsystem thing. I believe that they are 2 sides of the same coin. To me, a component means that the logic would be incorporated into each entity, where as a subsystem indicates there's just 1 instance of it (this also kinda implies that the entities are purely data).

Regards
elFarto
Quote:Original post by vicviper
For example: many have said that only allow one instance of a given component type inside a single entity; but, given that a "weapon" would be a component, what if I want an entity to have multiple weapons?


In that case, you can have a WeaponCollectionComponent that maintains the list of WeaponComponents the player has, along with which WeaponComponent is currently active, etc.
Quote:Original post by vicviper
For example: many have said that only allow one instance of a given component type inside a single entity; but, given that a "weapon" would be a component, what if I want an entity to have multiple weapons?
Then "weapon" shouldn't be a component; "weaponry" should, or (perhaps too abstracted) "inventory".

Quote:
-spatial component (position, rotation)
-physics (velocities, collision detection) component
-user input component

"User input", IMHO, is sort of a strange thing to make into a component; I see it as an outside system sending calls to a particular entity.

Quote:
-3rd person character mesh component (mesh id, animation frame)
-3rd person weapon mesh component ( mesh id, character mesh bone)
-1st person character mesh component (mesh id, animation frame)
-1st person weapon mesh component ( mesh id, character mesh bone)

Blech! More likely, a single "graphics" component.

Quote:
-weapon1 component (ammo)
-weapon2 component (ammo)
-weapon3 component (ammo)
-weapon4 component (ammo)
-Shield component (remaining time)
-cloaking device component (remaining time)

See "weaponry"/"inventory" above.
Quote:
-Score component (num of kills, num of deaths, etc)

Somehow, I know I would need all that stuff for a quake like entity, but they're already quite a number of components for a single entity... and we're talking about the ultra simple old quake guy... modern games might need much more than that.

Your idea for components has much teenier granularity than mine. I don't think that taking all the character's weapons and all his stats and all his meshes and throwing them into a flat list of "components" is a good idea. A "component", to me, is an entity-specific delegate* for accomplishing a particular area of the entity's functionality. Components should have data structures that are as complex as they need to be. The complexity should be maintained within the component.


*I don't mean that in the bound-function-pointer sense of the word.
a weapon is fluff on the side of the engine. the engine shouldnt know about things like multiple instance game items.

The game should be defining an 'item' or usable item class(s) which be kept in an item inventory.

class ItemInventory;// Item base classclass ItemBase{private:    ItemInventory * parent;public:    virtual void Use (void) = 0; // etc etc    const char * Name (void);};// item inventoryclass ItemInventory : PropertyObject{private:    map <string, vector <ItemBase *>> item_categories;    void AddItem (string category, ItemBase * item);};// adds a weapon item and sets it to be the primaryItemInventory inv;Weapon * shotty = new Weapon ("shotgun");inv.AddItem ("weapons", shotty);inv.SetProperty ("prim-weapon", shotty); // from PropertyObject class



Quote:Original post by smitty1276
[ lotsa stuff ]

I like this approach. One thing that I notice about it, though, is that it is basically a reimplementation of OOP within C++, one which supports runtime-composed objects. My thought, therefore, is that the first thing to do is to come up with a good framework for runtime-composed objects in C++, independent of entities and components and whatnot.

More to come, gotta run.
In regards to smitty's post - it seems like a nice simple way to tackle the problem, but aren't you making a pretty big sacrifice: compile time checking? Maybe there is some real magic behind the scenes, but I can see that as being a predominantly runtime system...

My latest iteration of this is to now declare Entity's like this:

	public class Asteroid : Entity	{		public Vector2 InitialVelocity { get; set; }		Controllers.ScreenWrappingController swc = new SpaceGame.Controllers.ScreenWrappingController(new System.Drawing.Size(800, 600));		public Asteroid(World manager) : base(manager)		{			AddComponent(typeof(Components.Damage));			AddComponent(typeof(Components.Geometry));			AddComponent(typeof(Components.MoveableComponent));		}		public override void Initialize()		{			Components.Geometry geometry = RequestComponent<Components.Geometry>();			geometry.CreateQuad(new Rectangle(-1, -1, 1, 1));			Components.MoveableComponent moveable = RequestComponent<Components.MoveableComponent>();			moveable.Velocity = InitialVelocity;		}	}


Then you just create an Asteroid as:
Entities.Asteroid asteroid = new SpaceGame.Entities.Asteroid(this){	Position = position,	Rotation = (float)(randomGenerator.NextDouble() * 2 * Math.PI - Math.PI),	Scale = (float)(randomGenerator.NextDouble() * 50 + 10),	InitialVelocity = velocity};InjectEntity(asteroid);

InjectEntity(Entity) is a method on my World class that simply notifies all component subsystems that an Entity has been added, and they then check the Entities requiredComponents as to whether they should act on the creating an Entity.

The Entity is then initialized, and is able to retrieve it's components as it needs then, and seed them appropriatley.

In this model, the Entity acts as a specific "coordinator", and would be responsible for handling certain messages (I.e. when a Damage component reports itself as depleted/destroyed), and routing them to other components as needed.

Any ideas on this?
Oliver Charles (aka aCiD2) [ Cycles Blog ]
Quote:Original post by Sneftel
I like this approach. One thing that I notice about it, though, is that it is basically a reimplementation of OOP within C++, one which supports runtime-composed objects. My thought, therefore, is that the first thing to do is to come up with a good framework for runtime-composed objects in C++, independent of entities and components and whatnot.


Quote:Original post by Cycles
In regards to smitty's post - it seems like a nice simple way to tackle the problem, but aren't you making a pretty big sacrifice: compile time checking?


Yes and mostly yes.

One of the uses of the system is that it allows non-developers to create content... entire AI behaviors (of widely varying complexity) can be visually "scripted" for entities, using nothing more than basic operations on named attributes. So, yeah... it's definitely a way of exposing an OOP-like interface to non-developers who wouldn't even recognize the term. It definitely allows for class inheritance and that sort of thing from the non-developers perspective--entity types can be drived from others and inherit their attached components, etc.

I'm curious how people handle scenegraph integration with a component based system. Usually things like Effect, Position, Cameras, etc are part of a scene graph but they also make sense as components.

I was thinking of arranging my entities hierarchally such that the entities double as nodes. I found traversal difficult with this method.

The other approach I tried was maintaining separate hierarchies for things like world transforms.

class WorldTransform : public IComponent{public:  Matrix Transform()  {    Matrix t = transform_;    if(parent_)    {      t *= parent_->Transform();    }    return t;  }private:  Matrix transform_;  boost::shared_ptr<WorldTransform> parent_;};


This worked alright for world transforms but doesn't seem to apply cleanly anywhere else. For example, I have no idea how cameras, and effects might fit in.
[size=2]
Quote:Original post by Sneftel
Quote:Original post by smitty1276
[ lotsa stuff ]

I like this approach. One thing that I notice about it, though, is that it is basically a reimplementation of OOP within C++, one which supports runtime-composed objects. My thought, therefore, is that the first thing to do is to come up with a good framework for runtime-composed objects in C++, independent of entities and components and whatnot.

More to come, gotta run.

I couldn't leave well enough alone.

This topic is closed to new replies.

Advertisement