Member 14157091 Ответов: 3

Реализация конечного автомата


Мой проект включает в себя класс BaseEntity, который делает базовые вещи, такие как рисование объекта на экране. У меня есть подкласс BaseEntity под названием Seeker, который заставляет объект BaseEntity идти в определенное место (через функцию, которая называется каждый кадр). У меня есть подкласс BaseEntity под названием Flee, который делает обратное. То, что я хочу сделать, - это создать объект BaseEntity, который будет действовать как искатель при инициализации, а после достижения пункта назначения я хочу изменить его поведение и действовать как беглец в течение короткого времени, а затем вернуться к поиску. Я думал о создании конечного автомата
  class state:public BaseEntity
{
public:
    virtual void onenter() = 0;
    virtual void update() = 0;
    virtual void onexit() = 0;
};


class seek : public state
{
public:
    void onenter() override;
    void update() override;
    void onexit() override;
};

class flee : public state
{
public:
    void onenter() override;
    void update() override;
    void onexit() override;
};

I am not sure how create my "player", where to put the piece of code which moves the player, how to make the tranzition between states, how to make make player2 aware of player1 state( once player1 reaches destination, player2 starts seeking and vice versa). My game will be pretty simple, only 2 states, which means I don't have to make it fully encapsulated or worry about 2 states running at the same time. I was thinking about using an enum/switch approach but I would like to do stuff while entering a state( like giving the player a specific colour to know what is he doing or just print a message), another problem is that I need to run onenter and onexit functions only once and I need to run update in a while(true){}

Что я уже пробовал:

Я попытался реализовать класс для каждого поведения, но я не знаю, как связать этот класс с объектом BaseEntity

3 Ответов

Рейтинг:
2

Rick York

Вам не нужен оператор switch-case, когда у вас есть доступные методы класса. Для каждой переменной, которую вы можете включить, объявите виртуальный метод, реализующий эту функциональность, и вызовите его. Тогда речь идет о том, чтобы определить объекты с помощью соответствующих методов.

Когда я сделал это, я обнаружил, что класс state нуждается в указателе на содержащий его объект, и, конечно же, объект нуждается в экземпляре класса state, который обычно находится через указатель. Вы можете реализовать методы OnEnterState и OnExitState, чтобы делать то, что подразумевают их имена. Чтобы изменить состояния или функции, вы уничтожаете один объект состояния, создаете новый и сообщаете объекту, что он имеет новое состояние.

Каждый раз, когда вы испытываете искушение использовать оператор switch-case, подумайте о создании виртуального метода, который устранит это решение для вас. Другими словами, если вы собираетесь сделать оператор switch, который выполняет действие на основе состояния, создайте виртуальный метод для класса state, который имеет специализированные реализации для каждого состояния вместе с реализацией по умолчанию, которая выполняет общую функциональность или вообще ничего не делает, если это необходимо.


Рейтинг:
1

RickZeeland

Может быть, этот вопрос CodeProject поможет: Государственный проектно-машина в C++[^]


Рейтинг:
0

Stefan_Lang

Ваши классы описывают государственную машину без if или switch, и это нормально. Однако вам нужно добавить виртуальные деструкторы! Теперь вам нужно только добавить одно состояние (начальное состояние) к каждому игроку и некоторые события, которые вызывают изменение состояния:

class player {
   std::unique_ptr<state> current_state;
public:
   player(std::unique_ptr<state> starting_state) : current_state(starting_state) {}
   void setState(std::unique_ptr<state> other_state) { current_state = other_state; }
   void onSwitch() { /* switch to other state */ }
   void onFlee() { current_state = new flee; }
   void onSeek() { current_state = new seek; }
};

Затем нужно вставить код, описывающий взаимодействие между игроками. Может быть класс arena он содержит игроков и контролирует, когда и как они (Интер)действуют:
class arena {
   player player1;
   player player2;
   int player1_score;
   int player2_score;
public:
   arena() : player1(new seek()), player2(new flee()) {}
   void startGame (); // starts a new game
   void nextTurn(); // generates (random) event(s) for the players
   int currentLeader(); // returns the player who is currently leading the scoreboard
};