Я пытаюсь создать соседей моего искателя пути, но при этом исходный путь (путь) синего цвета также закрывается. Я пробовал переключать порядок спавна, но это, похоже, не решает проблему. Совершенно новичок в Unity и был бы признателен за любое понимание того, как я могу создать путь к соседям, не теряя исходный синий путь.
Получение соседей пути; путь нереста + соседи
for (int i = 1; i < path.Count; i++)
{
var pathCellPosition = path[i];
pathCellPosition.Position = new Vector3(pathCellPosition.Position.x, pathPrefab.transform.position.y, pathCellPosition.Position.z);
List<Node> neighbours = GetNeighbours(pathCellPosition);
var p = Instantiate(pathPrefab, pathCellPosition.Position, Quaternion.identity, PathCells);
foreach (Node n in neighbours)
{
neighbourPrefab.GetComponentInChildren<Text>().text = n.Cost.ToString();
Instantiate(neighbourPrefab, n.Position, Quaternion.identity, p.transform);
}
}
Плитки вокруг теперь появляются, но при применении того же решения для реализации соседей соседей кажется, что это вызывает перекрытие с исходными соседними узлами.
Изменения кода:
HashSet<Node> visitedNodes = new HashSet<Node>();
for (int i = 1; i < path.Count; i++)
{
var pathCellPosition = path[i];
visitedNodes.Add(path[i]);
pathCellPosition.Position = new Vector3(pathCellPosition.Position.x, pathPrefab.transform.position.y, pathCellPosition.Position.z);
List<Node> neighbours = GetNeighbours(path[i]);
int fCost = DistanceFromStart(pathCellPosition) + HCostDistanceFromEndNode(pathCellPosition) + pathCellPosition.Cost;
pathPrefab.GetComponentInChildren<Text>().text = fCost.ToString();
var p = Instantiate(pathPrefab, pathCellPosition.Position, Quaternion.identity, PathCells);
for(int x = 0; x < neighbours.Count; x++)
{
var node = neighbours[x];
if (visitedNodes.Contains(node))
{
continue;
}
visitedNodes.Add(node);
fCost = DistanceFromStart(node) + HCostDistanceFromEndNode(node) + node.Cost;
neighbourPrefab.GetComponentInChildren<Text>().text = fCost.ToString();
Instantiate(neighbourPrefab, node.Position, Quaternion.identity, p.transform);
List<Node> NeighBourOfNeighbourNodes = GetNeighbours(node);
if (NeighBourOfNeighbourNodes.Count > 0)
{
for (int y = 0; y < NeighBourOfNeighbourNodes.Count; y++)
{
var neighbourNode = NeighBourOfNeighbourNodes[y];
if (visitedNodes.Contains(neighbourNode))
{
continue;
}
visitedNodes.Add(neighbourNode);
fCost = DistanceFromStart(neighbourNode) + HCostDistanceFromEndNode(neighbourNode) + neighbourNode.Cost;
nofn.GetComponentInChildren<Text>().text = fCost.ToString();
Instantiate(nofn, neighbourNode.Position, Quaternion.identity, p.transform);
}
}
}
Если я не рисую соседа соседей, это выглядит правильно. Но если я делаю соседние соседи, фиолетовые не появляются так часто, как должны.
До:
Типичное простое решение — перед добавлением проверить, является ли узел частью пути. Для этого может подойти HashSet, но вам понадобится что-то, что можно надежно сравнить.
Возможно что-то вроде этого:
var visitedNodes = new HashSet<Node>(path);
for (int i = 1; i < path.Count; i++)
{
var pathCellPosition = path[i];
pathCellPosition.Position = new Vector3(pathCellPosition.Position.x, pathPrefab.transform.position.y, pathCellPosition.Position.z);
List<Node> neighbours = GetNeighbours(pathCellPosition);
var p = Instantiate(pathPrefab, pathCellPosition.Position, Quaternion.identity, PathCells);
foreach (Node n in neighbours)
{
if (visitedNodes.Contains(n))
continue;
visitedNodes.Add(n);
neighbourPrefab.GetComponentInChildren<Text>().text = n.Cost.ToString();
Instantiate(neighbourPrefab, n.Position, Quaternion.identity, p.transform);
}
}
Вы также можете использовать тот же подход, чтобы убедиться, что сосед не добавляется дважды.
Если вам нужно несколько уровней от узла, вам может потребоваться выполнить что-то вроде поиска с первым вдохом, в идеале отслеживая расстояние от исходного пути. Следующий общий код должен обходить граф в ширину, просто используйте path
в качестве первого параметра и метод GetNeighbours
в качестве второго.
public static IEnumerable<(T Node, int Distance)> GetNeighborsWithDistance<T>(IEnumerable<T> self, Func<T, IEnumerable<T>> selector)
{
var stack = new Queue<(T Node, int Distance)>();
var visited = new HashSet<T>();
foreach (var node in self)
{
stack.Enqueue((node, 0));
}
while (stack.Count > 0)
{
var current = stack.Dequeue();
if (visited.Contains(current.Node))
continue;
yield return current;
visited.Add(current.Node);
foreach (var child in selector(current.Node))
{
stack.Enqueue((child, current.Distance+ 1));
}
}
}
Это должно гарантированно возвращать узлы в порядке удаления от исходного пути, поэтому просто выполните .TakeWhile(p => p.Distance < DesiredDistanceFromOriginalPath)
, чтобы получить столько узлов, сколько хотите.
@Krelex Смотрите редактирование, вам, вероятно, просто нужно добавить соседние узлы в hashSet.
Спасибо, что вернулись снова. Я обновил, как вы предложили, но, похоже, приоритет отдается соседям соседей как первоначальным соседям. Я обновил сообщение, чтобы показать изображения и код
@Krellex, ваше редактирование, вероятно, должно быть новым вопросом, но я добавил раздел о получении узлов на произвольном расстоянии от исходного пути.
Спасибо за предложение! Это исправило для меня проблему с соседним узлом, но когда я пытаюсь создать соседей соседей, эти новые соседи в конечном итоге перекрываются с предыдущими соседями. Я не уверен, почему. Я чувствую, что ваше решение должно было решить эту проблему.