• Advertisement
Sign in to follow this  

Component Systems - Entity examples

This topic is 2993 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently writing a basic entity system (concentrating on the base classes for the ComponentSystem and the EntitySystem (resolving dependencies, etc...). This works like a charm in theory but while implementing, there were somethings I really couldn't solve with a component system yet: I want to create a space RTS (basically an equivalent of world in conflict) game that uses more "realistic" (as opposed to other games) physics. Can anyone give me some examples how to "glue" together entities that are usually together, but may be seperated as well? For example: Spaceship with several turrets/modules. I figure my ship consists of a physics component, graphics, etc/blablabla, but should those turrets be entities as well? I think they should because they have a graphical & physical component, but then again there's my problem. Those modules have additional mass (which may not be neglected in some cases) so they should somehow be bound to the "main" entity (ie. the spaceship). Do you have any ideas or preferably experience how to solve that kind of problem?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by SiS-Shadowman
Can anyone give me some examples how to "glue" together entities that are usually together, but may be seperated as well?

You describe a hierarchy of entities. In your case, a ship entity is the parent of turret entities. You can implement this with a child entities component, which acts as a list of entities that should be attached to the parent. Add one to the main ship entity and make the turrets and modules children of the main ship. Rotation and position of the child entities then are measured relatively to the parent, for example.

Quote:
Original post by SiS-Shadowman
Spaceship with several turrets/modules. I figure my ship consists of a physics component, graphics, etc/blablabla, but should those turrets be entities as well? I think they should because they have a graphical & physical component, but then again there's my problem. Those modules have additional mass (which may not be neglected in some cases) so they should somehow be bound to the "main" entity (ie. the spaceship).

Depends on your preferences and your component system model. If you allow more than one graphics component per entity, and your modules/turrets are just that, I think it's alright to save some memory and not make them entities; but if you strictly impose "one graphics only", you'd add child entities for all modules/turrets, of course.
For anything more complex, you have entities anyway. E.g. the turrets might rotate independently from the ship and fire. I don't recommend implementing that as a component, since an entity can already do it, and you'd only end up with two kinds of objects that implement the same behaviour.

Share this post


Link to post
Share on other sites
So I could simply move entities from the "main" list of entities into a specific entity? I think I'm just not sure if this might be an elegant solution to the problem or not. After all, this component approach is there to not implement another hierarchy, but a system that decouples behavior into separate components. I have tried that hierarchy thing before, implemented as a tree (like you described), however it became pretty messy because I had to keep dynamic_cast'ing stuff (nodes in my previous approach), moving it, etc...

Isn't there something uncomplicated that would not introduce the same problems into a component system?

Share this post


Link to post
Share on other sites
Quote:
Original post by SiS-Shadowman
After all, this component approach is there to not implement another hierarchy, but a system that decouples behavior into separate components. I have tried that hierarchy thing before, implemented as a tree (like you described), however it became pretty messy because I had to keep dynamic_cast'ing stuff (nodes in my previous approach), moving it, etc...


Agreed. However, what I wrote about is a different kind of hierarchy which has nothing to do with the inheritance tree you mentioned. I should've been more specific. I did not propose a hierarchy of classes, but rather a hierarchy of entity objects which only tells which objects (temporarily) belong together in some way.

What you were basically asking for, if I understood you correctly, is some kind of "bones system", some way to tell "this object is part of that other object". That, too, forms a hierarchy. However, this is actually a desired one.

Perhaps I can explain it with another example. Say you have some smaller space ships, possessing attached gun turrets. These guns are "part of" the ship - there is no inheritance involved here, just the fact that the guns "somehow" belong to the ship, so they move together, get destroyed together, etc.
Now assume you have a bigger carrier ship, and several of your smaller ships can land on it. So now, the small ships belong to the carrier in the sense that they move together, since they are docked. But again, they just belong together temporarily, not by inheritance.

You have to express this hierarchy in some way, and what I proposed in my last post does just that. There are other solutions, of course; anything that applies to how to store tree structures does apply here, too.

Share this post


Link to post
Share on other sites
Quote:
Original post by mightshade
you'd add child entities for all modules/turrets, of course.
Of course, things aren't always that simple. For instance, if you are using a physics engine, then these relations often have to be joints, and the whole 'parent<-->child' notation doesn't work very well. Similarly in the fighter/carrier case, you need to make and break temporary attachments between docked fighters and the carrier.

Share this post


Link to post
Share on other sites
Quote:
Original post by mightshade
Agreed. However, what I wrote about is a different kind of hierarchy which has nothing to do with the inheritance tree you mentioned.


I didn't talk about an inheritance tree. I was talking about the dynamic part, ie. a Player would simply have a list of entities (called them nodes this time) that contained a gun-node, all items in the inventory, etc...
But this way I had to dynamic_cast those nodes all the time (like for example when a specific node has been removed, like the gun). I just didn't like the concept back then and it doesn't apply to me now either. However I don't see how I could express that concept of linked entities in a clean/simple fashion.

Share this post


Link to post
Share on other sites
Quote:
Original post by mightshade
Quote:
Original post by SiS-Shadowman
After all, this component approach is there to not implement another hierarchy, but a system that decouples behavior into separate components. I have tried that hierarchy thing before, implemented as a tree (like you described), however it became pretty messy because I had to keep dynamic_cast'ing stuff (nodes in my previous approach), moving it, etc...


Agreed. However, what I wrote about is a different kind of hierarchy which has nothing to do with the inheritance tree you mentioned. I should've been more specific. I did not propose a hierarchy of classes, but rather a hierarchy of entity objects which only tells which objects (temporarily) belong together in some way.

What you were basically asking for, if I understood you correctly, is some kind of "bones system", some way to tell "this object is part of that other object". That, too, forms a hierarchy. However, this is actually a desired one.

Perhaps I can explain it with another example. Say you have some smaller space ships, possessing attached gun turrets. These guns are "part of" the ship - there is no inheritance involved here, just the fact that the guns "somehow" belong to the ship, so they move together, get destroyed together, etc.
Now assume you have a bigger carrier ship, and several of your smaller ships can land on it. So now, the small ships belong to the carrier in the sense that they move together, since they are docked. But again, they just belong together temporarily, not by inheritance.

You have to express this hierarchy in some way, and what I proposed in my last post does just that. There are other solutions, of course; anything that applies to how to store tree structures does apply here, too.


Agreed

Quote:

Of course, things aren't always that simple. For instance, if you are using a physics engine, then these relations often have to be joints, and the whole 'parent<-->child' notation doesn't work very well. Similarly in the fighter/carrier case, you need to make and break temporary attachments between docked fighters and the carrier.


Doubly agreed.

I am working on the same kind of game, i commented out my component system because im prepping the rest of the engine first.

The nice thing about physics in this kind of situation is that you have control over the "rules". Some things don't necessarily NEED to be functioning with the physics. I am just going to use reference points and "attach" my components (which are just other game objects) to my game objects. the key for me is making attachable things "game objects" like particle emitters, lights, and possible other generic type objects. When something is hit by a bullet or whatever and needs to break off, that can just be a function. My problem is that i need an editor just to attach things in the right spot. I use lua though and it is coming together pretty nicely.

For me the parent child thing really only applies to matrix transforms to maintain attachment, as well as the obvious mass that something adds to an object when it's attached.

It's still a work in progress but thats at least how i see doing it.

this is a good thread.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiS-Shadowman
But this way I had to dynamic_cast those nodes all the time (like for example when a specific node has been removed, like the gun). I just didn't like the concept back then and it doesn't apply to me now either. However I don't see how I could express that concept of linked entities in a clean/simple fashion.
dynamic_cast automatically means that you are in fact using inheritance.

Why do you feel that Gun and InventoryItem need to be distinct types? The whole point of an entity/component system is that everything is the same class, Entity, with various components, i.e. Damage or SpaceTakeInInventory, that define their behaviour.

Share this post


Link to post
Share on other sites
I've made quite a bit of progress on mine so i'll share it with you. I'm abreviating everything because i'm typing it from memory. It's not perfect, i'm still in the process of refactoring a ton of core test code into an actual engine.


typedef boost::shared_ptr p;

struct Entity : public ComponentContainer
{
p&lt;Engine&gt; E;
p&lt;Scene&gt; S;

//base components, expected to be here and not in list
p&lt;Physics::BaseObject&gt; Phys;
p&lt;Graphics::Renderable&gt; Rend;
p&lt;Brain&gt; Brain;

virtual void Unregister()
{
if (S && Phys) S-&gt;Remove(Phys);
if (S && Rend) S-&gt;Remove(Rend);
}
};

static p&lt;Entity&gt; CreateCharacter(p&lt;Engine&gt; E, p&lt;Scene&gt; S /*from data file here*/)
{
p&lt;Entity&gt; newEnt(new Entity(E, S));
S-&gt;Add(newEnt);

newEnt-&gt;Phys = CreateCharacterPhysicsObject(blah);
S-&gt;Add(newEnt-&gt;Phys);

newEnt-&gt;Rend = CreateCharacterModel(blah);
S-&gt;Add(newEnt-&gt;Rend);

//these are really shared ptrs again but i'm too lazy to type it
newEnt-&gt;AddComponent(new InputMap(E-&gt;InputManager));
newEnt-&gt;AddComponent(new VehiclePassenger);

p&lt;WeaponInventory&gt; w(new WeaponInventory);
w-&gt;Add(CreateRifle(E,S));
newEnt-&gt;AddComponent(w);
//todo health and damage

newEnt-&gt;Brain = CreateCharacterBrain(blah);
//entity is automatically checked for a brain when scene is updated

return newEnt;
}


static p&lt;Entity&gt; CreateRifle(p&lt;Engine&gt; E, p&lt;Scene&gt; S /*from data file here*/)
{
p&lt;Entity&gt; newEnt(new Entity(E, S));
S-&gt;Add(newEnt);

newEnt-&gt;Rend = CreateRifleModel(blah);
S-&gt;Add(newEnt-&gt;Rend);

p&lt;EffectsComponent&gt; fx(new EffectsComponent);
fx-&gt;Add(CreateMuzzleFlash(E, S));
fx-&gt;Add(CreateMuzzleSmoke(E, S));
newEnt-&gt;AddComponent(fx);

return newEnt;
}




K, getting tired of retyping code. Theres a lot that is not apparent here. Like how the brain internally will create a state machine and then check the entity for other components that it will use such as the input map and weapon inventory.

Also, these create functions are actually virtual members of an EntityDef class. That was you can pass around the "potential" to make an entity. For example, when adding the weapon to the weapon inventory, part of its initialization is to include an EntityDef for the shell. That way when you use the weapon it has a handle to the create function for spawning shells. When the shell create function is returned, the entity->Phys is used to set its spawn location.

[Edited by - bzroom on December 8, 2009 1:08:08 PM]

Share this post


Link to post
Share on other sites
Here's a real example, for some reason i decided to have my Character inherit the brain and the entity.. theres absolutely no reason why so everywhere you see Character::Foo, should be CharacterBrain::Foo

and everywhere you see newEnt->someSpecificComponent other than the base types, it really shouldbe charBrain->someSpecificComponent.. i'm not too worried about that small fact though.

">Video
Pic



#include "Character.h"
#include "CharacterGroundState.h"
#include "CharacterMountedState.h"
#include "CharacterMountTransitionState.h"
#include "CharacterCam.h"
#include "MountableComponent.h"
#include "CameraComponent.h"
#include "InputMapComponent.h"
#include "WeaponInventory.h"
#include "CollisionFlags.h"

#include "Rifle.h"

#include "EntityList.h"
#include "LODEngine/Engine.h"
#include "LODGraphics/Renderer.h"
#include "LODGraphics/Camera.h"
#include "LODGraphics/AnimationController.h"
#include "LODGraphics/Model.h"
#include "LODGraphics/Scene.h"
#include "LODGraphics/ModelInstance.h"
#include "LODGraphics/Geometry.h"
#include "LODPhysics/World.h"
#include "LODPhysics/Character.h"
#include "LODInput/InputManager.h"
#include "LODResources/ResourceManager.h"
#include "LODCore/DebugMenu.h"
#include "LODMath/Matrix.h"

using namespace LOD::Graphics;
using namespace LOD::Resources;
using namespace LOD::Math;


DEBUG_BOOL(Character_Draw_Basis, false);
DEBUG_BOOL(Character_Draw_Bones, false);

void FillMatrixLines(Lines *lines, Matrix *bones, int cnt, Matrix &basis)
{
float size = 0.05f;
lines-&gt;SetActiveLineCount(0);

for(int b = 1; b &lt; cnt; ++b)
{
Vector p = bones * basis * Vector(0,0,0,1);

if (b &lt; cnt-1) lines-&gt;PushLine(p, bones[b+1] * basis * Vector(0,0,0,1), Color::Yellow);
lines-&gt;PushLine(p, bones * basis * Vector(size,0,0,1), Color::Red);
lines-&gt;PushLine(p, bones * basis * Vector(0,size,0,1), Color::Green);
lines-&gt;PushLine(p, bones * basis * Vector(0,0,size,1), Color::Blue);
}
}

namespace LOD
{
namespace Gameplay
{
boost::shared_ptr&lt;ResourceGetter&gt; CharacterDef::GetResources(boost::shared_ptr&lt;ResourceManager&gt; &rm /*pass in declaration file here*/)
{
//these will be read from a file at this point
boost::shared_ptr&lt;ResourceGetter&gt; getter(new ResourceGetter);
getter-&gt;Add(rm-&gt;GetResource&lt;Model&gt;(ResourceKey("Models/urban.xml")));

getter-&gt;Add(CharacterGroundState::GetResources(rm));
getter-&gt;Add(CharacterMountedState::GetResources(rm));
getter-&gt;Add(CharacterMountTransitionState::GetResources(rm));

boost::shared_ptr&lt;RifleDef&gt; rifleDef(new RifleDef());
getter-&gt;Add(rifleDef-&gt;GetResources(rm));

return getter;
}

boost::shared_ptr&lt;Entity&gt; CharacterDef::Create(boost::shared_ptr&lt;Engine&gt; &e, boost::shared_ptr&lt;Graphics::Scene&gt; &s)
{
boost::shared_ptr&lt;Character&gt; newEntity(new Character);
newEntity-&gt;MainBrain = newEntity;

newEntity-&gt;MyEngine = e;
e-&gt;m_Entities-&gt;Add(newEntity);

//create graphics
ResourceHandle&lt;Model&gt; model = e-&gt;m_Resources-&gt;GetResource&lt;Model&gt;(ResourceKey("Models/urban.xml"));
model-&gt;PrepareForAnimation();

boost::shared_ptr&lt;BasicAnimationController&gt; animation(new BasicAnimationController);
newEntity-&gt;Animation = animation;
animation-&gt;SetBones(model-&gt;GetBones());

newEntity-&gt;Renderable.reset(new ModelInstance(model, animation));
s-&gt;AddRenderable(newEntity-&gt;Renderable);

//create physics
Physics::CharacterCreationParams p(0.5f, 2.0f, 0.3f, Matrix(Vector(0,20,0)), BIT(COLLIDE_CHARACTER), collidesWith[COLLIDE_CHARACTER]);

newEntity-&gt;character.reset(new Physics::Character());
newEntity-&gt;Physics = newEntity-&gt;character;
newEntity-&gt;character-&gt;Create(p);
newEntity-&gt;character-&gt;DependentTransform = &newEntity-&gt;Renderable-&gt;Transform;
e-&gt;m_Physics-&gt;AddCharacter(newEntity-&gt;character);

//vehicle component
boost::shared_ptr&lt;MountPassenger&gt; passComp(new MountPassenger);
newEntity-&gt;AddComponent(passComp);
passComp-&gt;PotentialMountables.Results.reserve(10);

//camera component
newEntity-&gt;camComp.reset(new CameraComponent(&e-&gt;m_Renderer-&gt;GetCurrentViewable()-&gt;SceneCamera));
newEntity-&gt;AddComponent(newEntity-&gt;camComp);

//input component
newEntity-&gt;input.reset(new InputMapComponent(e-&gt;m_Input));
newEntity-&gt;AddComponent(newEntity-&gt;input);

//weapons component
newEntity-&gt;weapons.reset(new WeaponInventory(newEntity));
newEntity-&gt;AddComponent(newEntity-&gt;weapons);

boost::shared_ptr&lt;Weapon&gt; rifle(new Weapon);
boost::shared_ptr&lt;RifleDef&gt; rifleDef(new RifleDef());
rifle-&gt;weaponEntity = rifleDef-&gt;Create(e, s);
rifle-&gt;shellEntityDef.reset(new RifleShellDef);
rifle-&gt;muzzleAttachPtID = 1;
rifle-&gt;shellAttachPtID = 2;

newEntity-&gt;weapons-&gt;AddWeapon(rifle);
newEntity-&gt;weapons-&gt;AddSlot(1); //attach pt id
newEntity-&gt;weapons-&gt;Equip(0, 0);



//state machine
newEntity-&gt;stateMachine.reset(new State);

newEntity-&gt;groundState.reset(new CharacterGroundState(e, newEntity));
State::AddState(newEntity-&gt;stateMachine, newEntity-&gt;groundState);

boost::shared_ptr&lt;CharacterMountedState&gt; cms(new CharacterMountedState(e, newEntity));
State::AddState(newEntity-&gt;stateMachine, cms);

boost::shared_ptr&lt;CharacterMountTransitionState&gt; cmts(new CharacterMountTransitionState(e, newEntity));
State::AddState(newEntity-&gt;stateMachine, cmts);

newEntity-&gt;stateMachine-&gt;Start(CharacterGroundState::GetTypeIDStatic());

//debugging
newEntity-&gt;lines = new Lines(100, NULL);
newEntity-&gt;lines-&gt;SetActiveLineCount(0);
newEntity-&gt;lines-&gt;Material = e-&gt;m_Resources-&gt;GetResource&lt;Material&gt;(ResourceKey("Materials/debug.xml"));
boost::shared_ptr&lt;Lines&gt; li(newEntity-&gt;lines);
s-&gt;AddRenderable(li);

return newEntity;
}

bool Character::PreUpdate(float dt)
{
input-&gt;Update(dt);

stateMachine-&gt;PreUpdate(dt);

return true;
}

bool Character::PostUpdate(float dt)
{
camComp-&gt;Update(dt);

stateMachine-&gt;PostUpdate(dt);

weapons-&gt;Update(dt);

if (Character_Draw_Bones)
{
FillMatrixLines(lines, Animation-&gt;GetBonePallet(), Animation-&gt;GetBoneCount(), character-&gt;GetTransform());
}

return true;
}

}
}



*it'd be cool if the source tags didnt break the forum layout....

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by SiS-Shadowman
But this way I had to dynamic_cast those nodes all the time (like for example when a specific node has been removed, like the gun). I just didn't like the concept back then and it doesn't apply to me now either. However I don't see how I could express that concept of linked entities in a clean/simple fashion.
dynamic_cast automatically means that you are in fact using inheritance.

Why do you feel that Gun and InventoryItem need to be distinct types? The whole point of an entity/component system is that everything is the same class, Entity, with various components, i.e. Damage or SpaceTakeInInventory, that define their behaviour.


I didn't think it through when I wrote that. I think I'm a bit stuck in my old system. My actual point is the following. Suppose I attach an entity to another (perhaps a turret to a ship), how does the weapons controller (some part of the AI component) "know" which turrets it controls? They can be added/removed to/from a ship (nearly) any time.

Share this post


Link to post
Share on other sites
The ship needs a weapon inventory component, which the turret would be added to. The weapons controller only interfaces the weapon inventory, a particular slot in fact. Which ever weapon is associated with that slot is the one that will be controlled.

Share this post


Link to post
Share on other sites
This is an interesting thread, I am too working on a Space Based RTS, and attempting to build it entirely with a components based system, I have one glass GameEntity and no deriving from this, all functionality for every object (be it the sun, a planet, a battleship or a space station) is being created as components and propertys using a "lego brick" philosophy... no one component is ever reliant on the existence of another component or a property, and you can attach whatever you want to an object.

Ever wanted to make your camera chase a player and then blow up when it hits it, killing the player... well this should be possible to create in a few lines of script.

As for your turret attaching to a battleship problem, we use an AttachEntity component, which will create a new entity from a script, this agent is free to do whatever it wants, and the messaging system can be used to communicate with it.

My script for this would look something like this:

//HumanBattleshipTurretProjectile.txt
property float Range 10,000;
property float Damage 50.0;

component Movable
float Speed 50.0;
component Renderable
string MeshFile HumanBattleshipTurretProjectile.mesh;




// Turret.txt
property vector3 Position;
property vector3 Target {0, 0, 0};
property float FireRate 5.0;

component AIComponent
string AIBase TurretAIBase;
component Renderable
string MeshFile HumanBattleshipTurret.mesh;
component ProjectileLauncher
string ProjectileScript HumanBattleshipTurretProjectile.txt;




//HumanBattleship.txt

component Renderable
string MeshFile HumanBattleship.mesh;
component AttachedEntity
string EntityScript Turret.txt;

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
For instance, if you are using a physics engine, then these relations often have to be joints, and the whole 'parent<-->child' notation doesn't work very well.

Hmm. Can you be more specific or give me an example where this is the case?

Quote:
Original post by swiftcoder
Similarly in the fighter/carrier case, you need to make and break temporary attachments between docked fighters and the carrier.

Agreed. If I made it sound like these relationships were static, that's not what I intended to say.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement