Jump to content

Component & Property/Attribute design


Rick
 Share

Recommended Posts

So just playing around with different design patterns. I've read, and experience, that deep class hierarchy systems become bloated and not very flexible. As things change tons of hacks end up being put in and classes get stuff they don't need. So the Component design is supposed to help with that by using containment rather than inheritance. That's kind of the idea behind the Component design, but to make that idea generic so it can be used as almost a framework get's interesting. Anyway I'll show how one would use it first, then how the code behind the magic (if you call it that) works. Interested in thoughts/ideas/concerns/potato chips?

 

The main test program: Very simplistic idea with heavy comments

int main()
{
// we are treating this as the main top level component that stores all other game object type components like
// players, zombie, ammo crates, etc. each component added will be able to get this owner so it can search
// for all other game object component's loaded. this provides an easy way for enemies to query things about
// the player for example
Component _gameObjects;

// make a generic game object component
Component obj1;

// _gameObjects becomes obj1's owner automatically by adding a component to it
_gameObjects.AddComponent(&obj1, "player");

// add just the components you need for the player to work and after all added check the component dependencies 
// to make sure they all fit
obj1.AddComponent(new HealthComponent());
obj1.AddComponent(new RespawnComponent());

// currently multiple calls to CheckDependencies() could be dangerous since events can get bound in there
if(!obj1.CheckDependencies())
{
	// todo: report a dependency not met somewhere
	int i = 0;
}

// testing different ways to get components and attributes
//=========================================================
// this is how we can get specific components from game objects or generic components
Component* healthCompGeneric = obj1.GetComponent("HealthComponent");
HealthComponent* healthComp = obj1.GetComponent<HealthComponent>("HealthComponent");

// this is how we can get attributes from specific components or generic components
Attribute<float>* health = healthComp->GetAttribute<float>("health");
Attribute<float>* health1 = healthCompGeneric->GetAttribute<float>("health");

// or we can do it this way
//float health1 = obj1.GetComponentAttribute<HealthComponent,float>("HealthComponent", "health");

// below is just for testing purposes to see events fire
_gameObjects.OnUpdate();
health->Value = -5;
_gameObjects.OnUpdate();
_gameObjects.OnUpdate();

return 0;
}

 

The HealthComponent: Used to store a health value and track other health related things like death.

class HealthComponent : public Component
{
private:
void RespawnComponent_OnRespawn(Component& c, Message& m)
{
	// we've respawned!! set our health back to the base health value
	GetAttribute<float>("health")->Value = GetAttribute<float>("base.health")->Value;
}
public:
HealthComponent()
{
	AddAttribute("health", new Attribute<float>(100.0));
	AddAttribute("base.health", new Attribute<float>(100.0));

	// create an OnDeath event that we can fire and inform other components attached to a game object that
	// this game object is "dead"
	CreateEvent("OnDeath");
}

virtual void OnUpdate()
{
	// this component will fire the OnDeath event to anyone listening when health is <= 0
	if(GetAttribute<float>("health")->Value <= 0)
		FindEvent("OnDeath")->Raise(*this, Message());
}
virtual void OnMessage(int msg){}

virtual bool CheckDependencies()
{
	if(!Component::CheckDependencies())
		return false;

	Component* respawn = GetComponent("RespawnComponent");

	if(respawn == 0)
		return false;
	else
		// bind to the respawn event so we can reset ourselves
		respawn->FindEvent("OnRespawn")->Bind(this, &HealthComponent::RespawnComponent_OnRespawn);

	return true;
}

virtual string Type() { return "HealthComponent"; }
};

 

The RespawnComponent: Controls respawning of game obejcts

