コンポーネントベースのエンティティシステムで動作のオーバーライドを実装する方法を考えていました。具体的な例として、エンティティには、ダメージ、回復、殺されるなどのヒースコンポーネントがあります。エンティティには、キャラクターが受けるダメージの量を制限する鎧コンポーネントもあります。
これまでにコンポーネントベースのシステムでこのような動作を実装したことはありますか?
どうやってやったの?
誰もこれまでにこれをしたことがないのなら、なぜそうだと思いますか? コンポーネントの動作をオーバーライドすることに特に問題があることはありますか?
以下は私がそれがうまくいくと想像する方法の大まかなスケッチです。エンティティのコンポーネントは順序付けられています。最前線のユーザーは、最初にインターフェースのサービスを受ける機会を得ます。それがどのように行われるかについては詳しく説明しません。悪意のあるdynamic_cast
sを使用すると仮定します(実際は使用しませんが、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 );
私がこれを行うことを提案している方法について特にナイーブなものはありますか?
IHealth
とを実装したいのではないかと心配しましたIKnockback
。これら2つのコンポーネントを単一のクラス階層に結合することは意味がありません。多重継承は常に厄介な問題であり、シールドからIHealth
すべての呼び出しを派生させてシールドに転送するプロキシメンバークラスをシールドに使用させることを検討していました。その実装手法では、追加の非仮想メソッド呼び出し(オプティマイザがインライン化できる場合がある)を犠牲にしてMIはありません。いずれの場合もAPI( 、add
、get
、next
など)が同じです。