Component-based Entities using Properties

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
Trefall
Gnoblar
Posts: 13
Joined: Tue Mar 13, 2007 4:39 pm
x 1

Component-based Entities using Properties

Post by Trefall »

Component-based Entities using Properties

Introduction
This is my second public design for using compoents with entities to prevent deep hierarchy problems and make the game object difinition more data-driven. By data-driven, I mean that you can define your game objects in for example XML.

Third party dependencies
- ClanLib (http://www.clanlib.org)

Some history
Over the last couple years I've been doing a lot of thinking on component-based entities. I really liked the idea of approaching the definition of entities this way. It chuncks up logic in the game nicely, makes it easy to write small scripted chuncks of logic, it's data-driven to the point where you could define entierly new game objects in for example XML.

The last couple of books from the Game Programming Gems series have covered this topic with different approaches, but the approach I'm suggesting here have not been discussed before to my knowledge; -using properties to add the glue between components!

During my time designing these component-based entity systems, I discovered that most of the time, if not all the time, when one component needed to communicate with another component, this was either to change some data, or that someone else had to change some data.

There was a problem here, because often you'd find that a component owning a specific data, (like, you'd want the movement component, to own the data for positioning your entities) had to inform other components about changing data, or change the state of data on other components' request.

Like with the MovementComponent example, it turns out a ton of components would like to know about the Position of their entity. Your dependency chain between components starts to weave and wrap around your logic, the more components depend on this common data that one component owns, the messier it gets, until you're left with an unmanagable pile of garbage code of inter-dependencies!

This raised the idea one day, to let the entities own all the data! Let components add data to their parent entity, let them change it, and let all components in an entity have the option to react to data changing!

This approach allowed components to be written totaly unaware of any other components in the mix. It only cares for it's entity and the properties it want to manipulate with it's logic.

The current version
The current version of the component-based entity system using properties, does not contain any specialized components (like those that can be defined from script) or any system for defining game objects in XML. Those systems should be fairly simple to extend the engine with however, and could (and should) be written externally from the EntityEngine library.

The source-code
http://svn2.xp-dev.com/svn/Trefall-Comp ... tem/Source

HOW TO/ FAQ
1)What is a game object?
- A Game Engine side object that inherits from Entity in Entity engine,
to wrap the Entity engine functionality, and add additional Game Engine
specific functionality to the Game Engine's Game Objects.

2)What is an Entity?
- A wrapper of ComponentContainer and PropertyContainer.

3)What is a ComponentContainer?
- Holds a map of components, and robust/secure methods for adding and manipulating components.

4)What is a PropertyContainer?
- Holds a map of properties, and robust/secure methods for adding/removing and manipulating properties.

5)What is a Property?
- Entity Engine's secure variable for data storage, including a smart pointer. It's owned by it's
ComponentContainer/Entity. It serves as glue between components, as components can listen for an altered
property and act upon such changes. Two components can work on the same property (as Entity is the owner).
This allows multiple components to work on the Position property of an Entity for instance, without them
ever knowing about each other.

6)What is a Component?
- Entity Engine's modular chuncks of logic for entities. Instead of using inheritance to define new entity
types, a modular approach is used. This seperates logic cleanly, makes extending objects simple and the
definition of a new game object data driven. A new game object definition, is simply about defining which
components it holds.

7)How to register new components with the entity engine?

Code: Select all

entityManager.GetComponentFactory().RegisterComponent(ExamineComponent::GetType(), &ExamineComponent::Create);
entityManager.GetComponentFactory().RegisterComponent(MovementComponent::GetType(), &MovementComponent::Create);
8)How to attach a component to a game object?
- Some initialization method for a zone:

Code: Select all

GameObject *objectRobot = new GameObject(entityManager, zone);
objectRobot->AddComponent("Examine");
objectRobot->AddComponent("Movement");
objectRobot->GetProperty<CL_String>("Description") = "It's a useless robot!";
objectRobot->GetProperty<float>("MovementSpeed") = 50.0f;
9)How to write a new component from scratch
- ExamineComponent.h
---------------------------

