Первый привет:) Это будет долгая поездка, так голая со мной, если хотите, я обещаю, что это будет весело:)
Я работаю над системой элементов для игры, которую мы делаем аналогично старым классическим зверским званиям Resident. В настоящее время я реализую элементы, объединяющие, где вы комбинируете разные элементы друг с другом, чтобы получить что-то новое. Осложнения возникают из-за того, что существуют предметы, которые имеют более одного уровня трансформации, и более одного помощника для каждого уровня. Позвольте мне уточнить, допустим, что у нас есть зеленая, красная и синяя травы. Вы не можете комбинировать красный + синий, однако вы можете комбинировать G + B, чтобы получить GreenBlueHerb, или G + R, чтобы получить GreenRedHerb, теперь, если вы объедините любой из этих результатов с синей травой, вы получите GreyHerb. Как вы видите из этого примера, есть 2 уровня трансформации для зеленой травы, так как она достигает первого уровня, есть два возможных помощника (красный | синий), с этого момента идет на второй уровень, там только один помощник (синий).
Итак, я придумал интересное дерево, охватывающее все возможности, которые идут вниз nLevels, а не только 2, тем больше уровни сложнее дерева, посмотрите на этот пример из трех уровней, форма треугольника, которую вы видите в середине, представляет элемент, а другие цветные фигуры вокруг него представляют собой возможные помощники для достижения следующего уровня:
Там много разных комбинаций, я мог бы сначала объединить свой предмет с синим, затем красный, затем зеленый или зеленый, затем красный, затем синий и т.д. Чтобы достичь моего финального уровня. Я придумал это дерево, представляющее все возможные комбинации:
(Числа справа - это #levels, слева - #nodes на каждом уровне). Но, как вы можете видеть, это избыточно. Если вы посмотрите на конечные узлы, все они должны быть едины, потому что все они ведут к одному и тому же окончательному результату, который представляет собой G + R + B. Для этой ситуации существует всего 7 возможных состояний, вот правильное дерево:
Это имеет большой смысл, обратите внимание на огромную разницу в количестве узлов.
Теперь мой вопрос: какова правильная структура данных для этого? - Я почти уверен, что для этого нет встроенного, поэтому мне нужно будет сделать свой собственный, который я действительно сделал, и мне удалось заставить его работать, но с проблемой. (Одна вещь, о которой стоит упомянуть, это то, что я получаю информацию о узлах из файла XML, по информации, я имею в виду itemRequired, чтобы достичь уровня node/, и что будет именем моего элемента в что node, например: для зеленой травы, чтобы достичь состояния RedGreenHerb, для нее требуется "a RedHerb, когда эта комбинация происходит, имя" GreenHerb "изменится на" RedGreenHerb ", и если вам интересно, что происходит с RedHerb, оно просто исчезает, мне больше не нужно) вот мои структуры данных:
public struct TransData
{
public TransData(string transItemName, string itemRequired)
{
this.transItemName = transItemName;
this.itemRequired = itemRequired;
}
public string transItemName;
public string itemRequired;
}
public class TransNode
{
public List<TransNode> nodes = new List<TransNode>();
public TransData data;
public TransNode(TransNode node): this(node.data.transItemName, node.data.itemRequired) { }
public TransNode(string itemName, string itemRequired)
{
data = new TransData(itemName, itemRequired);
}
}
public class TransLevel
{
public List<TransNode> nodes = new List<TransNode>();
public TransNode NextNode { get { return nodes[cnt++ % nodes.Count]; } }
int cnt;
}
public class TransTree
{
public TransTree(string itemName)
{
this.itemName = itemName;
}
public string itemName;
public TransNode[] nodes;
public List <TransLevel> levels = new List<TransLevel>();
// other stuff...
}
Позвольте мне объяснить: TransTree
на самом деле является базой node, которая имеет название элемента при запуске ( GreenHerb для ex), дерево имеет несколько уровней (строки в черный, который вы видите на рисунках), каждый уровень имеет несколько узлов, каждый node несет с собой новые данные элемента и несколько узлов, которые указывают на это (дочерние узлы). Теперь вы можете спросить, в чем состоит необходимость размещения списка узлов в классе TransTree
? - Я отвечу, что после того, как я покажу вам, как я получаю данные из своего XML файла:
public TransTree GetTransItemData(string itemName)
{
var doc = new XmlDocument();
var tree = new TransTree(itemName);
doc.LoadXml(databasePath.text);
var itemNode = doc.DocumentElement.ChildNodes[GetIndex(itemName)];
int nLevels = itemNode.ChildNodes.Count;
for (int i = 0; i < nLevels; i++) {
var levelNode = itemNode.ChildNodes[i];
tree.levels.Add(new TransLevel());
int nPaths = levelNode.ChildNodes.Count;
for (int j = 0; j < nPaths; j++) {
var pathNode = levelNode.ChildNodes[j];
string newName = pathNode.SelectSingleNode("NewName").InnerText;
string itemRequired = pathNode.SelectSingleNode("ItemRequired").InnerText;
tree.levels[i].nodes.Add(new TransNode(newName, itemRequired));
}
}
tree.ConnectNodes(); // pretend these two
tree.RemoveLevels(); // lines don't exist for now
return tree;
}
Здесь образец XML, чтобы все было ясно: ItemName- > Level- > Path (это не что иное, как node) → Данные пути
<IOUTransformableItemsDatabaseManager>
<GreenHerb>
<Level_0>
<Path_0>
<NewName>RedGreenHerb</NewName>
<ItemRequired>RedHerb</ItemRequired>
</Path_0>
<Path_1>
<NewName>BlueGreenHerb</NewName>
<ItemRequired>BlueHerb</ItemRequired>
</Path_1>
</Level_0>
<Level_1>
<Path_0>
<NewName>GreyHerb</NewName>
<ItemRequired>BlueHerb</ItemRequired>
</Path_0>
</Level_1>
</GreenHerb>
</IOUTransformableItemsDatabaseManager>
Теперь проблема с этим заключается в том, что узлы не связаны друг с другом, так что, что это значит? Ну, если элемент занимает определенный путь до определенного уровня, то нам, разумеется, не нужно сохранять другие пути, которых это не берет, поэтому зачем хранить их в памяти? (там нет перехода назад, как только вы пойдете по пути, что вы обязаны следовать этому пути и никогда не оглядываться назад) Что бы я хотел иметь, это когда я вынимаю node, все остальные узлы под ним тоже будет падать, что имеет смысл, но в настоящее время я так делаю это примерно так:
Как вы можете видеть, узлы не связаны, что их удерживает уровень! это означает, что в настоящее время мне не удается вынуть node таким образом, чтобы он вынимал все его дочерние узлы. (Выполнение этого без того факта, что узлы связаны очень тяжело, и может сильно ухудшить производительность). Это приводит нас к:
tree.ConnectNodes();
tree.RemoveLevels();
Сначала подключаю узлы, а затем удаляю уровни? почему, потому что, если я этого не сделаю, то каждый node имеет две ссылки на него: одну из ее родительской node и другую с текущего уровня.
Теперь ConnectNode
на самом деле для длинного дерева, которое я показал, а не для оптимизированного с 7 состояниями:
// this is an overloaded version I use inside a for loop in ConnectNodes()
private void ConnectNodes(int level1, int level2)
{
int level1_nNodes = levels[level1].nodes.Count;
int level2_nNodes = levels[level2].nodes.Count;
// the result of the division gives us the number of nodes in level2,
// that should connect to each node in level1. 12/4 = 3, means that each
// node from level1 will connect to 3 nodes from level2;
int nNdsToAtch = level2_nNodes / level1_nNodes;
for (int i = 0, j = 0; i < level2_nNodes; j++)
{
var level1_nextNode = levels[level1].nodes[j];
for (int cnt = 0; cnt < nNdsToAtch; cnt++, i++)
{
var level2_nextNode = levels[level2].nodes[i];
level1_nextNode.nodes.Add(new TransNode(level2_nextNode));
}
}
}
Это, в конечном счете, то, что я хочу иметь на своем другом дереве, но я не знаю, как это сделать. Я хочу связать узлы и сформировать второе дерево, которое я показал, что относительно проще, чем 4 уровня для ex, я даже не мог соединить узлы в краске! (когда я пробовал 4 уровня)
Если вы посмотрите на него, вы найдете некоторое сходство с двоичными числами, здесь мое дерево в двоичной форме:
001
010
100
011
101
110
111
Каждый '1' представляет собой фактический элемент, '0' означает пустой. Из моего дерева, '001' = Синий, '010' = Зеленый, '100' = Красный, '011' означает Зеленый + Синий,... '111' = Серый (конечный уровень)
Итак, теперь я все объяснил, во-первых: мой подход правильный? Если нет, то что есть? Если да, то какова структура данных, которую я мог бы использовать/сделать для достижения этой цели? и если структуры данных, которые я придумал, находятся на их месте, как я могу хранить данные из файла XML в своей структуре данных так, чтобы они соединяли узлы вместе, поэтому всякий раз, когда я вынимаю node, он извлекает его узлы с ним?
Большое спасибо за вашу помощь и терпение:)
EDIT: Интересно отметить, что вся эта система предназначена для предметов, которые встречаются только один раз на протяжении всей игры (получает один раз). Вот почему, когда я беру путь, я удаляю его из memeory, а также всякий раз, когда я беру элемент, я удаляю его запись из базы данных, потому что я больше не буду встречаться с ней.
РЕДАКТИРОВАТЬ: Обратите внимание, что я не только представляю свои объекты только с помощью строк, у них много других свойств. Но в этой ситуации меня волнуют только их имена, поэтому я имею дело со строками.