C++ 确定类是否可以使用对象 - 文本 RPG 游戏

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

本文关键字:对象 文本 RPG 游戏 可以使 是否 C++      更新时间:2023-10-16

>我面临以下设计问题:

TL;TD需要确定Hero(类)是否可以在有许多英雄实现的情况下使用特定对象

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

对于武器.hpp,我有剑,锤子,十字弓,弓,魔杖,法杖。

战士可以使用剑或锤子 弓箭手可以使用弩或弓 向导可以使用法杖或魔杖

有英雄基类:

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

我通过删除所有不必要的内容并推广到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->use(target).

您可以使用dynamic_cast<>()来确定 Hero 指针的类型,如下所示:

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 *的类型,如果它是错误职业的对象,则可以打印出类似"战士无法使用法杖"之类的内容。

您可以使用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
}

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

像这样:

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

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