Ejemplo n.º 1
0
 private void IdentitySuccessors(JPSNode currNode, JPSNode goalNode, HashSet <JPSNode> openSet, HashSet <JPSNode> explored, PriorityQueue <JPSNode, float> priorityQueue)
 {
     JPSNode[] neibours = GetNeibours_JPS(currNode);
     for (int i = 0; i < neibours.Length; i++)
     {
         if (neibours[i] == null)
         {
             continue;
         }
         if (explored.Contains(neibours[i]))
         {
             Debug.Log("Skip neibour explored.");
             continue;
         }
         JPSNode jumpNode = Jump(currNode, neibours[i], goalNode);
         if (jumpNode == null)
         {
             continue;
         }
         float dist    = Heuristic(currNode.x, currNode.z, jumpNode.x, jumpNode.z);
         float newCost = currNode.realCost + dist;
         if (openSet.Contains(jumpNode) == false || newCost < jumpNode.realCost)
         {
             jumpNode.realCost = newCost;
             jumpNode.previous = currNode;
             float estimateCost = Heuristic(jumpNode.x, jumpNode.z, goalNode.x, goalNode.z);
             priorityQueue.Insert(jumpNode, jumpNode.realCost + estimateCost);
             openSet.Add(jumpNode);
         }
     }
 }
Ejemplo n.º 2
0
    private void AddToOpen(JPSNode newNode)
    {
        for (int i = 0; i < open.Count; i++)
        {
            if (open[i].pos == newNode.pos)
            {
                return;
            }
        }
        for (int i = 0; i < closed.Count; i++)
        {
            if (closed[i].pos == newNode.pos)
            {
                return;
            }
        }

        /*
         * if (newNode.pos == new Vector3(2, 0, 1)  || newNode.pos == new Vector3(2, 0, 3))
         * {
         *  Debug.Log(newNode.pos + "F: " + newNode.priority + " H:" + newNode.H);
         * }
         */
        if (DebugMode)
        {
            floor.HighlightUV((int)newNode.pos.x, (int)newNode.pos.z, Color.blue);
        }
        open.Add(newNode);
    }
Ejemplo n.º 3
0
    private void CreateScene(Texture2D texture)
    {
        GameObject p = new GameObject("Pathfinding Scene");

        isObstacle = new bool[texture.width, texture.height];
        size       = texture.width;
        nodeMap    = new JPSNode[size, size];
        Color c;

        for (int i = 0; i < texture.width; i++)
        {
            for (int j = 0; j < texture.height; j++)
            {
                float value = texture.GetPixel(i, j).r;
                // 阻挡
                if (value == 0)
                {
                    isObstacle[i, j] = true;
                    c = Color.black;
                }
                else
                {
                    isObstacle[i, j] = false;
                    c = Color.white;
                }
                nodeMap[i, j] = new JPSNode(i, j, Single.PositiveInfinity, isObstacle[i, j]);
                GameObject go = Instantiate(blockPrefab, p.transform);
                go.transform.position = new Vector3(i, 0, j);
                SetBlockColor(go, c);
                nodeMap[i, j].block = go;
            }
        }
    }
