Exemplo n.º 1
0
    public List <PF_Node> GetNeighbourNodes(PF_Node node_)
    {
        List <PF_Node> neighbourNodes = new List <PF_Node>();

        // Loop through and get all neighbouring nodes.
        for (int x = -1; x <= 1; x++)
        {
            for (int y = -1; y <= 1; y++)
            {
                // Ignore the current node.
                if (x == 0 && y == 0)
                {
                    continue;
                }

                int checkX = node_.gridX + x;
                int checkY = node_.gridY + y;

                if (checkX >= 0 &&
                    checkX < gridSizeX &&
                    checkY >= 0 &&
                    checkY < gridSizeY)
                {
                    // Add the node to the neighbour nodes.
                    neighbourNodes.Add(grid[checkX, checkY]);
                }
            }
        }

        return(neighbourNodes);
    }
Exemplo n.º 2
0
    private int GetDistance(PF_Node nodeA, PF_Node nodeB)
    {
        // Get the x and y distances between the two nodes.
        int distanceX = Mathf.Abs(nodeA.gridX - nodeB.gridX);
        int distanceY = Mathf.Abs(nodeA.gridY - nodeB.gridY);

        // Return the distance of the shortest path.
        if (distanceX > distanceY)
        {
            return(14 * distanceY + 10 * (distanceX - distanceY));
        }
        else
        {
            return(14 * distanceX + 10 * (distanceY - distanceX));
        }
    }
Exemplo n.º 3
0
    private Vector3[] CalculatePath(PF_Node startNode_, PF_Node endNode_)
    {
        List <PF_Node> path = new List <PF_Node>();

        // Begin at the end node.
        PF_Node currentNode = endNode_;

        // Loop through from the end node to the start node and construct the path.
        while (currentNode != startNode_)
        {
            path.Add(currentNode);
            currentNode = currentNode.parentNode;
        }

        // Simplify the path by removing duplicate commands from adjacent nodes when direction does not change.
        Vector3[] waypoints = SimplifyPath(path);

        // Reverse the waypoints to get it from start to end.
        Array.Reverse(waypoints);

        return(waypoints);
    }
Exemplo n.º 4
0
    private void CreateGrid()
    {
        grid = new PF_Node[gridSizeX, gridSizeY];

        // Get the world position for the bottom left of the grid.
        Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.forward * gridWorldSize.y / 2;

        for (int x = 0; x < gridSizeX; x++)
        {
            for (int y = 0; y < gridSizeY; y++)
            {
                // Get the world position for the current node.
                Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);

                // Determine if the node is walkable or should be considered obstructed.
                bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask));

                int movementPenalty = 0;

                // Raycast
                if (walkable)
                {
                    // Start the ray in the sky and fire directly down.
                    Ray ray = new Ray(worldPoint + Vector3.up * 50, Vector3.down);

                    RaycastHit hit;

                    if (Physics.Raycast(ray, out hit, 100, walkableMask))
                    {
                        // Get the movement penalty of the terrain type.
                        walkableRegionsDictionary.TryGetValue(hit.collider.gameObject.layer, out movementPenalty);
                    }
                }

                // Update the node information within the grid for this particular node.
                grid[x, y] = new PF_Node(walkable, worldPoint, x, y, movementPenalty);
            }
        }
    }
Exemplo n.º 5
0
    private void OnDrawGizmos()
    {
        // Wireframe to show grid boundaries in editor.
        Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, 1, gridWorldSize.y));

        if (grid != null && displayGridGizmos)
        {
            PF_Node playerNode = GetNodeFromWorldPoint(player.position);

            foreach (PF_Node n in grid)
            {
                if (n.walkable)
                {
                    // Walkable.
                    Gizmos.color = Color.white;
                    if (n.movementPenalty == 5)
                    {
                        Gizmos.color = Color.green;
                    }
                }
                else
                {
                    // Obstacle.
                    Gizmos.color = Color.red;
                }

                if (playerNode == n)
                {
                    // Player.
                    Gizmos.color = Color.cyan;
                }

                // Cubes to represent node positions.
                Gizmos.DrawCube(n.worldPos, Vector3.one * (nodeDiameter - 0.1f));
            }
        }
    }
Exemplo n.º 6
0
    IEnumerator FindPath(Vector3 startPos_, Vector3 endPos_)
    {
        Stopwatch sw = new Stopwatch();

        sw.Start();

        Vector3[] waypoints   = new Vector3[0];
        bool      pathSuccess = false;

        // Get the start and end nodes.
        PF_Node startNode = grid.GetNodeFromWorldPoint(startPos_);
        PF_Node endNode   = grid.GetNodeFromWorldPoint(endPos_);

        startNode.parentNode = startNode;

        // Only search if start and end are both walkable nodes.
        if (startNode.walkable && endNode.walkable)
        {
            // Create two lists of nodes.
            // Open list will contain nodes to be evaluated.
            // Closed list will contain nodes that have already been evaluated.
            PF_Heap <PF_Node> openSet   = new PF_Heap <PF_Node>(grid.MaxSize);
            HashSet <PF_Node> closedSet = new HashSet <PF_Node>();

            // Add the starting node to our open list.
            openSet.Add(startNode);

            // Loop through the openSet.
            while (openSet.Count > 0)
            {
                // Begin with the first element in the list.
                PF_Node currentNode = openSet.RemoveFirst();

                // Add the starting node to the closed set.
                closedSet.Add(currentNode);

                // Path has been found.
                if (currentNode == endNode)
                {
                    sw.Stop();

                    //UnityEngine.Debug.Log("Path found: " + sw.ElapsedMilliseconds + "ms");

                    pathSuccess = true;

                    break;
                }

                foreach (PF_Node neighbour in grid.GetNeighbourNodes(currentNode))
                {
                    // Check if the neighbour is not walkable, or already in the closed list.
                    if (!neighbour.walkable || closedSet.Contains(neighbour))
                    {
                        continue;
                    }

                    // Get the cost to move to the neighbour.
                    int newNeighbourMoveCost = currentNode.gCost + GetDistance(currentNode, neighbour) + neighbour.movementPenalty;

                    // If the new move cost is smaller than the current, or the open list does not contain this neighbour.
                    if (newNeighbourMoveCost < neighbour.gCost || !openSet.Contains(neighbour))
                    {
                        // Update the gCost and hCost.
                        neighbour.gCost = newNeighbourMoveCost;
                        neighbour.hCost = GetDistance(neighbour, endNode);

                        // Update the parent node.
                        neighbour.parentNode = currentNode;

                        // Add it to the open set if it is not currently there.
                        if (!openSet.Contains(neighbour))
                        {
                            openSet.Add(neighbour);
                        }
                        // Otherwise update it.
                        else
                        {
                            openSet.UpdateItem(neighbour);
                        }
                    }
                }
            }
        }

        yield return(null);

        if (pathSuccess)
        {
            waypoints = CalculatePath(startNode, endNode);
        }

        requestManager.FinishedProcessingPath(waypoints, pathSuccess);
    }