2016-12-13 8 views
-2

Я занимаюсь разработкой в ​​ролевой игре C++ roguelike. Теперь я выполняю систему квестов, и идея состоит в том, что есть абстрактный класс Quest, каждый новый квест (например, «Kill lats for guard») - это новый класс, и каждый квест содержит некоторые цели абстрактного класса Objective, который нам нужно сделать, один одним. И это работает нормально. Проблема состоит в том, что цели отличаются друг от друга и, например,Идея реализации полиморфизма

class KillMonstersWhole : public Objective 
{ 
    vector<KillMonster> vector_of_monsters_to_kill; 
public: 
    virtual void ShowObjectiveStatus(); 
    virtual void CheckIfConditionsFilled(); 
    virtual vector<KillMonster> GetMonstersToKill() { return vector_of_monsters_to_kill; } 
    virtual vector<KillMonster>::iterator GetBeginOfMonstersToKill() { return vector_of_monsters_to_kill.begin(); } 
    virtual vector<KillMonster>::iterator GetEndOfMonstersToKill() { return vector_of_monsters_to_kill.end(); } 
    KillMonstersWhole(int amount, KillMonster first, ...); 
}; 

Этот класс нужны определенные функции, такие как GetMonsterToKill() и т.д. (который наследуется от абстрактной цели), но, например, что

class ReachXY : public Objective 
{ 
    int x, y; 
    string status_text; 
public:  
    virtual void ShowObjectiveStatus(); 
    virtual void CheckIfConditionsFilled(); 
    ReachXY(int x, int y, string status_text); 
}; 

не нужен, и я понятия не имею, как получить способ реализовать его, не создавая пустых функций, которые ничего не делают, и что будет мусор моего кода. Я хотел бы сохранить наследование от одного абстрактного класса, потому что он работает хорошо - в классе Quest у меня есть только вектор объектов Objective *. Я знаю, что могу, например. создайте vector_of_monsters_to_kill в базовом классе Objective, а затем создайте непустую виртуальную функцию, но ReachXY займет дополнительное, не пригодное для использования место. Когда я делаю эти функции не виртуальными и помещаю их в класс KillMonstersWhole, я бы потерял способность получить это с помощью полиморфных указателей Objective *. Есть ли какой-нибудь умный способ сделать это? Объективные и Quest классы для сделать все ясно:

class Objective 
{ 
protected: 
    bool conditions_fullfilled; 
    OBJECTIVE_ID id; 
public: 
    Objective() {} 
    bool GetConditionsState() { return conditions_fullfilled; } 
    virtual void ShowObjectiveStatus() = 0; 
    virtual void CheckIfConditionsFilled() = 0; 
    virtual vector<KillMonster> GetMonstersToKill() = 0; 
    virtual vector<KillMonster>::iterator GetBeginOfMonstersToKill() = 0; 
    virtual vector<KillMonster>::iterator GetEndOfMonstersToKill() = 0; 
    virtual OBJECTIVE_ID GetID() { return id; } 
    virtual ~Objective() {} 
}; 

class Quest 
{ 
protected: 
    string name; 
    vector<Objective*> objectives_list; 
    vector<Objective*>::iterator quest_state; 
public: 
    Quest() {} 
    vector<Objective*>::iterator GetQuestState() { return quest_state; } 
    OBJECTIVE_ID GetQuestStateID(); 
    vector<Objective*> GetObjectivesList() { return objectives_list; } 
    virtual void CheckRaiseQuestState(); 
    virtual void ShowDescription() = 0; 
    virtual ~Quest() {} 
}; 
+0

Полиморфизм основан на единых контрактах _interface. –

ответ

1

Keep высшие классы уровня глупы и использовать классы нижнего уровня, чтобы сделать детальную работу. Если другой класс должен знать статус квеста должен быть очень общий интерфейс, как

std::string Objective::getStatus() 

, что для классической Rat-Killing миссии будет реализован что-то вроде

std::string RatKiller::getStatus() 
{ 
    switch (ratcounter)   
    { 
     case 0: 
      return "Rodents Of Unusual Size? I KNOW they don't exist. Heh heh heh." 
     case 1: 
      return "You need to kill 1 more rat!" 
     default: 
      return "You need to kill " + std::to_string(ratcounter) + " more rats!" 
    } 
} 

Если героя Цель состоит в том, чтобы собрать один бурбон, один шотландский и один пиво, getStatus смотрит на инвентарь героя, находит бурбон и скотч и возвращает «Торогуд, разрушитель все еще нуждается в одном пиве!»

Таким образом, верхний уровень не дает smurf объекту, он просто отображает строку.

Я использую строку здесь, потому что она не получает гораздо больше, чем строка, но вы можете использовать структуру статуса, которая является общей для всех.

struct status 
{ 
    std::string message; 
    double percentComplete; 
    std::vector<std::string> othernotes; 
    // more general information here 
}; 

Если герой совершает действие (например, убивает монстра), передать эту информацию в цель, и цель будет обновлять свое внутреннее состояние соответственно.

void RatKiller::updateStatus(Action & actionPerformed) 
{ 
    if (actionPerformed.getActionType() == KilledRat) 
    { 
     if (ratcounter > 0) 
     { 
      ratcounter--; 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^