Ejemplo n.º 4
0
    public IEnumerator FindPathJPS(JPSNode startNode, JPSNode goalNode)
    {
        if (!InRange(startNode) || !InRange(goalNode))
        {
            throw new IndexOutOfRangeException();
        }
        if (startNode.isObstacle || goalNode.isObstacle)
        {
            Debug.LogError("起点/终点处于障碍物!");
            yield break;
        }
        switch (heuristic)
        {
        case EHeuristic.EulerDistance:
            Heuristic = EulerDistance;
            break;

        case EHeuristic.ManhattonDistance:
            Heuristic = ManhattonDistance;
            break;

        case EHeuristic.DiagonalDistance:
            Heuristic = DiagonalDistance;
            break;

        default:
            Heuristic = EulerDistance;
            break;
        }
        Stopwatch watch = Stopwatch.StartNew();
        // --JPS Path Finding
        PriorityQueue <JPSNode, float> priorityQueue = new PriorityQueue <JPSNode, float>(0f);
        HashSet <JPSNode> openSet  = new HashSet <JPSNode>();
        HashSet <JPSNode> explored = new HashSet <JPSNode>();

        openSet.Add(startNode);
        startNode.realCost = 0f;
        startNode.previous = null;
        priorityQueue.Insert(startNode, 0f);
        while (priorityQueue.Count() != 0)
        {
            JPSNode currNode = priorityQueue.Pop();
            if (currNode.x == goalNode.x && currNode.z == goalNode.z)
            {
                watch.Stop();
                //Debug.Log($"JPS寻路完成,耗时{watch.ElapsedMilliseconds}ms");
                _pathForDisplay = ConstructPath(currNode);
                yield break;
            }
            explored.Add(currNode);
            openSet.Remove(currNode);

            IdentitySuccessors(currNode, goalNode, openSet, explored, priorityQueue);
            if (showProcess)
            {
                yield return(waitTime);
            }
        }
        Debug.LogError("JPS 没找到路径");
    }
Ejemplo n.º 5
0
 public JPSNode(int x, int z, float realCost, bool obstacle)
 {
     this.x        = x;
     this.z        = z;
     this.realCost = realCost;
     previous      = null;
     isObstacle    = obstacle;
 }
Ejemplo n.º 6
0
    private List <JPSNode> ConstructPath(JPSNode n)
    {
        List <JPSNode> nodeList = new List <JPSNode>();

        nodeList.Add(n);
        while (n.previous != null)
        {
            n = n.previous;
            nodeList.Add(n);
        }
        return(nodeList);
    }
Ejemplo n.º 7
0
    private JPSNode Jump(JPSNode parentNode, JPSNode neibour, JPSNode goal)
    {
        if (neibour == null || !IsWalkable(neibour))
        {
            return(null);
        }
        if (neibour == goal)
        {
            return(neibour);
        }

        int dx = neibour.x - parentNode.x;
        int dz = neibour.z - parentNode.z;

        // 检查对角线
        if (dx != 0 && dz != 0)
        {
            // 检查对角线时也要对水平或垂直的进行检查,如果后续检查存在跳点,则该点是跳点
            if (Jump(neibour, GetNode(neibour.x + dx, neibour.z), goal) != null ||
                Jump(neibour, GetNode(neibour.x, neibour.z + dz), goal) != null)
            {
                return(neibour);
            }
            if ((!IsWalkable(GetNode(neibour.x - dx, neibour.z)) && IsWalkable(GetNode(neibour.x - dx, neibour.z + dz))) ||
                (!IsWalkable(GetNode(neibour.x, neibour.z - dz)) && IsWalkable(GetNode(neibour.x + dx, neibour.z - dz))))
            {
                return(neibour);
            }
        }
        else
        {
            // 水平
            if (dx != 0)
            {
                if ((IsWalkable(GetNode(neibour.x + dx, neibour.z + 1)) && !IsWalkable(GetNode(neibour.x, neibour.z + 1))) ||
                    (IsWalkable(GetNode(neibour.x + dx, neibour.z - 1)) && !IsWalkable(GetNode(neibour.x, neibour.z - 1))))
                {
                    return(neibour);
                }
            }
            else
            {
                if ((IsWalkable(GetNode(neibour.x - 1, neibour.z + dz)) && !IsWalkable(GetNode(neibour.x - 1, neibour.z))) ||
                    (IsWalkable(GetNode(neibour.x + 1, neibour.z + dz)) && !IsWalkable(GetNode(neibour.x + 1, neibour.z))))
                {
                    return(neibour);
                }
            }
        }
        //SetBlockColor(neibour.block, Color.cyan, drawPath);
        return(Jump(neibour, GetNode(neibour.x + dx, neibour.z + dz), goal));
    }