class RespawnComponent : public Component
{
private:
bool _dead;

void HealthComponent_OnDeath(Component& c, Message& m)
{
	_dead = true;
}
public:
RespawnComponent()
{
	_dead = false;

	CreateEvent("OnRespawn");
}

virtual void OnUpdate()
{
	if(_dead)
	{
		_dead = false;
		FindEvent("OnRespawn")->Raise(*this, Message());
	}
}
virtual void OnMessage(int msg){}
virtual bool CheckDependencies()
{
	// check any child dependencies I have to make sure they are good
	if(!Component::CheckDependencies())
		return false;

	// I care about the health component because when it fires it's OnDeath message I need to start my repsawn
	// timer
	Component* health = GetComponent("HealthComponent");

	if(health == 0)
		return false;
	else
		// bind to the OnDeath event if this game object has the HealthComponent attached to it
		health->FindEvent("OnDeath")->Bind(this, &RespawnComponent::HealthComponent_OnDeath);

	return true;
}

virtual string Type() { return "RespawnComponent"; }
};

 

 

The implementation

==================

Events.h : You can ignore figuring this out if you like and just use it. Much easier to use than read :)

#pragma once

#define events private;

#include <list>

using namespace std;

template<class P, class Q>
class TFunctor2
{
public:
  virtual void Call(P var1, Q var2)=0;
};

template <class TClass, class param1, class param2>
class TSpecificFunctor2 : public TFunctor2<param1, param2>
{
private:
  void (TClass::*fpt)(param1, param2);
  TClass* pt2Object;         
public:
  TSpecificFunctor2(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2))
  { pt2Object = _pt2Object;  fpt=_fpt; }

  virtual void Call(param1 var1, param2 var2)
  { (*pt2Object.*fpt)(var1, var2); }
};

template<class T1, class T2>
class Event2
{
public:
  list<TFunctor2<T1, T2>* >  mCaller;

  template<class Target>
  Event2(Target* t, void (Target::*fnPtr)(T1, T2))
  { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }

  Event2(){}

  template<class Target>
  void Bind(Target* t, void (Target::*fnPtr)(T1, T2))
  { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }

  void Raise(T1 V1, T2 V2)
  {
     list<TFunctor2<T1, T2>*>::reverse_iterator iter;


     for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
     {
        (*iter)->Call(V1, V2);
     }
  }   

  void Clear()
  {
     mCaller.clear();
  }
};

 

Component & Attribute: Much easier to use than read

class Message
{
};

class Component;

typedef Event2<Component&, Message&> EventHandler;

class AttributeType
{
};

//===================================================

template <typename T>
class Attribute : public AttributeType
{
private:
public:
T Value;
Attribute(T value){ Value = value; }
~Attribute(void){}
};

//====================================================

class Component
{
private:
map<string, AttributeType*> _attributes;

// a game component can have other game components
map<string, Component*> _components;
private:
map<string, EventHandler*> _events;
protected:
void CreateEvent(string name)
{
	// make sure an event doesn't already exists
	if(_events.find(name) == _events.end())
		_events[name] = new EventHandler();
}
public:
Component(void){}
~Component(void){}
virtual string Type() { return "Component"; }
virtual void OnUpdate()
{
	map<string, Component*>::iterator iter;

	// toconsider: we might need certain components to update before others
	for(iter = _components.begin(); iter != _components.end(); iter++)
	{
		(*iter).second->OnUpdate();
	}
}
virtual void OnMessage(int msg){}

EventHandler* FindEvent(string name)
{
	if(_events.find(name) == _events.end())
		return 0;

	return _events[name];
}

virtual bool CheckDependencies()
{ 
	map<string, Component*>::iterator iter;

	// check all dependencies of all components added
	for(iter = _components.begin(); iter != _components.end(); iter++)
	{
		if(!(*iter).second->CheckDependencies())
			return false;
	}

	return true;
};

void AddComponent(Component* comp)
{
	// set the parent of the passed in attribute to us
	comp->AddAttribute("parent", new Attribute<Component*>(this));

	// add this component
	_components[comp->Type()] = comp;
}

// an alternative way to identify components. this is used for top level components that'll store game object
// style components with a different name like "player"
void AddComponent(Component* comp, string name)
{
	// set the parent of the passed in attribute to us
	comp->AddAttribute("parent", new Attribute<Component*>(this));

	_components[name] = comp;
}

// casts the component
template <typename T>
T* GetComponent(string name)
{
	if(_components.find(name) == _components.end())
	{
		// if we don't have this component see if our parent does
		Component* parent = GetAttribute<Component*>("parent")->Value;

		if(parent != 0)
			return parent->GetComponent<T>(name);
		else
			return 0;
	}

	return (T*)_components[name];
}

// doesn't cast component
Component* GetComponent(string name)
{
	if(_components.find(name) == _components.end())
	{
		// if we don't have this component see if our parent does
		Component* parent = GetAttribute<Component*>("parent")->Value;

		if(parent != 0)
			return parent->GetComponent(name);
		else
			return 0;
	}

	return _components[name];
}

template <typename T, typename C>
C GetComponentAttribute(string component, string attribute)
{
	// todo: if we don't have this attribute, travel up the "parent" attribute to see if any of our parents have it

	// make sure the component exists
	if(_components.find(component) == _components.end())
		return 0;

	T* comp = GetComponent<T>(component);

	return comp->GetAttribute<C>(attribute)->Value;
}

//template <typename T>
void AddAttribute(string name, AttributeType* att)
{
	// only add the attribute if it doesn't already exist
	if(_attributes.find(name) == _attributes.end())
		_attributes[name] = att;
}

template <typename T>
Attribute<T>* GetAttribute(string name)
{
	// todo: if we don't have this attribute, travel up the "parent" attribute to see if any of our parents have it

	if(_attributes.find(name) == _attributes.end())
		return 0;

	return reinterpret_cast<Attribute<T>*>(_attributes[name]);
}
};