Code: Select all

#pragma once

#include <EntityEngine/Component.h>
#include <EntityEngine/Property.h>

namespace EntityEngine { class Entity; }

class ServerPlayer;

class ExamineComponent : public EntityEngine::Component
{
public:
	ExamineComponent(EntityEngine::Entity* entity, const CL_String &name);
	virtual ~ExamineComponent() {}

	virtual void RequestCommands(std::vector<CL_String> &requestCommands, ServerPlayer *player);
	virtual void ExecuteCommand(const CL_String &command, ServerPlayer *player);

	static CL_String GetType() { return "Examine"; }
	static EntityEngine::Component* Create(EntityEngine::Entity* entity, const CL_String &name) { return new ExamineComponent(entity, name); }

protected:
	EntityEngine::Property<CL_String> description;

	void OnExamine(ServerPlayer *player);
};
----------------------------
- ExamineComponent.cpp
----------------------------

Code: Select all

#include "precomp.h"
#include "ExamineComponent.h"
#include "../GameObject.h"
#include "../ServerPlayer.h"
#include <EntityEngine/Entity.h>
#include <NetworkSharedLibrary/NetEvents.h>

using namespace EntityEngine;

ExamineComponent::ExamineComponent(Entity* entity, const CL_String &name)
: Component(entity, name)
{
	description = entity->AddProperty<CL_String>("Description", CL_String());
}

void ExamineComponent::RequestCommands(std::vector<CL_String> &requestCommands, ServerPlayer *player)
{
	requestCommands.push_back("Examine");
}

void ExamineComponent::ExecuteCommand(const CL_String &command, ServerPlayer *player)
{
	if(command == "Examine")
	{
		OnExamine(player);
	}
}

void ExamineComponent::OnExamine(ServerPlayer *player)
{
	GameObject *gameObject = (GameObject *)entity;
	gameObject->SendViewEvent(CL_NetGameEvent(STC_OBJECT_DESCRIPTION, description.Get()), player->GetConnection());
}
------------------------------------
- MovementComponent.h
------------------------------------

Code: Select all

#pragma once

#include <EntityEngine/Component.h>
#include <EntityEngine/Property.h>

namespace EntityEngine { class Entity; }

class MovementComponent : public EntityEngine::Component
{
public:
	MovementComponent(EntityEngine::Entity* entity, const CL_String &name);
	virtual ~MovementComponent() {}

	virtual void Update(int deltaTime);

	static CL_String GetType() { return "Movement"; }
	static EntityEngine::Component* Create(EntityEngine::Entity* entity, const CL_String &name) { return new MovementComponent(entity, name); }

protected:
	EntityEngine::Property<float> movementSpeed;
	EntityEngine::Property<CL_Pointf> newDestinationPosition;
	std::vector<CL_Pointf> movementDestinations;

	CL_Slot slotNewDestinationPositionChanged;
	void OnNewDestinationPosition(const CL_Pointf &oldValue, const CL_Pointf &newValue);

	void ClearDestinationPositions();
	void AddDestinationPosition(const CL_Pointf &position);
	void SendDestinationPositions();
};
----------------------------------------
- MovementComponent.cpp
----------------------------------------

Code: Select all

#include "precomp.h"
#include "MovementComponent.h"
#include "../GameObject.h"
//...
#include <EntityEngine/Entity.h>
#include <NetworkSharedLibrary/NetEvents.h>

using namespace EntityEngine;

MovementComponent::MovementComponent(Entity* entity, const CL_String &name)
: Component(entity, name)
{
	movementSpeed = entity->AddProperty<float>("MovementSpeed", 100.0f);
	newDestinationPosition = entity->AddProperty<CL_Pointf>("NewDestinationPosition", CL_Pointf());
	slotNewDestinationPositionChanged = newDestinationPosition.ValueChanged().connect(this, &MovementComponent::OnNewDestinationPosition);

	GameObject *gameObject = (GameObject*)entity;
	gameObject->AddClientComponentRequirement(GetType());
}

