Выбор дизайна в отношении манипулирования основным циклом из дерева графа
Я создаю простую игру для практики программирования на больших проектах, и в настоящее время я застрял на перекрестке.
В игре используется древовидная структура для хранения всех сущностей игры, все они исходят из базового класса, называемого 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
тип данных.