Link to comment
Share on other sites

I think this design is very useful in some situations, but I really cannot think to use it as base structure for a complete game because I think it do things more complex than it would have with a well structured inherits and base class (I usually create interface and abstract class with the fewest information as possible and then derive them as needed).

 

First of all I don't like very much to have to remember the string constant of a property or event, and this may cause more "syntax errors" which the compiler cannot find and so generate logical bugs. And even if you use constants for properties/events names, yet the code will result very less readable than an explicit one:

 

float health1 = obj1.GetComponent<HealthComponent>("HealthComponent")->GetAttribute<float>("health");
float health2 = obj2.Health;

 

I think that the component/properties pattern design is very useful if you are going to build a generic game library (and still it needs more methods to hide that way of get value under the hood), but not for a specific game structure.

?? FRANCESCO CROCETTI ??

http://skaredcreations.com

Link to comment
Share on other sites

I think it do things more complex than it would have with a well structured inherits and base class (I usually create interface and abstract class with the fewest information as possible and then derive them as needed).

 

The interesting thing that I read about this pattern is that most everyone says that. I think one article said that we have become very good at learning to deal with the downfalls of a messy hierarchy structure because in any relatively large game (for the most part) things start to get large and almost unmanageable with a deep hierarchy. Requirements change (as they always do) and suddenly we realize our perfect design starts to fall apart or get unmanageable because of maybe some hacks or what have you.

 

I've ran into this and I was only making smaller games. You get your perfect hierarchy design down, start coding away, then a new(er) game design idea hits you. You look at what it takes to implement into the hierarchy design you have and either you refactor a ton of code or you hack it in. Most of the time this is where things get either boring or frustrating.

 

 

First of all I don't like very much to have to remember the string constant of a property or event, and this may cause more "syntax errors" which the compiler cannot find and so generate logical bugs. And even if you use constants for properties/events names, yet the code will result very less readable than an explicit one:

 

I agree that the properties method looks ugly (not sure much can be done about that in C++) and most likely works better with languages like lua where you can just create a variable that can hold anything anytime. However, this approach is more flexible. This allows me to create variables from outside sources like a config file without recompiling. Flexibility is the name of the game for this pattern.

 

 

The thing I really enjoy about this is that it seems to be great for sharing code and working on projects with larger teams (if you can convince other programmers to use it).

 