void MovementComponent::OnNewDestinationPosition(const CL_Pointf &oldValue, const CL_Pointf &newValue)
{
	ClearDestinationPositions();
	AddDestinationPosition(newValue);
	SendDestinationPositions();
}

void MovementComponent::Update(int deltaTime)
{
	GameObject *gameObject = (GameObject*)entity;
	
	//... perform some movement logic
}

void MovementComponent::ClearDestinationPositions()
{
	movementDestinations.clear();
}

void MovementComponent::AddDestinationPosition(const CL_Pointf &position)
{
	movementDestinations.push_back(position);
}

void MovementComponent::SendDestinationPositions()
{
	CL_NetGameEvent movementDestinationEvent(STC_OBJECT_MOVEMENT_LIST);

	for(size_t i = 0; i < movementDestinations.size(); ++i)
	{
		movementDestinationEvent.add_argument(movementDestinations[i].x);
		movementDestinationEvent.add_argument(movementDestinations[i].y);
	}

	GameObject* gameObject = (GameObject*)entity;
	gameObject->SendViewEvent(movementDestinationEvent);
}
Last edited by Trefall on Tue Oct 27, 2009 5:19 pm, edited 2 times in total.

User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Component-based Entities using Properties

Post by jacmoe »

Trefall, your Component-based Entities and how they communicate topic at the IrrLicht forum is awesome! :D
Thanks a lot for that.
I'll look through fingers that this is not Ogre powered, because the topic is definitely wanted.
Take a look at this:
Component Based Objects?
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.

User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 3
Contact:

Re: Component-based Entities using Properties

Post by _tommo_ »

Cool idea :D
In fact i didn't even get to the point where "you're left with an unmanagable pile of garbage code" but i was starting to be uneasy because of the many inter-relation managers... like, physics requesting mesh AABB, components owning other components and using another one, etc.
This looks like a very good solution!
But:
-the whole system looks complex enough, that's 5 virtual methods to override, even if i see the point behind each one;
-it is fast?
I mean, it is true that gameplay requires often a negligible amount of power compared to the rest, but i bet that 200-some virtual function accesses per frame over a map come with a cost :wink:

Anyway, very interesting read!
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games

mirlix
Goblin
Posts: 225
Joined: Mon May 01, 2006 12:03 am
Location: Germany
x 5

Re: Component-based Entities using Properties

Post by mirlix »

Sounds like a good idea. I use messagelists to propergate changes, but connect seems to do almost the same thing, so not much difference there :).
Only one concerne here. What is when two components have a property with the same name, but a different meaning? Is there a way to handle this case in your system? This is where my system fall into pieces :D

Trefall
Gnoblar
Posts: 13
Joined: Tue Mar 13, 2007 4:39 pm
x 1

Re: Component-based Entities using Properties

Post by Trefall »

First, thank you all for replying. I'm honored to hear you say that my last component-based approach was awesome jacmoe :)

Thank you for the link. Looks like there's a lot of guys here already having done a ton of stuff with components. That's great! Now, I'm not going to read all those 25 pages today, but I'll surely make my way through every single page!

When I first started using the component-based approach, I tried to make everything a component. Every single engine feature was becoming a component of sorts. Now, I've gone away from this approach, because to my experience it was overkill and made more havoc than it made clear code and any benefit for my projects. I ended up in my last project to only put game logic into components. Like in the two example components I wrote in this topic. Examine and Movement. Pure gameplay logic. Also, from my last approach, I stepped away from the abuse of signal/slot events. It proved to be a real mess and was a nightmare to debug. I'm now making a persistant online game (not MMO), where we're using the component system quite extensively on the server. We have a base object called Game Object. This holds the logic required for clients to draw it already. It would be really simple to make a hardcoded RobotGameObject that inherits from GameObject and that does not care about components. In fact, as long as it cares about using the property system for storing data, it would be no problem hooking in components on top of it and use/react to whatever data was hardcoded into the Robot.

So we've ended up with a couple of objects that use inheritance. ItemGameObject and ActorGameObject, for instance. On top of these we add components to add more game logic.