Ejemplo n.º 8
0
 private bool IsWalkable(JPSNode node)
 {
     if (node == null)
     {
         return(false);
     }
     if (InRange(node) == false)
     {
         return(false);
     }
     if (node.isObstacle)
     {
         return(false);
     }
     return(true);
 }
Ejemplo n.º 9
0
    public JPSNode(Vector3 newPos, JPSNode par, Vector3 dest)
    {
        pos    = newPos;
        parent = par;
        int dx = (int)Mathf.Abs(dest.x - pos.x);
        int dz = (int)Mathf.Abs(dest.z - pos.z);

        H = (dx + dz) + ((Mathf.Sqrt(2) - 2) * Mathf.Min(dx, dz));
        // Chebyshev Mathf.Max(Mathf.Abs(dest.x - pos.x), Mathf.Abs(dest.z - pos.z));
        directions = new List <Vector3>();
        if (parent != null)
        {
            parentPos = parent.pos;
            parentF   = parent.priority;
            G        += parent.G
                        + (Mathf.Sqrt(Mathf.Pow(parent.pos.x - pos.x, 2) + Mathf.Pow(parent.pos.z - pos.z, 2)));
        }
        priority = G + H;
    }
Ejemplo n.º 10
0
    private JPSNode[] GetAllNeibours(JPSNode n)
    {
        int x = n.x;
        int z = n.z;

        JPSNode[] neibours = new JPSNode[8];

        if (InRange(x - 1, z))
        {
            neibours[0] = nodeMap[x - 1, z];
        }
        if (InRange(x, z + 1))
        {
            neibours[1] = nodeMap[x, z + 1];
        }
        if (InRange(x + 1, z))
        {
            neibours[2] = nodeMap[x + 1, z];
        }
        if (InRange(x, z - 1))
        {
            neibours[3] = nodeMap[x, z - 1];
        }

        if (InRange(x - 1, z - 1))
        {
            neibours[4] = nodeMap[x - 1, z - 1];
        }
        if (InRange(x - 1, z + 1))
        {
            neibours[5] = nodeMap[x - 1, z + 1];
        }
        if (InRange(x + 1, z + 1))
        {
            neibours[6] = nodeMap[x + 1, z + 1];
        }
        if (InRange(x + 1, z - 1))
        {
            neibours[7] = nodeMap[x + 1, z - 1];
        }
        return(neibours);
    }
Ejemplo n.º 11
0
    public void Search()
    {
        searched = true;
        //Reset Debug floor
        if (DebugMode)
        {
            foreach (JPSNode node in closed)
            {
                floor.HighlightUV((int)node.pos.x, (int)node.pos.z, Color.white);
            }
            foreach (JPSNode node in path)
            {
                floor.HighlightUV((int)node.pos.x, (int)node.pos.z, Color.white);
            }
        }
        //Prime search values
        searching        = true;
        destinationFound = false;
        placeInPath      = 0;
        open.Clear();
        closed.Clear();
        path.Clear();
        currentNode = new JPSNode(startingPosition, null, destination);

        //First node must have all directions
        currentNode.AddDirection(new Vector3(1, 0, 1));
        currentNode.AddDirection(new Vector3(1, 0, -1));
        currentNode.AddDirection(new Vector3(-1, 0, 1));
        currentNode.AddDirection(new Vector3(-1, 0, -1));
        currentNode.AddDirection(new Vector3(1, 0, 0));
        currentNode.AddDirection(new Vector3(-1, 0, 0));
        currentNode.AddDirection(new Vector3(0, 0, 1));
        currentNode.AddDirection(new Vector3(0, 0, -1));
        AddToOpen(currentNode);

        //begin main search loop
        while (!destinationFound && open.Count > 0)
        {
            currentNode = open[0];
            for (int i = 0; i < open.Count; i++)
            {
                if (currentNode.priority > open[i].priority)
                {
                    currentNode = open[i];
                }
            }

            open.Remove(currentNode);
            closed.Add(currentNode);
            for (int i = 0; i < currentNode.directions.Count; i++)
            {
                if (currentNode.directions[i].magnitude == 1)
                {
                    FindNodes(currentNode.pos + currentNode.directions[i], currentNode, currentNode.directions[i], true);
                }
                else
                {
                    FindNodes(currentNode.pos + currentNode.directions[i], currentNode, currentNode.directions[i], false);
                }
            }
        }
        //Prepare path for unit
        currentNode = null;
        for (int i = 0; i < closed.Count; i++)
        {
            if (closed[i].pos == destination)
            {
                currentNode = closed[i];
            }
        }
        if (DebugMode)
        {
            Debug.Log("Path Cost: " + currentNode.priority);
        }
        if (currentNode != null)
        {
            while (currentNode.parent != null)
            {
                if (DebugMode)
                {
                    floor.HighlightUV((int)currentNode.pos.x, (int)currentNode.pos.z, Color.green);
                }
                path.Add(currentNode);
                currentNode = currentNode.parent;
            }
            path.Reverse();
            if (destinationFound)
            {
                navigating = true;
            }
        }
        searching = false;
    }