The syntax I have is something I put together in a day or so. I might be able to make it little less intrusive. I think the communication between components is where the trouble starts. My first attempt is what you see above with using an event system. Virtual methods could be used like OnMessage() (which I have but didn't use). I'm not a fan of use switch statements in a catch all message function myself.

 

I'll see what I can do about component & attribute access.

Link to comment
Share on other sites

When I picture this system I always picture the building of an actual game from an editor where the components have been built already (or new components can be added). Where designers drag and drop components that programmers have built to make game objects functional.

 

I drop the base level model into my scene. I then drop the pathfinding component on it that builds a navmesh.

I then drop an empty game object into the scene. Attach an alient model component. Attach an AIPathFinder component on it and now it'll work with the level pathfinding component to be able to find paths. Add a controller component and now it can move along the paths it finds. Add a PlayerSeeker component and now it'll wonder around looking for the "player". The components become the building blocks for designers to make games. It probably sounds a lot like a FPS creator, but when you have control to code components it's not limiting at all.

 

All game objects would know about each other because a game object is just a component and every "game object component" is derived from 1 master component, so there is a parent tree that can be climbed by any child component to find any other "game object component". That's why there are 2 AddComponent() methods. One allows you to give a name instead of a component type. So in any other component, like the PlayerSeekComponent example above, it can simply do GetComponent("player") and it'll transverse the tree automatically to find the player component and can then know everything it wants to about the player component. To me that's very cool. In a class based system getting information about other classes can start to get messy normally. Are you passing tons of variables around, or storing pointers to them in other classes, or making them global. I've used all those methods and it's a pain. When your design changes you often end up changing what needs to be seen by what, until each class has a ton of pointers to objects, or you end up passing a ton of objects to functions, or everything becomes global/singleton. Those methods suck :) I think I would find it nice to be able to easily query any component at any time from within any other component. If only the syntax didn't suck so much :)

 

 

[edit]

Another feature about this I think would be that after awhile you would have a nice component library and basic reusable components would be so plug and play in any game you make with 0 alteration required since they are all self containing. For the most part any complex hierarchy structure generally takes some tweaking/slamming in to get working with multiple projects.

Link to comment
Share on other sites

Continuing from what we were discussing last night, the other reason I think the Properties Pattern might be useful for rapid development, is while it uses inheritance, it is not static inheritance (I hope I am using the term correctly), where related classes must be stacked on top of each other. Instead, unrelated objects can be dynamically linked together in a vertical structure, so everything can be accessed and overridden, from an update script situated at the bottom. It will be an ugly ball of code at the base, but if it is all in scripts written by your users, it may not matter so much.

 

With the Object Components method, you have a flat structure where each object must look left and right for components it needs to access and control, so you have the problem of components sending messages and getting data from each other, while preserving the all important loose coupling. I haven't seen if you have solved this problem yet, but the solution needs to be simple, it must not create extra work and it must be available to script programmers.

 

EDIT

One other thing I'd want for an Object Component system is the ability to call functions in other components that calculate and return a response. I assume that is easy to do with your event class.

 

 

Anyway I haven't made up my mind yet. I'm still weighing the pros and cons of each system. :)

 

These are the relevant articles for anyone who wants to join the discussion:

 

Properties Pattern

http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html

 

Object Component Pattern

http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

http://gameprogrammingpatterns.com/component.html

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

so you have the problem of components sending messages and getting data from each other, while preserving the all important loose coupling. I haven't seen if you have solved this problem yet, but the solution needs to be simple, it must not create extra work and it must be available to script programmers.

 

I've found that game objects talking to each other and knowing about each other is always a problem with most every system. There seems to be a few ways to handle this and some I would consider better than others, but might be somewhat more complex. For example I would consider objects sending events the best solution but it's more complex than having all game objects global. If one class tries to access a global object and then you take that objects away for some reason things start to break. I like events because objects that need to care about events are responsible for registering for them, and the registration can be done in the "outside world" instead of pointers being stored from within objects to other specific objects.

 

My solution above was to use events (that have a common signature) and to have components query for other components, that are attached with the game object, that they wish to bind to an event it has. So the RespawnComponent binds to the OnDeath event from the HealthComponent so it knows when the health is <= 0. From within the RespawnComponent it doesn't need to reference HealthComponent directly. Instead it can query for the HealthComponent but return it's Component only and then bind to the even. This requires knowing the names of events that a specific component creates.

 

I think easier helper functions within Component can make this easier for component makers.

Link to comment
Share on other sites

This article discusses and solves the communication problem nicely using Java generics. I don't know if you can apply it to C++ or not.

 

http://t-machine.org/index.php/2010/05/09/entity-system-1-javaandroid/

 

