Home > Enterprise >  Spawning pathfinder neighbours
Spawning pathfinder neighbours

Time:03-18

I am trying to spawn the neighbours of my path finder but when doing so the original path (path) blue also becomes covered up. I have tried switching of the order of spawn but this does not seem to help the problem. Quite new to Unity and would appreciate any insight into how I might go about spawning the path the neighbours without losing the original blue path.

Obtaining path neighbours; spawning the path neighbours

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);            
    }

}

Original path enter image description here

Path getting covered by neighbours enter image description here

Implemented suggestions fixing part of the problem

The tiles around now seem to appear but when applying the same solution to implement neighbours of neighbours it seems to cause an overlap with the original neighbouring nodes. enter image description here

Code changes:

    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);
                }
            }
        }

If I don't draw neighbour of neighbours, this looks right. But if I do neighbour of neighbours the purple ones don't appear as much as they should. Before: enter image description here

After: enter image description here

CodePudding user response:

A typical simple solution is to check if the node is part of the path before adding. A HashSet can be good for this, but you will need something that can be reliably compared.

Perhaps something like this:

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);            
    }

}

You can also use the same approach to ensure a neighbour is not added twice.

If you want multiple levels from the node you might need to do something like a breath first search, ideally keeping track of the distance from the original path. The following generic code should traverse the graph in a breadth first manner, just use the path as the first parameter, and the GetNeighbours method for the second.

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));
        }
    }
}

This should be guaranteed to return nodes in order of distance from the original path, so just do .TakeWhile(p => p.Distance < DesiredDistanceFromOriginalPath) to get as many nodes as you want.

  • Related