【问题标题】:C++ Determine if class can use an object - text RPG gameC++判断类是否可以使用对象——文字RPG游戏
【发布时间】:2016-12-06 19:35:10
【问题描述】:

我面临以下设计问题:

TL;TD 需要确定 Hero(class) 是否可以使用特定的对象,而有很多 hero 实现

我有 3 个英雄类的子类,每个子类都可以使用特定的物品。

对于 Weapons.hpp,我有剑、锤、弩、弓、魔杖、法杖。

战士可以使用剑或锤 弓箭手可以使用弩或弓 巫师可以使用法杖或魔杖

还有 Hero 基类:

class Hero: public Entity{

public:
    Hero(std::string name, Gender gender, double damage, Point2d* location);
    ~Hero();
    virtual void move(int x, int y);
    virtual void damage(Entity* other); // Override
    virtual bool use(Potion* _potion);
    virtual bool use(Weapon* _weapon) = 0;
    virtual bool use(ShieldArmor* _shieldArmor) = 0;
    virtual bool use(BodyArmor* _bodyArmor) = 0;

private:
    std::string name;
    Gender gender;
    Weapon* weapon;
    ShieldArmor* shield_armor;
    BodyArmor* body_armor;
};

这是武器:

class Weapon: public Item{

public:
    Weapon(double damage, Point2d* location); 
    virtual ~Weapon();
    virtual double getDamage() const;
    virtual const Point2d* getLocation() const; 
    virtual const std::string toString() const;

private:
    Point2d* location;
    double damage; 
};

在游戏主界面中,我需要确定 Hero *h 是否可以在不向下施放的情况下使用特定物品。

所以我可以像这样使用它:

Hero *h;
Weapon * i;
// do something assign values
h->use(i);

【问题讨论】:

  • 有趣的事实:您不需要对所有事情都使用指针。如果您避免使用有利于静态分配、容器和引用的指针,通常会更好。
  • @user4581301 地图的输入是动态的。在从地图的输入中获取英雄类型后,我需要根据一些输入确定所有这些内容。
  • 在不了解武器使用规则的情况下,很难说解决问题的最佳方法。以老式 D&D 为例,您可以让 class Class 包含一个列出所有允许的武器类型的 std::set<weapontype> allowedWeapons 和一个 bool canUse(Weapon *) 方法,如果武器类型在 set 中,则返回 true。 class Weapon 需要一个 weapontype getType() 方法来支持这一点。所以class Cleric: public Class 会在攻击前初始化allowedWeapons({OneHandBlunt, TwoHandBlunt, ...})Heromyclass->canUse(weapon)

标签: c++ inheritance


【解决方案1】:

我通过删除所有不必要的内容来简化示例,并将其推广到Item 的概念。武器是物品的子类,药水、魔杖、磁通电容器等等也是如此。 use 方法执行 Itemtarget 所做的任何事情。武器会尝试击中并伤害target。治疗药水会治疗target。磁通电容器将及时发送target 或以 1.21 吉瓦消除其中删除的脏话。

但一切都是通过Item 的镜头看到的。调用类不知道该项目是什么,做什么,或者它对target 做了什么。 target 甚至不知道上面用了什么,他们只是感觉效果。除了简单的通用接口之外,没有人对其他对象一无所知。

class Item
{
public:
    enum types
    {
        whole lot of types go here.
        They are fairly broad categories, like knife, sword, two handed sword, 
        healing potion, wand, etc.
    };
    types getType()
    {
         return type;
    }
    virtual bool use(Entity * target) = 0;
private:
    types type;

};

class Hero: public Entity{

public:
    Hero(std::set<Item::type> & usable): usableItems(usable)
    ~Hero();
    bool use(Item* item,
             Entity * target)
    {
        // this is the magic. If the item's type is in the list of usable items,
        // the item is used on the target. They exact type of item or target
        // is not known. Polymorphism will take care of everything from here
        if (usableItems.find(item->getType()) != usableItems.end())
        {
            return item->use(target);
        }
        return false;
    }
private:
    std::set<Item::type> & usableItems;
};

