C++ Determine if class can use an object - text RPG game

前端 未结 4 1015
有刺的猬
有刺的猬 2021-01-25 18:58

I\'m facing with the following design problem:

TL;TD need to determine if Hero(class) can use specific object while there\'s many heroes implementations

I have

相关标签:
4条回答
  • 2021-01-25 19:29

    I'm thinking about using Visitor Pattern.

    Something like:

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

    Then the visitor looks like:

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

    Any suggestions regard to this idea?

    0 讨论(0)
  • 2021-01-25 19:36

    You could use dynamic_cast<>() to determine the type of your Hero pointer, like so:

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

    where HeroSubClass is the particular subclass of Hero that you want to check for (Warrior, etc.). If your Hero * is not a pointer to an object of class HeroSubClass, dynamic_cast will return nullptr, if it is, it will return a HeroSubClass *.

    Alternatively, you could just check the type of the Weapon * within use() for each HeroSubClass, and perhaps print out something like "Warrior cannot use Staff" if it's an object of the wrong class.

    0 讨论(0)
  • 2021-01-25 19:48

    You can use enum values to define weapon and hero's specific types.

    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.
    };
    

    and do same for weapons.

    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;
    };
    

    Now you can specify weapons for hero classes.

    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
    }
    
    0 讨论(0)
  • 2021-01-25 19:49

    I have simplified the example by removing everything that isn't necessary and generalized to the concept of Item. A weapon is a subclass of Item, as is a potion, a wand, a flux capacitor, whatever. The use method does whatever the Item does to target. A weapon will attempt to hit and damage target. A healing potion will heal target. A flux capacitor will either send target back in time or zap the expletive deleted out of them with 1.21 gigawatts.

    But everything is seen through the lens of Item. The invoking classes doesn't know what the item is, does, or what it did to target. target doesn't even know what was used on it, they just feel the effects. Nobody knows nothin' about the other objects outside of a simple, generic interface.

    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;
    };
    

    The point is the main classes are incredibly stupid. They simply provide a framework for much more detailed objects to do the detailed work. VorpalSword uses generic methods inherited from Weapon and Item to see if it hit target, not knowing that target is in fact a HugeRedDragon instance, and if it hit assigns damage and then does the specific things a VorpalSword does like checking for lopped off limbs.

    And all Hero saw was item->use(target).

    0 讨论(0)
提交回复
热议问题