Ejemplo n.º 12
0
    private bool FindNodes(Vector3 position, JPSNode parent, Vector3 direction, bool core)
    {
        Vector3 currentPosition = position;

        while (IsInBounds(currentPosition) && !ObjectAt(currentPosition))
        {
            if (currentPosition == destination)
            {
                JPSNode destNode = new JPSNode(currentPosition, parent, destination);
                closed.Add(destNode);
                destinationFound = true;
                return(true);
            }
            if (direction.magnitude > 1) // do diagonal stuff
            {
                bool    addDiag  = false;
                JPSNode diagNode = new JPSNode(currentPosition, parent, destination);
                if (!ObjectAt(currentPosition + new Vector3(-direction.x, 0, 0)) ||
                    !ObjectAt(currentPosition + new Vector3(0, 0, -direction.z)))
                {
                    if (!ObjectAt(currentPosition + new Vector3(-direction.x, 0, 0)) && ObjectAt(currentPosition + new Vector3(0, 0, -direction.z)))
                    {
                        diagNode.AddDirection(new Vector3(direction.x, 0, -direction.z));
                        addDiag = true;
                    }
                    else if (!ObjectAt(currentPosition + new Vector3(0, 0, -direction.z)) && ObjectAt(currentPosition + new Vector3(-direction.x, 0, 0)))
                    {
                        diagNode.AddDirection(new Vector3(-direction.x, 0, direction.z));
                        addDiag = true;
                    }
                    if (FindNodes(currentPosition + new Vector3(direction.x, 0, 0), diagNode, new Vector3(direction.x, 0, 0), false))
                    {
                        diagNode.AddDirection(new Vector3(direction.x, 0, 0));
                        addDiag = true;
                    }
                    if (FindNodes(currentPosition + new Vector3(0, 0, direction.z), diagNode, new Vector3(0, 0, direction.z), false))
                    {
                        diagNode.AddDirection(new Vector3(0, 0, direction.z));
                        addDiag = true;
                    }
                    if (addDiag)
                    {
                        AddToOpen(diagNode);
                    }
                }
                else
                {
                    return(false);
                }
            }
            else // do horizontal/vertical stuff
            {
                bool    addNode = false;
                JPSNode newNode = new JPSNode(currentPosition, parent, destination);
                newNode.AddDirection(direction);
                if (currentPosition == destination)
                {
                    closed.Add(newNode);
                    destinationFound = true;
                    return(true);
                }
                bool horizVert = (Mathf.Abs(direction.x) == 1) ? true : false;
                if (!ObjectAt(currentPosition + direction) &&
                    ObjectAt(currentPosition + ((horizVert) ? new Vector3(0, 0, 1) : new Vector3(1, 0, 0))) &&
                    !ObjectAt(currentPosition + ((horizVert) ? new Vector3(direction.x, 0, 1) : new Vector3(1, 0, direction.z))))
                {
                    newNode.AddDirection((horizVert) ? new Vector3(direction.x, 0, 1) : new Vector3(1, 0, direction.z));
                    addNode = true;
                }
                if (!ObjectAt(currentPosition + direction) &&
                    ObjectAt(currentPosition + ((horizVert) ? new Vector3(0, 0, -1) : new Vector3(-1, 0, 0))) &&
                    !ObjectAt(currentPosition + ((horizVert) ? new Vector3(direction.x, 0, -1) : new Vector3(-1, 0, direction.z))))
                {
                    newNode.AddDirection((horizVert) ? new Vector3(direction.x, 0, -1) : new Vector3(-1, 0, direction.z));
                    addNode = true;
                }
                if (addNode)
                {
                    if (core)
                    {
                        AddToOpen(newNode);
                    }
                    return(true);
                }
            }
            currentPosition += direction;
        }
        return(false);
    }