He reduces it down to the following.

 

e.getAs( Position.class ).x = 5;
e.getAs( Damage.class ).hitpoints = 145;
e.getAs( Renderable.class ).foregroundColour = Color.red;

 

 

If you could call functions using that system and from scripts, it would be a dream to use.

 

int retVal = e.getAs( Position.class ).SomeFunctionCall(param1, param2, param3);

e.getAs( Position.class ).FunctionCall(ref param1, ref param2, ref param3);

 

EDIT:

 

Looking at that again, I'm thinking if you need to do the above, you may as well link the components together.

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

A friend of mine implemented this very pattern into an old Leadwerks C# framework. I liked the flexibility, but it seemed bloated.

 

The best example usage I came across in using his system came in two ways:

1) We had components that made up the player: Camera, Controller, and Control components, that handled the Leadwerks camera, the Leadwerks controller, and our input system, respectively.

 

2) We had a set of components that made up the actual gameplay logic behind the player; it was a survival RPG, and you had to eat (Hunger), sleep (Energy), and drink water (Thirst)/Water. It was a "stranded on an island" game.

 

There was a component for each of the 3 "needs", and a Health component. Each component could talk to the other components by querying the player (parent of all 4 components) for the other using a Name, or get the entire set of 3 by using a FamilyID string.

 

