我正在尝试创建一种机制,用一个Spell对象填充 vector ,每个对象都有自己的名称,然后选择带有cin输入的咒语并将其投射到目标上。最好的方法是什么?这就是我所做的,但是,如果该咒语具有多种咒语效果,该怎么办?

//Spell.h
class Spell
{
public:
    enum e_spellType //enum with all spells
    {
        FIREBALL = 1,
        FROSTBOLT
    };

    enum e_spellEffect //enum with different effects
    {
        DAMAGE = 1, //for damaging effect
        SLOW
    };

    Spell(e_spellEffect effect);

    void returnSpellEffect(Unit* target);
    //getters here
    string getSpellName() const { return m_SpellName; }
    int getSpellValue() const { return m_SpellValue; }
    int getCooldown() const { return m_Cooldown; }
    int getManaCost() const { return m_ManaCost; }
protected:
    string m_SpellName;
    int m_SpellValue;
    int m_Cooldown;
    int m_ManaCost;
    int m_SpellID;
    e_spellEffect m_spellEffect;
    e_spellType m_spellType;
};

Spell::Spell(e_spellType type)
{
    m_spellType = type;
    switch (m_spellType)
    {
    case 1: //Fireball
        m_SpellValue = 35;
        m_ManaCost = 40;
        m_Cooldown = 2;
        m_spellEffect = DAMAGE;
    case 2: //Frostbolt
        m_SpellValue = 30;
        m_ManaCost = 40;
        m_Cooldown = 2;
        m_spellEffect = SLOW;
    }
}

void Spell::returnSpellEffect(Unit * target)
{
    switch (m_SpellEffect)
    {
    case DAMAGE:
        target->takeDamage(m_SpellValue);
        break;
    case SLOW:
        target->setDamage(0.5); //modifies Unit object's attack dmg to half
        break;
    default:
        break;
    }
}

//Game.h
class Game
{
public:
    void enemyCombat();

protected:
    Player *player;
    vector<Enemy*> enemyList;
    vector<Spell*> spellList;

};

void Game::enemyCombat()
        {
//after you  have chosen a target from enemyList (enemyList[target])
spellList.push_back(new Spell(FIREBALL));
spellList.push_back(new Spell(FROSTBOLT));
    cout << "Choose a spell to cast:" << endl
            << "1. Fireball" << endl
            << "2. Frostbolt" << endl;
            int spellChoice = 0;
            cin >> spellChoice;
            spellList[spellChoice-1]->returnSpellEffect(enemyList[target]);
}

如何使整个事情变得更抽象,以使一个咒语可以使用多个咒语效果?

最佳答案

考虑使用多态性。如果您具有虚函数doSpellEffects,则可以在基类中实现“常规”逻辑,而在其他类中针对特定咒语或咒语类别实现更专门的逻辑。

class Spell
{
public:
    // Copying disabled to avoid slicing.
    Spell(const Spell&) = delete;
    Spell& operator=(const Spell&) = delete;
    virtual ~Spell() = default;

    enum e_spellType { /*...*/ };
    // TBD whether e_spellEffect belongs in Spell or SimpleSpell.

    // Factory function:
    static std::unique_ptr<Spell> create(e_spellType spellType);

    const std::string& getSpellName() const noexcept { return m_SpellName; }
    int getCooldown() const noexcept { return m_Cooldown; }
    int getManaCost() const noexcept { return m_ManaCost; }

    virtual void doSpellEffects(Unit* target) = 0;

protected:
    Spell(e_spellType spellType) :
        m_spellType(spellType), m_SpellName(),
        m_Cooldown(0), m_ManaCost(0) {}

    e_spellType m_spellType;
    std::string m_SpellName;
    int m_Cooldown;
    int m_ManaCost;
};

class SimpleSpell : public Spell
{
public:
    SimpleSpell(e_spellType spellType);
    void doSpellEffects(Unit* target) override;

    int getSpellValue() const { return m_SpellValue; }
protected:
    e_spellEffect m_spellEffect;
    int m_SpellValue;
};

class WarlocksRay : public Spell
{
public:
    WarlocksRay() : Spell(WARLOCKS_RAY, "Warlock's Ray") {}
    void doSpellEffects(Unit* target) override;
};
void WarlocksRay::doSpellEffects(Unit* target)
{
    // Two effects!
    target->takeDamage(5);
    target->stun();
}

// The factory function that creates all spells:
std::unique_ptr<Spell> Spell::create(e_spellType spellType) {
    switch(spellType) {
    case FIREBALL:
    case FROSTBOLT:
        return std::make_unique<SimpleSpell>(spellType);
    case WARLOCKS_RAY:
        return std::make_unique<WarlocksRay>();
    }
    // Invalid spellType: Log an error? Throw an exception? Just return nullptr?
    throw std::invalid_argument("Bad spellType in Spell::create");
}

您可以通过其他方式使用子类,这可能值得也可能不值得:
  • 代替switch中的SimpleSpell::doSpellEffects,为每种常见效果类型创建类,例如DamageSpellSlowSpell
  • 如果“冷却时间”和/或“法力消耗”机制可能不适用于所有咒语,请将这些成员和相关逻辑从Spell中移到NormalCastingSpell类或某些东西中,该类将介于Spell和层次结构中的其他类之间。
  • 甚至可以为每个单独的咒语创建一个类。在某些情况下,这可能仅继承SimpleSpellDamageSpell等,并且它需要定义的唯一成员是正确设置所有数据成员的构造函数。
  • 关于c++ - 我应该如何在文字RPG中称呼玩家咒语?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56816917/

    10-13 09:08