How to use dynamic_cast efficiently?

120 views Asked by At

There is an abstract class Entity, and other classes like Player and Enemy are inherit from it. When game detects a collision between the entities, the following method is called:

    void handleCollision(Entity* ent1, Entity* ent2) {
        if (dynamic_cast<Player*>(ent1) || dynamic_cast<Player*>(ent2) &&
            dynamic_cast<Enemy*>(ent1) || dynamic_cast<Enemy*>(ent2)) {
            //player <-> enemy collision
        }
        else if (dynamic_cast<Player*>(ent1) || dynamic_cast<Player*>(ent2) &&
                 dynamic_cast<Projectile*>(ent1) || dynamic_cast<Projectile*>(ent2)) {
            //player <-> projectile collision
        }
        else if () {
            //...
        }
        else if() {
            //...
        }
    }

Each entity has unique behavior when colliding with another, which depends on the type of entity (Player, Enemy, etc), that's why I need to check every possible combination between entities as shown above. But I don't like the fact it creates a huge else if chain, where each entity is checked multiple times. Is there another way of doing it?

2

There are 2 answers

0
MatG On BEST ANSWER

Trying to expand Ben Voigt's comment about multiple virtual dispatch, something along the lines of:

void handleCollision(Entity* ent1, Entity* ent2)
{
  ent1->collide_with(ent2);
}

Where:

class Entity
{
 public:
  virtual void collide_with(Entity*) = 0; // Dispatcher

  virtual void handle_collision_with(Entity*) {}
  virtual void handle_collision_with(class Player*) {}
  virtual void handle_collision_with(class Enemy*) {}
  virtual void handle_collision_with(class Projectile*) {}
};


class Player : public Entity
{
public:
  virtual void collide_with(Entity* other) override
   {
    other->handle_collision_with(this);
   }

  virtual void handle_collision_with(Entity* other) override
   {
    // Unhandled entity
   }

  virtual void handle_collision_with(Player* other) override
   {
    // Handle collision player-player
   }

  virtual void handle_collision_with(Projectile* projectile) override
   {
    // Handle collision player-projectile
   }
};

class Enemy : public Entity
{
public:
  virtual void collide_with(Entity* other) override
   {
    other->handle_collision_with(this);
   }

  virtual void handle_collision_with(Enemy* other) override
   {
    // Handle collision enemy-enemy
   }

  virtual void handle_collision_with(Player* player) override
   {
    // Handle collision enemy-player
   }

  virtual void handle_collision_with(Projectile* projectile) override
   {
    // Handle collision enemy-projectile
   }
};

class Projectile : public Entity
{...}

source: a-polyglots-guide-to-multiple-dispatch

0
Ishara Priyadarshana On

Use a virtual function defined in Entity class to uniquely identify the derived class whether Player or Enemy. This will be a good practice to avoid any runtime errors as well.

 enum EntityType { Entity, Player, Enemy}

In the Entity class define a virtual function like this,

virtual EntityType getType (return Entity;)

and override the function in two classes accordingly.