产卵探路者邻居
Spawning pathfinder neighbours
我正在尝试生成路径查找器的邻居,但是这样做时原始路径(路径)蓝色也被掩盖了。我试过切换生成顺序,但这似乎无助于解决问题。对 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));
}
}
}
这应该保证 return 个节点,按照与原始路径的距离顺序排列,所以只需 .TakeWhile(p => p.Distance < DesiredDistanceFromOriginalPath)
即可获得任意数量的节点。
我正在尝试生成路径查找器的邻居,但是这样做时原始路径(路径)蓝色也被掩盖了。我试过切换生成顺序,但这似乎无助于解决问题。对 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));
}
}
}
这应该保证 return 个节点,按照与原始路径的距离顺序排列,所以只需 .TakeWhile(p => p.Distance < DesiredDistanceFromOriginalPath)
即可获得任意数量的节点。