I was thinking of how to implement overriding of behaviors in a component based entity system. A concrete example, an entity has a heath component that can be damaged, healed, killed etc. The entity also has an armor component that limits the amount of damage a character receives.
Has anyone implemented behaviors like this in a component based system before?
How did you do it?
If no one has ever done this before why do you think that is. Is there anything particularly wrong headed about overriding component behaviors?
Below is rough sketch up of how I imagine it would work. Components in an entity are ordered. Those at the front get a chance to service an interface first. I don't detail how that is done, just assume it uses evil dynamic_cast
s (it doesn't but the end effect is the same without the need for RTTI).
class IHealth
{
public:
float get_health( void ) const = 0;
void do_damage( float amount ) = 0;
};
class Health : public Component, public IHealth
{
public:
void do_damage( float amount )
{
m_damage -= amount;
}
private:
float m_health;
};
class Armor : public Component, public IHealth
{
public:
float get_health( void ) const
{
return next<IHealth>().get_health();
}
void do_damage( float amount )
{
next<IHealth>().do_damage( amount / 2 );
}
};
entity.add( new Health( 100 ) );
entity.add( new Armor() );
assert( entity.get<IHealth>().get_health() == 100 );
entity.get<IHealth>().do_damage( 10 );
assert( entity.get<IHealth>().get_health() == 95 );
Is there anything particularly naive about the way I'm proposing to do this?
IHealth
andIKnockback
. It would not make sense to join those two components in a single class hierarchy. Multiple inheritance is always troublesome I had considered having Shield use a proxy member class that derives fromIHealth
and then forwards all calls to Shield. With that implementation technique there is no MI at the expense of an extra non-virtual method call (which the optimizer may be able to inline). In either case the API (add
,get
,next
, etc) is the same. \$\endgroup\$