It was pretty awesome. I have attached the source code for the entire game (C# in Leadwerks x.x, I think it was 2.0). What was also pretty cool, was that you could create components in either C# or Lua, and it made no difference. Components could still talk to each other and be interacted with the same way, though this required a .NET Lua module that allowed importing .NET types into Lua.

 

 

I also attached a RAR with the most recent version of source code for said game framework. You might be able to find a playable version of the game in the Showcase of the old Leadwerks forum.

 

EDIT: http://forum.leadwerks.com/viewtopic.php?f=32&t=2254&start=0 There is the old thread, but it seems I deleted the archive from the server.

Survival.zip

Modules.rar

52t__nvidia.png nVidia 530M cpu.gif Intel Core i7 - 2.3Ghz 114229_30245_16_hardware_memory_ram_icon.png 8GB DDR3 RAM Windows7_Start.gif Windows 7 Ultimate (64x)

-----

IconVisualStudio16.png Visual Studio 2010 Ultimate google-Chrome.png Google Chrome PhotoshopLinkIndicator.png Creative Suite 5 icon28.gif FL Studio 10 MicrosoftOfficeLive.png Office 15

-----

csharp.png Expert cpp.png Professional lua_icon.png Expert BMX Programmer

-----

i-windows-live-messenger-2009.pngskype-icon16.pngaim_online.pnggmail.pngicon_48x48_prism-facebook.pngtunein-web.pngyahoo.giftwitter16.png

Link to comment
Share on other sites

Dynamic Game Object Component System for Mutable Behavior Characters

http://www.josericardojunior.com/docs/DGOCSMBC_SBG08_1.pdf

 

 

In this paper we propose an augmented Game

Object Component System with automatic

activation/deactivation of components based on

runtime evaluation of logical conditions. Using this

approach, it is possible to compose entities with

mutable behavior based on such dynamically activated

components. We propose this architecture as an

alternative to Finite State Machines to model NPC

behavior. This dynamic mechanism decouples the

implementation of the behavior itself from its

activation and deactivation, providing for easy reuse of

such components in different game types by only

modifying the activation rules.

 

EDIT:

 

This has links to his source code.

http://sertao3d.blogspot.com/2008/01/data-driven-game-development.html

 

His forum discussions.

http://www.jmonkeyengine.com/forum/index.php?topic=6980.0

http://www.jmonkeyengine.com/forum/index.php?topic=6980.15

 

Unfortunately the engine is in Java, but you might get some good ideas.

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

Code won't download for me. Says the gcore.zip file doesn't exist.

52t__nvidia.png nVidia 530M cpu.gif Intel Core i7 - 2.3Ghz 114229_30245_16_hardware_memory_ram_icon.png 8GB DDR3 RAM Windows7_Start.gif Windows 7 Ultimate (64x)

-----

IconVisualStudio16.png Visual Studio 2010 Ultimate google-Chrome.png Google Chrome PhotoshopLinkIndicator.png Creative Suite 5 icon28.gif FL Studio 10 MicrosoftOfficeLive.png Office 15

-----

csharp.png Expert cpp.png Professional lua_icon.png Expert BMX Programmer

-----

i-windows-live-messenger-2009.pngskype-icon16.pngaim_online.pnggmail.pngicon_48x48_prism-facebook.pngtunein-web.pngyahoo.giftwitter16.png

Link to comment
Share on other sites

Code won't download for me. Says the gcore.zip file doesn't exist.

 

Try this:

www.infoway-pi.com.br/erick/gcore.zip

 

I have to admit that his article has made me like object components a little more.

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

 

There was a component for each of the 3 "needs", and a Health component. Each component could talk to the other components by querying the player (parent of all 4 components) for the other using a Name

 

That's what I have above also. All a component has to call is GetComponent(component_name) and it'll find any component attached to the "game object" that that component is also attached to and return it.

 

 

Looking at that again, I'm thinking if you need to do the above, you may as well link the components together.

 

Yeah, with that system you'd have to include the headers of those classes in C++ into those components since you are using the type name. That's not decoupled enough I don't think. Events or virtual methods part of the Components class seem to really be the only way to keep these components "unknown" to each other. I prefer events since I think it's easier than having 1 giant switch in an OnMessage() virtual method, although the only issue with events is that there needs to be a way for components to bind to other components events and that can't happen until all components are added. I have solved that above, but I don't like it since if CheckDependencies() gets called more than once it can cause multiple binding of events. I might have to go to an OnMessage() virtual method, but not all that thrilled about that. I could also work out a way to see if a event handler is already bound and if so don't bind again. Haven't tried doing that before with the event system. Might be able to compare function pointers or something.

 

 

I liked the flexibility, but it seemed bloated

 

I do agree with this also, but I'm hoping that it pays off in the long run. I can vouch for the problem they say this design solves though. To many times have I got a good hierarchy structure and then want to make a gameplay design change when I'm 1/2 way in and realize that it's going to be a major overhaul or hack city and just lost interest in the game. This seems like it'll solve that.

Link to comment
Share on other sites

I'm curious as to what you mean by bloated. According to this it should be lean and fast.

 

 

http://gameprogrammingpatterns.com/component.html

 

 

This pattern goes hand in hand with the Structure of Arrays pattern. Components split a monolithic object into separate smaller objects for each domain being used. If you get all of the components of the same type and put them in an array, now you’ve got them laid out in memory just the way the Structure of Arrays pattern needs to improve your game’s performance.

 

This is a rare hat trick in architecture: your code is both more maintainable and faster.

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

The way that guy is doing his communication between components is by storing actual derived component pointers in other component classes. Doing it this way wouldn't be bloated but it's not a good separation either since you actually store a pointer to the child component objects within other components. Then he's passing them in constructors or with set methods. This completely goes against decoupling which could be looked at as one of the main reasons for even doing this design.

 

In order to make the "correct" separation "bloat" needs to be added to how components work. Like in my example above there is "bloat" to allow components to get other components without directly including a specific derived component. Then an event system is implemented in order for components to communicate between each other without knowing the specific derived component type. This can be looked at as "bloat" also.

 

If we followed that website the components aren't really plug and play because they are looking specifically for certain types. With the "bloated" design types aren't needed and only string keys are required. Both for components and events. That helps make the components decoupled as I could use 3 different components as long as I identify them with the same name and they have the same events. The actual class name to all 3 could be completely different and the method I use above still works. If we use the approach of communication that website uses and I use a different component from someone else that kind of does the same thing as others, I would have to go into my components class and change the type name and include that types header.

 

Let's say you, me, and tyler all create a FPSMovement component. We each implement different features like maybe you have head bobbing, tyler has ducking, and I have peaking around corners. You call your actual component class FPSHeadBobComponent, tyler calls his FPSDuckComponent, and I call mine FTPCornerPeakComponent. Now I have a component that needs data from a FPS movement type component. With the websites method I would have to go into my component that requires this FPS stuff and edit the type so I can get your specific instance or each one. That's not really the idea behind component design so that's a no no. Ideally you shouldn't have to alter the insides of your component just because it's using a different class component. That's possible with the design I have above as long as each different instance exposes the same interface (or events/attribtues). So in the example of our 3 different style classes, I can have all 3 in my project and just plug and play any one to a game object and as long as they all 3 are identified with the same string name, it'll work.

 

Taking the example above one could make a separate disoriented FPS movement that happens after a flashbang goes off. As long as the interface between that and the normal fps control are the same, one could swap these components when the flashbang goes off on the fly and all components that have a reliance on the fps movement component will continue to work. Swapping on the fly like this is pretty cool. You could have many different behaviors that get swapped on the fly like this. Think of flying controls compared to fps walking controls. You can have 2 separate components to handle both, and as long as the events between them are the same and the name of each is the same, you can swap these components in and out of a game object based on if you are flying or on the ground and everything will continue to work in stride. That's amazing separation because now you don't have to have 1 main movement component that has to branch off logic based on what it's doing. The game object that has these components can now control what components it needs on the fly.

Link to comment
Share on other sites

 

In order to make the "correct" separation "bloat" needs to be added to how components work. Like in my example above there is "bloat" to allow components to get other components without directly including a specific derived component. Then an event system is implemented in order for components to communicate between each other without knowing the specific derived component type. This can be looked at as "bloat" also.

 

 

 

 

I think events are a logical method for sending messages to other components to preserve loose coupling. But if you need to check values from another component, or call its functions, the component is not independent and needs another component to function, as your CheckDependencies function shows.

 

So if you don't want to give a component too much information, why not use C# style interfaces as contracts, that the injected components must fulfill? Does C++ have an equivalent?

 

If you use this method, you can swap the required component for another dynamically.

 

EDIT:

Or perhaps this only works in C#?

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

But if you need to check values from another component, or call its functions, the component is not independent and needs another component to function, as your CheckDependencies function shows.

 

Yeah, from the way I see it not many components would truly be standalone. So you are right. However, how you expose these dependent components becomes the topic at hand then.

 

1) Directly place a child component pointer into the component that depends on it. Very straight forward and easy, but requires you to pass these dependent components directly to this component somewhere. Then this component has the actual class name of dependent component so if you wanted to try a different component you'd have to alter the containing component which isn't good. You could store pointers to just the base component class. You still have to pass in the pointer to that component somewhere. This would put the dependency checks on the person assembling the game object instead of the components checking while they run. I can see both good & bad there.

 