关键是主要课程非常愚蠢。它们只是为更详细的对象提供了一个框架来完成详细的工作。 VorpalSword 使用继承自WeaponItem 的泛型方法来查看它是否击中target,不知道target 实际上是HugeRedDragon 实例,如果击中分配伤害然后执行特定操作VorpalSword 喜欢检查被砍断的肢体。

所有英雄看到的都是item-&gt;use(target)

【讨论】:

    【解决方案2】:

    您可以使用dynamic_cast&lt;&gt;() 来确定您的英雄指针的类型,如下所示:

    Hero *h;
    Weapon * i;
    // do something assign values
    if(dynamic_cast<HeroSubClass> != nullptr)
        h->use(i);
    

    其中HeroSubClass 是您要检查的Hero 的特定子类(Warrior 等)。如果您的Hero * 不是指向HeroSubClass 类对象的指针,则dynamic_cast 将返回nullptr,如果是,它将返回HeroSubClass *

    或者,您可以只检查每个 HeroSubClass 的 use()Weapon * 的类型,如果它是错误类的对象,可能会打印出类似“战士不能使用法杖”的内容。

    【讨论】:

      【解决方案3】:

      您可以使用enum 值来定义武器和英雄的特定类型。

      enum class HERO_TYPE{
         WARRIOR,
         ARCHER,
         WIZARD
      }
      
      class Hero: public Entity{
      
      public:
          Hero( std::string name, Gender gender, double damage, Point2d* location, HERO_TYPE type );
          ~Hero();
          virtual void move(int x, int y);
          virtual void damage(Entity* other); // Override
          virtual bool use(Potion* _potion);
          virtual bool use(Weapon* _weapon) = 0;
          virtual bool use(ShieldArmor* _shieldArmor) = 0;
          virtual bool use(BodyArmor* _bodyArmor) = 0;
      
      private:
          std::string name;
          Gender gender;
          Weapon* weapon;
          ShieldArmor* shield_armor;
          BodyArmor* body_armor;
          HERO_TYPE type; //define in subclasses.
      };
      

      对武器也是如此。

      enum class WEAPON_TYPE{
             SWORD,
             CROSSBOW,
             WAND
          }
      class Weapon: public Item{
      
      public:
          Weapon(double damage, Point2d* location, WEAPON_TYPE type); 
          virtual ~Weapon();
          virtual double getDamage() const;
          virtual const Point2d* getLocation() const; 
          virtual const std::string toString() const;
          WEAPON_TYPE get_type() { return this->type; }//getter
      
      private:
          Point2d* location;
          double damage;
          WEAPON_TYPE type;
      };
      

      现在您可以为英雄职业指定武器。

      void Hero::use(Weapon *i){
         if(!checkWeapon(i->get_type())) return;
      
        //...code...
      
      }
      
      bool Hero::checkWeapon(WEAPON_TYPE t){
        switch(this->type){
           case HERO_TYPE::WARRIOR:{
              if(t == WEAPON_TYPE::SWORD)
                  return true;
           }break;
      
           case HERO_TYPE::ARCHER:{
              if(t == WEAPON_TYPE::CROSSBOW)
                  return true;
           }break;
      
           //..all cases..
        }
      
        return false;//no hero-weapon matching
      }
      

      【讨论】:

        【解决方案4】:

        我正在考虑使用访客模式。

        类似:

        Hero * h;
        Item * i;
        Visitor v;
        // Assign some values
        h.accept(v,i);
        

        那么访客看起来像:

        visit(sword *p, warrior * w){
            w.use(p);
        }
        visit(wand *p, wizard * w){
            w.use(p);
        }
        visit(bow *p, archer * w){
            w.use(p);
        }
        

        关于这个想法有什么建议吗?

        【讨论】:

        • 强制代码知道Hero 和武器是什么,让您重新回到必须施法的状​​态。可行,但不是特别好的解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多