I've found that properly seperating the core logic of game objects is very difficult, and in most cases unnecessary, because most game objects will all have this same core logic in common anyway... the whole point of component-based entities, is to make the definition of game objects data-driven. To me, that means that for every new game object I want to define, I should be able to do that as quickly and effortlessly as possible through something like XML, or even a Graphical UI that can show a list of all available components and let me graphically string together a new object definition, and always update me on which data/properties are available for the game object with every new component I add to the mix.
But:
-the whole system looks complex enough, that's 5 virtual methods to override, even if i see the point behind each one;
-it is fast?
I mean, it is true that gameplay requires often a negligible amount of power compared to the rest, but i bet that 200-some virtual function accesses per frame over a map come with a cost
I think the best answer I can give to this question is: So far, it's been good enough for my project. There are certainly a number of optimizations that could be made to the component-based entity system I proposed here. Take a different route to prevent the use of virtuals, use a hashmap instead of a std::map, use enums/integers instead of strings for identifiers... but why put in a ton of effort into optimization, when your game is running fast enough as it is? I'm sure we're going to have to do some optimization down the line, but if it will happen in this part of our game's code, I can't know before we're there. Will my 200 virtuals cost more cpu time and be faster to optimize than some other parts of my game's code? I won't know until I get there, until we truly start to profile the game and do the stress testing. But one thing that's certainly true, is that if you can make the definition of all your game objects data-driven, you've saved a ton of time in compilation, so the time I spend profiling and optimizing down the line won't really be lost time, it'll be spending time already saved.
Only one concerne here. What is when two components have a property with the same name, but a different meaning? Is there a way to handle this case in your system? This is where my system fall into pieces :D
Yeah, we've been tackling this problem too. We found that in some rare occassions, you'd have different components with properties whos names had to be the same, but without them holding the same type of data. We tackled this by allowing an option for a component to prefix a property with that component's name. We found this to be a good enough solution, because we saw that in those occassions where we'd bump into this problem, those properties were always contained within those single components. Until we come into a situation where this assumption is proven wrong, we didn't really see a reason for spending more time on finding a more complete and robust solution here.

tp
Halfling
Posts: 40
Joined: Sat Dec 09, 2006 9:06 am

Re: Component-based Entities using Properties

Post by tp »

Trefall, I'd love to hear your view on a couple of questions regarding your design.

First, I think a big part of the advantage of component-based systems is that each component system can potentially very easily run on its own. This is often due to the fact that crucial and/or performance critical data is contained in the component. This lends itself quite well for development into a parallel processing friendly paradigm, which is becoming quite the fad these days (search for threads on these forums for some excellent information on the topic). Moving data from the component to the entity breaks this down. Do you have any ideas for addressing this with your entity housed properties?

Second, your system seems to work nicely when the interrelationships between things are straightforward. An example would be a physics engine driving the "position" property, which would then be observed by the rendering and AI components. Real life situations, however, tend to be more problematic, such as the physics model driving the rendering most of the time, except when an artist created animation is played, during which the order is reversed. Each component would need to be configurable to either ignore notifications or be flagged not to send them. You mentioned a very real problem (the unmanagable pile of garbage), but I didn't really get how storing the data in one place that is contested solves this better than having the data in multiple locations and having lots of interdependencies. Is there something I missed or am I just being dense?

<soapbox>
Now, my opinion on this is that trying to manage the interdependencies in a manner that is not specific to the problem at hand is a losing battle. My personal plan to address this in my system is to have properties, based on templates, housed in different components, but with a single linking interface that is usable on the entity level. This way, when you design a player character entity, you can specify that the graphics (through input) is controlling the physics component, and when you design a static object, that the physics is driving the graphics. As I mentioned in the giant component-based thread, in my system an entity is defined using a script file, so entities are not just IDs with a list of components, but context specific logic is inherent. I think an easy time with this linking is just one benefit of realizing that component-based systems are inherently context specific on the entity level.
</soapbox>