2) You can do the way I did it, where every component can query for every other component that share the same game object they are attached to and either use a message function or events.

 

3) You can use "interfaces" to determine the interface that a component is expecting from it's dependent components. This seems like a mix of 1 and 2. You could store pointers to that interface and shouldn't be that big of a deal.

 

 

I'll play around with that once. That might be a cool option.

 

C++ doesn't have interfaces. You can kind of simulate them by making pure virtual classes where the derived class needs to provide the body of a method though.

Link to comment
Share on other sites

If components can be added and removed during run time, then you would have to send a message to a component manager class, which in turn will tell all of its components what was removed.

 

Then for the components that are missing a dependency, we have two options:

 

1 A component that is a missing a dependency, tells the component manager to remove itself from the component list.

 

2 If components are not deleted when removed (they are still in the list, but are not updated, or rendered anymore) you can let the component continue to access its "missing" dependency, as if nothing happened.

 

As I don't know what should be the standard, perhaps it should be offered as a user selectable option for each component?

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

If components can be added and removed during run time, then you would have to send a message to a component manager class, which in turn will tell all of its components what was removed.

 

Would depend if the component is just swapped for another that is the same name (or has the same interface) because at that point the components shouldn't care and everything should just continue working.

 

 

I wouldn't suspect components would be removed completely at run-time but instead just swapped for other like components.

Link to comment
Share on other sites

Have a look at the article I linked to in comment #10. It makes Object Components go from cool, to very cool. :)

 

Dynamic Game Object Component System for Mutable behavior Characters

 