Ejemplo n.º 13
0
    private JPSNode[] GetNeibours_JPS(JPSNode node)
    {
        JPSNode[] nodes = new JPSNode[8];
        if (node.previous == null)
        {
            return(GetAllNeibours(node));
        }
        JPSNode parentNode = node.previous;
        int     x = node.x, z = node.z;
        int     px = parentNode.x;
        int     pz = parentNode.z;
        int     dx = (x - px) / Mathf.Max(Mathf.Abs(x - px), 1);
        int     dz = (z - pz) / Mathf.Max(Mathf.Abs(z - pz), 1);

        if (dx != 0 && dz != 0)
        {
            if (IsWalkable(GetNode(x, z + dz)))
            {
                nodes[0] = GetNode(x, z + dz);
            }

            if (IsWalkable(GetNode(x + dx, z)))
            {
                nodes[1] = GetNode(x + dx, z);
            }

            if (IsWalkable(GetNode(x + dx, z + dz)))
            {
                nodes[2] = GetNode(x + dx, z + dz);
            }

            if (!IsWalkable(GetNode(x - dx, z)))
            {
                nodes[3] = GetNode(x - dx, z + dz);
            }
            if (!IsWalkable(GetNode(x, z - dz)))
            {
                nodes[4] = GetNode(x + dx, z - dz);
            }
        }
        else
        {
            if (dx == 0)
            {
                //nodes[0] = GetNode(x, z + dz);
                //nodes[1] = GetNode(x + 1, z + dz);
                //nodes[2] = GetNode(x - 1, z + dz);
                if (IsWalkable(GetNode(x, z + dz)))
                {
                    nodes[0] = GetNode(x, z + dz);
                }

                if (IsWalkable(GetNode(x + 1, z + dz)))
                {
                    nodes[1] = GetNode(x + 1, z + dz);
                }

                if (IsWalkable(GetNode(x - 1, z + dz)))
                {
                    nodes[2] = GetNode(x - 1, z + dz);
                }
            }
            else
            {
                //nodes[0] = GetNode(x + dx, z);
                //nodes[1] = GetNode(x + dx, z + 1);
                //nodes[2] = GetNode(x + dx, z - 1);
                if (IsWalkable(GetNode(x + dx, z)))
                {
                    nodes[0] = GetNode(x + dx, z);
                }

                if (IsWalkable(GetNode(x + dx, z + 1)))
                {
                    nodes[1] = GetNode(x + dx, z + 1);
                }

                if (IsWalkable(GetNode(x + dx, z - 1)))
                {
                    nodes[2] = GetNode(x + dx, z - 1);
                }
            }
        }
        return(nodes);
    }
