ところが、そのままではゲーム中に登場する様々なキャラクターはお互いを継承元の基底クラスでしか認識できません。
この問題を解決する方法の一つとしてダブルディスパッチがあります!
<以下例文>
// キャラクター基底クラス
class Character
{
public:
virtual void Dispatch(Character& _character) = 0;
virtual void Collide(Player& _player) = 0;
virtual void Collide(Enemy& _enemy) = 0;
virtual void Collide(BossEnemy& _bossEnemy) = 0;
};
// キャラクター基底クラスを継承したプレイヤークラス
class Player : public Character
{
public:
virtual void Dispatch(Character& _character);
virtual void Collide(Player& _player);
virtual void Collide(Enemy& _enemy);
virtual void Collide(BossEnemy& _bossEnemy);
};
class Enemy : public Character { /* 省略 */ };
class BossEnemy : public Character { /* 省略 */ };
// ディスパッチ関数
void Player::Dispatch(Character& _character)
{
_character.Collide(*this);
}
※Collide関数にはそれぞれの引数のキャラクターに対する衝突判定の処理を書きます。
※エネミークラス、ボスクラスにもプレイヤークラスと同様の関数が必要になります。
・使い方の説明として。
まず、Character*型にアップキャストされたPlayerクラスc1と、何だか分からないキャラクターc2があるとします。
それに対してc1->Dispatch(*c2)を呼ぶと、Player::Dispatch(Character&)が呼ばれます。
その関数内で引数として受け取ったc2のCollideを呼ぶと、Player::Dispatch()の中では*thisの型はPlayerなので、もしc2がEnemyクラスだった場合、Enemy::Collide(Player&)が呼ばれ、c2がBossEnemyクラスだった場合、BossEnemy::Collide(Player&)が呼ばれます。
これでc2は衝突判定の相手のc1がPlayer型であるという事が判明しました。
このようにオーバーロードされたCollide()によって、型情報を使わずに派生クラスを特定する事ができます。
ダブルディスパッチの欠点として、新しい派生クラスを作るたびに、そのクラス用のCollide()を基底クラスと派生クラスに追加する必要があるという点があるので注意しておいて下さい。
衝突判定で悩んでいる方は是非参考にしてみてください!!
では!
COMMENT