Also there are some behaviors you may want to turn on and off. For instance: sparkly effects, a twitch or a limp, a sound playing, a skill or ability earned or lost, a weapon equipped, armor that affects your stats and so on.

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

Yeah, I could add an attribute in the component class in the ctor for enabled or not. That way each component will by default have this attribute. Then the Update() method can first check if that attribute is enabled or not for the children and not call Update() if it's not enabled. That should give the result.

Link to comment
Share on other sites

That sounds great. This makes doing things like NPC AI logic stupidly easy, almost like a finite state machine, but in an "infinite" manner :P

52t__nvidia.png nVidia 530M cpu.gif Intel Core i7 - 2.3Ghz 114229_30245_16_hardware_memory_ram_icon.png 8GB DDR3 RAM Windows7_Start.gif Windows 7 Ultimate (64x)

-----

IconVisualStudio16.png Visual Studio 2010 Ultimate google-Chrome.png Google Chrome PhotoshopLinkIndicator.png Creative Suite 5 icon28.gif FL Studio 10 MicrosoftOfficeLive.png Office 15

-----

csharp.png Expert cpp.png Professional lua_icon.png Expert BMX Programmer

-----

i-windows-live-messenger-2009.pngskype-icon16.pngaim_online.pnggmail.pngicon_48x48_prism-facebook.pngtunein-web.pngyahoo.giftwitter16.png

Link to comment
Share on other sites

Hey Guys,

I found a few more articles with source that relate to this topic. If you are new to this kind of coding, they will increase your understanding.

 

 

 

This is really long, but explains how actions, states and entities can work together to make an engine that can be used again and again for different types of games. It ties in with the code Rick wrote.

 

Object-Oriented Game Design

A modular and logical method of designing games

http://www.devmaster.net/articles/oo-game-design/

 

 

 

This blog entry explains the actions, states and entity relationship the above article introduces in simpler terms and once you understand it, you will see how powerful this kind of system is.

 

Object-Oriented Game Design

http://gbgames.com/blog/2006/03/object-oriented-game-design/

 

 

Both articles have source, one is in C# and one C++. The monopoly example in C++ is more clear IMO, but both are worth a look.

 

 

 

This guy wrote the code for the article "Game Object Component System" - Chris Stoy, from Game Programming Gems 6. It is mislabeled in the link below, as being from GPG 5. This is a C++ implementation.

http://www.unseen-academy.de/componentSystem.html

 

 

 

And finally a GameDev page of links:

component-based design resources

http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=443615&cmonth=9&cyear=2008

Win 7 Pro 64 bit

AMD Phenom II X3 720 2.8GHz

GeForce 9800 GTX/9800 GTX+

4 GB RAM

Link to comment
Share on other sites

Guest Red Ocktober

while this is an interesting topic... i find it has little practical value... sorta like theoretical metaphysics... :)

 

everything discussed above can be done in much simpler way, by a much more direct approach... and as such, in my opinion, is more relevant to someone who is working to get a game done... as opposed to someone who has lots of time on their hands in which to ponder the consciousness of the universe... :)

 

to me... this sorta 'science' is analguous to the study of rube-goldberg mechanical theory... ;)

 

 

--Mike

Link to comment
Share on other sites

But games have been and continue to be made this way, so it is being used in practice today in the industry. Some of those articles talk about a few games that have been made with this design. When a person starts getting into a medium to large game things become unmanageable very quickly. That's what this design tries to solve. It breaks things down to very small isolated (to some extent) components that become easier to maintain/create.

 

I have done the very simple designs in the past, but when your code base grows to thousands of lines (and it will most likely), it gets harder to make changes without major hacking and/or just giving up because it's to much of a pain. I haven't implemented this system yet, but I do agree with the reason for it because I've ran into the same issues in the past. That being said this isn't really for anything like a tetris or breakout clone although you could, it's probably overkill for that type of game.

 

I am excited to try and implement this with my zombie game, but I haven't had much time for programming it lately. No doubt it's a different way of thinking and will be hard at first to get right, but will be fun and interesting to try.

 

I do think this system would be best supported in C# where specific components are in their own DLL's. Then you just reference what component dll you need to build a game object. Could be done in C++ that way also, but C# just makes it easier to make and use dll's.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...