Trefall
Gnoblar
Posts: 13
Joined: Tue Mar 13, 2007 4:39 pm
x 1

Re: Component-based Entities using Properties

Post by Trefall »

Thank you for spending a bit of time with my approach TP!

Like I said in my last post, I approached this component system with one goal in mind, and that was to make as simple a component system to use for gameplay programming. Like I said, I didn't want to modularize rendering and physics, because I didn't see a need for it. Certainly, if you're looking for making your engine threaded, then it makes sense to put those things into self-contained components, but I think the requirements of these core engine components may differ a bit from the needs of gameplay components.

Certainly, if you'd like to parallelize all your gameplay logic as well, then my approach is not for you. I decided early that I wouldn't focus on multithreading for this design, because the project I was going to use it for didn't need it, and I had yet to design a component system that felt good to develope a game with. So, the idea of letting the entity own the data, and then allow components to change that data as required and listen to that data changing, was spurred by me wanting components that was totally unaware of any other component. My components simply change properties and they might care that properties change, but that's it. They couldn't care less if a thousand other components were changing the property they are listening to, or that a thousand other components are listening to the property they are changing. There's an update function on the components that gets called every update interval as well, so your component is not required to listen to property changes to do logic. In our engine, we also have commands, which are the clients (players and AIs) way of "ordering" logic to occure via input commands.

So, the result we're left with, is that we can create new components of game logic, without really caring much for which components have been made before. The execution order is unordered, but if you have a component that has some logic that needs to execute after a property changed, we have the ability to listen for such changes to cover that, and that's why that ability was put in there.

This is what I refered to as going away from a pile of garbage code. To my experience, if you have dependencies between components, you'll get garbage code in the end. In my last approach I was making the components loosely coupled by limiting all communication between components through a signal/slot event system. In theory, this avoided one problem of some past appraoches I had read about, which was the ordered execution of component types (where adding new components into the ordered list became an increasingly exhausting and risky task with every new component you added to the mix. You had to know about and understand the behavior of every other component before you could safely add another component into the mix). My event approach for communication also failed into garbage, however, because seperating components cleanly while maintaining communication became messy. In my project using the system, I ended up with a ping-pong system that quickly got out of hand. Thus, it ended up as garbage. With the component-based entities using properties approach I've described here, this kind of garbage has not piled up yet in my project, and I've come far longer into the project than I did with my last project using the other approach (components and how they communicate). I can't promise that this will be the case for every project, because with my last approach I felt pretty confident in the beginning as well. I only know that it's working very well on my current project and the requirements and needs that my current project hosts for me...

So, when adapting a component system into your game, I think it's very important to make a consious choice of what do you really want to use your component system for. It's so easy to make the decision of making everything a component, but that's a dangerous path to follow. One could also argue that core engine functionality might not hold the same requirements in a component system that game logic / game play does, so maybe two different component systems would be a good choice to implement if you really want to make the entire engine modularized into components. Beyond the argument of parallellization, I really don't see the point of doing that though.

To your second note on reversing the order of execution. This sounds like you'd have to incorporate some kind of state awareness in some of your components. In my approach, I would solve this by adding a state property on the entity, when the state then goes into the custom_animation_driving_execution state, the logic of that animation component would be responsible for changing the required properties that the other components listen to, to ensure that the execution goes as planned. The other components would also have to change a bit when the state property changes, so that it listens to the properties that the state requires. There is no strict order of execution in my system, however. So if you'd have many components that have to be executed one after the other, you'd have to go in an manually add these to the game object's update loop, where it today only updates over the components genericly. If you have this kind of dependency of execution in your components though, I think that in most cases it's due to that the logic seperation between components has gone wrong. Only in rare cases would such dependencies truly exist.

Like I said though, in our approach, Rendering is always executed after the components have been updated and the properties have been cleaned, so it doesn't care at all about the component system (it's not a component). In our game, we have no physics either, we only have collision detection, because it's a 2D game, so it holds a little less core engine functionality that would complicate matters.

