Выбор дизайна в отношении манипулирования основным циклом из дерева графа

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

В игре используется древовидная структура для хранения всех сущностей игры, все они исходят из базового класса, называемого TreeNode, который реализует некоторые базовые функции, такие как присоединение и отсоединение детей от себя, а также их положение в 2D-мире.

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

Мой вопрос заключается в том, как бы я реализовал это достойным образом, чтобы не превратить мои усилия по изоляции кода в кровавую массу? Я думал о создании нового класса с членом std::function, который я могу запрограммировать, чтобы делать то, что я хочу, но этот способ означал бы полное нарушение инкапсуляции кода, передав ему ссылку на мой мастер-класс, который содержит ВСЕ данные во всей игре.

Столкновение в настоящее время реализовано примерно так:

std::vector<std::pair<&TreeNode, &TreeNode>> vCollision;
MasterNode.checkCollision(vCollision);

checkCollision вызывается со ссылкой на вектор, вызывает рекурсивные проверки коллизий на остальной части графа и заполняет вектор парами разных сущностей, которые столкнулись. (это в цикле обновления.) Мне также нужно выяснить способ вызова указанной std::function из этого списка, так как указатели на базовый класс не будут иметь доступа к членам производных классов.

1 ответ

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

Поскольку у вас работает дерево, выделите тип данных в параметр шаблона.
Например, учитывая узел:

struct Tree_Node
{
  struct Tree_Node * left_subtree;
  struct Tree_Node * right_subtree;
  Some_Data_Type     node_data;
};

Вы можете выделить тип данных, используя шаблоны:

template <class Node_Data_Type>
struct Tree_Node
{
  struct Tree_Node * left_subtree;
  struct Tree_Node * right_subtree;
  Node_Data_Type     node_data;
};

Вы бы объявили узел дерева следующим образом:

struct Player_Data;
Struct Moves_Data;
struct Tree_Node<Player_Data>; // For a tree of Player_Data
struct Tree_Node<Moves_Data>; // For a tree of Moves_Data

Альтернативой является использование наследования для данных узла.

struct Node_Data_Base
{
   virtual bool is_equal(Node_Data_Base * p_node) const = 0;
   virtual bool is_less(Node_Data_Base * p_node) const = 0;
   bool operator==(Node_Data_Base * p_node) const
   {
     return is_equal(p_node);  // Dispatch to child.
   }
   bool operator<(Node_Data_Base * p_node) const
   {
     return is_less(p_node); // dispatch to child.
   }
};

struct Tree_Node_Inheritance
{
  struct Tree_Node * left_subtree;
  struct Tree_Node * right_subtree;
  Node_Data_Base *   p_data;
};

Кроме того, просмотрите std::map тип данных.

Другие вопросы по тегам