Ejemplo n.º 14
0
    public IEnumerator FindPathAstar(int xstart, int zstart, int xend, int zend)
    {
        // 一些设置
        if (!InRange(xstart, zstart) || !InRange(xend, zend))
        {
            throw new ArgumentOutOfRangeException();
        }
        if (isObstacle[xend, zend] || isObstacle[xstart, zstart])
        {
            yield break;
        }
        switch (heuristic)
        {
        case EHeuristic.EulerDistance:
            Heuristic = EulerDistance;
            break;

        case EHeuristic.ManhattonDistance:
            Heuristic = ManhattonDistance;
            break;

        case EHeuristic.DiagonalDistance:
            Heuristic = DiagonalDistance;
            break;

        default:
            Heuristic = EulerDistance;
            break;
        }
        SetBlockColor(nodeMap[xstart, zstart].block, Color.yellow, drawPath);
        SetBlockColor(nodeMap[xend, zend].block, Color.blue, drawPath);

        // 寻路流程
        Stopwatch         watch           = Stopwatch.StartNew();
        HashSet <JPSNode> reachedList     = new HashSet <JPSNode>();
        HashSet <JPSNode> exploredList    = new HashSet <JPSNode>();
        PriorityQueue <JPSNode, float> pq = new PriorityQueue <JPSNode, float>(0f);

        JPSNode[] neibours = new JPSNode[8];

        nodeMap[xstart, zstart].realCost = 0f;
        pq.Insert(nodeMap[xstart, zstart], 0f);
        reachedList.Add(nodeMap[xstart, zstart]);

        while (pq.Count() != 0)
        {
            JPSNode currNode = pq.Pop();
            if (currNode.x == xend && currNode.z == zend)
            {
                watch.Stop();
                Debug.Log($"寻路完成 耗时{watch.ElapsedMilliseconds}ms");
                _pathForDisplay = ConstructPath(currNode);
                yield break;
                //return ConstructPath(currNode);
            }
            exploredList.Add(currNode);
            reachedList.Remove(currNode);
            SetBlockColor(currNode.block, Color.gray, drawPath);
            neibours = GetAllNeibours(currNode);

            for (int i = 0; i < 8; i++)
            {
                if (neibours[i] != null && neibours[i].isObstacle == false && !exploredList.Contains(neibours[i]))
                {
                    float step         = i > 4 ? 1.41421356f : 1f;
                    float estimateCost = Heuristic(neibours[i].x, neibours[i].z, xend, zend);
                    float newCost      = currNode.realCost + step;
                    if (reachedList.Contains(neibours[i]) == false || newCost < neibours[i].realCost)
                    {
                        float beforeCost = neibours[i].realCost;
                        neibours[i].previous = currNode;
                        neibours[i].realCost = newCost;
                        if (reachedList.Contains(neibours[i]) == false)
                        {
                            Debug.Log($"Astart Add {neibours[i].x},{neibours[i].z}: {beforeCost + estimateCost} -> {estimateCost + neibours[i].realCost}");
                        }
                        else
                        {
                            Debug.Log($"Astar Update {neibours[i].x},{neibours[i].z}: {beforeCost + estimateCost} -> {estimateCost + neibours[i].realCost}");
                        }
                        pq.Insert(neibours[i], neibours[i].realCost + estimateCost);
                        reachedList.Add(neibours[i]);
                        SetBlockColor(neibours[i].block, Color.yellow, drawPath);
                    }
                }
            }
            if (showProcess)
            {
                yield return(null);
            }
        }
        //EditorUtility.ClearProgressBar();
    }
Ejemplo n.º 15
0
 private bool InRange(JPSNode node)
 {
     return(node.x >= 0 && node.z >= 0 && node.x < size && node.z < size);
 }
Ejemplo n.º 16
0
 private float GetDistance(JPSNode a, JPSNode b)
 {
     return(EulerDistance(a.x, a.z, b.x, b.z));
 }