With my approach, I've tried to stay true to that YAGNI principle, because adding functionality that you don't have the means to test in practise is just wasted time and effort. I think that it's very difficult to make a component system that would just work for every single project out there, because there are so many different needs and different developers want to have different capabilities in their system. Myself, my goal has always been that I want the ability to define new game objects in XML by stringing modules of logic together, and I want to be able to easily define new logic by writing new components in script. So, my component system was never designed for modularizing an entire engine. It was made with game logic in mind.

You got a bit fancy in your language there in the last paragraph, so I'm not sure I followed your english all the way through. What exactly is the benefit you get from defining entities in script? Does it house logic beyond that of your components? Or would you easily be able to define your entities in XML as well, for instance?

My goal, is to make a simple GUI tool for defining new game objects. Here you should be able to base your new game object on some other game object (a component and property container inheritance), and then be able to drag/drop new components onto your game object. As new components are added, the list of properties on the game object would update in a properties list, allowing you to easily define the initial values of each property on your game object without duplication. The GUI tool would then save the new game object into a simple XML file that the engine would be able to load at run-time. As we're making a persistent online game (without the massive in it), we really strive for being able to add new logic and content while the server is running, with the ability to stream new behavior and content to the clients at run-time. This is why we have a requirement in our project for data-driven game object definition and game logic definition through components, and is also why we have not focused the component system toward core engine functionality.

tp
Halfling
Posts: 40
Joined: Sat Dec 09, 2006 9:06 am

Re: Component-based Entities using Properties

Post by tp »

It seems you are considering the component system itself a part of your game logic, and are more willing to accept compromises in design if that helps stuff move along. I myself am particularly interested in how to be able to increase reuse between projects (which helps a lot when prototyping ideas). That's fine with me, I just wanted to mention this because I do not want to argue against your project, just debate the theory... ;)

The multithreading consideration especially is something that is just a design decision, I just wanted to point it out in case you hadn't thought of it. Whether rendering and/or physics is a component system is also not really relevant I think, as you can do it either way, but I do not think that making them component systems is an obvious mistake. A proper component system should lend itself to any context, but of course it's quite valid to design everything with a layer in between.

I would like to argue, though, that it's always desirable to design things so that they fit a compartmentalized component model. It's a lot easier to make an error free module when it only needs to care about itself and its public interfaces. It's also a lot easier to adapt complicated standalone components that do one thing very well (like OGRE!) and get them running in the game. One of the fundamental ideas of component based design is the idea that components should know as little as possible about each other. If you have to make two components that are designed for separate purposes (e.g. physics and rendering) aware of possible state changes in the other, you move away from the benefits of component based designs.

I still don't understand how moving data from a linked component-housed location to a central contested location helps this issue. Can you give an example that works with entity level properties, but not with linking? (No need for code I think, just the description of the situation)

I don't use XML myself for defining entities. I can make it user friendly enough in Lua (many people have missed the fact that Lua originated as a configuration language syntax). An extremely simple example might be something like:

Code: Select all

scenenode
{
  position = { 0, 0, 0 }
}

meshobject
{
  mesh = "object.mesh"
}

function onInit()
  self.scenenode:attach(self.meshobject)
end
A more complicated example:

Code: Select all

scenenode "attachmentpoint"
{
  position = { 10, 0, 0 }
}

meshobject "module"
{
  mesh = "spaceship_control_module.mesh"
}

function onInit(config)
  config.parentcomponent.attachmentpoint:attach(self.meshobject)
end
The latter represents a module in a spaceship, where each module is connected to another. It's not the perfect example, but the important point is that linking is done on the entity type logic level, not on the component level. In this example, it's not even a property that's being linked, but the scenenode parenting scheme. All things get easier to manage (in C++ at least) as you move interdependency management out of components.

For what it's worth, I would use a GUI tool for creating entity types defined by a programmer type person, i.e. level design, not for defining the entities out of components. I see your point regarding this though. Have a look at the Torchlight editor tutorial videos for inspiration: http://www.torchlightgame.com/developer ... rt-1-of-3/ (logic editing at around 5:45)

Post Reply