public static void Process(PNavMesh pNavMesh)
        {
            using (new SProfiler("Finding Islands"))
            {
                // find islands
                List <PNavIsland> islands = new List <PNavIsland>();
                int        maxX           = pNavMesh.columns.GetLength(0) - 1;
                int        maxZ           = pNavMesh.columns.GetLength(1) - 1;
                PNavPoint  pointMax       = new PNavPoint(maxX, maxZ);
                int        islandIndex    = 0;
                PNavIsland island         = new PNavIsland();

                for (int x = 0; x < maxX; x++)
                {
                    for (int z = 0; z < maxZ; z++)
                    {
                        PNavPoint point       = new PNavPoint(x, z);
                        bool      foundIsland = DetectIsland(pNavMesh.columns, point, pointMax, 1, pNavMesh.verticalDrop, islandIndex, island);
                        if (foundIsland)
                        {
                            islandIndex++;
                            islands.Add(island);
                            PNavMeshHelper.DetectEdgeCorner(pNavMesh.columns, pointMax, island);
                            PNavMeshHelper.ApplyEdgeGap(pNavMesh.columns, pointMax, island, pNavMesh.edgeGap);

                            island = new PNavIsland();
                        }
                    }
                }

                pNavMesh.islands = islands;
                Debug.Log($"Found {islands.Count} islands");
            }
        }
        public static bool AddRight(PNavColumn[,] columns, PNavPoint point, out PNavPoint pOut, PNavPoint pointMax, int verticalDrop, int edgeGap, int islandIndex, PNavIsland island, Queue <PNavPoint> queue)
        {
            PNavColumn column = columns[point.x, point.z];
            PNavNode   node   = column.SurfaceNode();

            bool valid        = GetRightPoint(point, pointMax, 1, out pOut);
            bool connected    = false;
            bool alreadyAdded = false;

            if (valid)
            {
                PNavColumn c  = columns[pOut.x, pOut.z];
                PNavNode   sn = c.SurfaceNode();

                //already checked
                if (sn != null && sn.islandIndex >= 0)
                {
                    alreadyAdded = true;
                }

                connected = column.IsConnected(c, verticalDrop);

                if (connected && !alreadyAdded)
                {
                    sn.islandIndex = islandIndex;
                    island.nodes.Add(sn);

                    //add top to queue
                    PNavPoint pTopOut;

                    bool addedTop = AddTop(columns, pOut, out pTopOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                    if (addedTop)
                    {
                        queue.Enqueue(pTopOut);
                    }

                    //add bottom to queue
                    PNavPoint pBottomOut;
                    bool      addedBottom = AddBottom(columns, pOut, out pBottomOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                    if (addedBottom)
                    {
                        queue.Enqueue(pBottomOut);
                    }
                }
            }

            if (!connected)
            {
                node.type = node.type | (int)ParallelNavIslandNodeType.RightEdge;
            }

            return(connected && !alreadyAdded);
        }
        public static void Process(PNavMesh pNavMesh)
        {
            using (new SProfiler("Finding Edge Loops"))
            {
                int       maxX     = pNavMesh.columns.GetLength(0);
                int       maxZ     = pNavMesh.columns.GetLength(1);
                PNavPoint pointMax = new PNavPoint(maxX, maxZ);

                FindEdgeLoops(pNavMesh.columns, pointMax, pNavMesh);
            }
        }
        public static bool GetBottomPoint(PNavPoint point, PNavPoint pointMax, int nodes, out PNavPoint pointOut)
        {
            pointOut = new PNavPoint(point.x, point.z - nodes);

            if (pointOut.z < 0)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        public static bool GetTopPoint(PNavPoint point, PNavPoint pointMax, int nodes, out PNavPoint pointOut)
        {
            pointOut = new PNavPoint(point.x, point.z + nodes);

            if (pointOut.z > pointMax.z)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        public static bool GetLeftPoint(PNavPoint point, PNavPoint pointMax, int nodes, out PNavPoint pointOut)
        {
            pointOut = new PNavPoint(point.x - nodes, point.z);

            if (pointOut.x < 0)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        public static bool GetRightPoint(PNavPoint point, PNavPoint pointMax, int nodes, out PNavPoint pointOut)
        {
            pointOut = new PNavPoint(point.x + nodes, point.z);

            if (pointOut.x > pointMax.x)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        public static bool GetPoint(PNavPoint point, PNavPoint pointMax, PNavPoint nodes, out PNavPoint pointOut)
        {
            pointOut = new PNavPoint(point.x + nodes.x, point.z + nodes.z);

            if (pointOut.x > pointMax.x || pointOut.x < 0 || pointOut.z > pointMax.z || pointOut.z < 0)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        static bool isWalkableNode(PNavPoint self, PNavPoint max, PNavPoint delta, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            bool      valid = PNavMeshHelper.GetPoint(self, max, delta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                valid = (n != null && n.walkable);
            }

            return(valid);
        }
示例#10
0
        static bool isInnerNode(PNavPoint point, PNavPoint max, PNavPoint delta, int nodes, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            PNavPoint newDelta = new PNavPoint(delta.x * nodes, delta.z * nodes);
            bool      valid    = PNavMeshHelper.GetPoint(point, max, newDelta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                valid = (n != null && n.IsInner);
            }

            return(valid);
        }
示例#11
0
        static bool isEdgeNode(PNavPoint point, PNavPoint max, PNavPoint delta, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            bool      valid = PNavMeshHelper.GetPoint(point, max, delta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                if (n == null)
                {
                    return(false);
                }

                return(n.IsLeftEdge || n.IsRghtEdge || n.IsBackEdge || n.IsFrontEdge);
            }

            return(false);
        }
        static void FindEdgeLoops(PNavColumn[,] columns, PNavPoint pointMax, PNavMesh pNavMesh)
        {
            List <PNavIsland> islandsToRemove = new List <PNavIsland>();

            foreach (PNavIsland island in pNavMesh.islands)
            {
                int          edgeLoopIndex = 0;
                int          maxNodeCount  = 0;
                PNavEdgeLoop edgeLoop      = new PNavEdgeLoop();

                foreach (PNavNode node in island.nodes)
                {
                    if (node.walkable)
                    {
                        bool foundLoop = DetectEdgeLoop(node, edgeLoop, edgeLoopIndex, columns, pointMax);

                        if (foundLoop)
                        {
                            int nodeCount = edgeLoop.nodes.Count;
                            if (nodeCount > maxNodeCount)
                            {
                                maxNodeCount = nodeCount;
                                island.boundaryEdgeLoopIndex = edgeLoopIndex;
                            }
                            edgeLoopIndex++;
                            island.edgeLoops.Add(edgeLoop);
                            edgeLoop = new PNavEdgeLoop();
                        }
                    }
                }

                if (island.boundaryEdgeLoopIndex < 0)
                {
                    islandsToRemove.Add(island);
                }
            }

            foreach (PNavIsland island in islandsToRemove)
            {
                pNavMesh.islands.Remove(island);
            }
        }
示例#13
0
        public static void DetectEdgeCorner(PNavColumn[,] columns, PNavPoint pointMax, PNavIsland island)
        {
            foreach (PNavNode node in island.nodes)
            {
                if (node.IsInner)
                {
                    bool topEdge   = isEdgeNode(node.point, pointMax, TOP, columns);
                    bool botEdge   = isEdgeNode(node.point, pointMax, BOTTOM, columns);
                    bool leftEdge  = isEdgeNode(node.point, pointMax, LEFT, columns);
                    bool rightEdge = isEdgeNode(node.point, pointMax, RIGHT, columns);

                    bool topLeftEdge  = isEdgeNode(node.point, pointMax, TOPLEFT, columns);
                    bool topRightEdge = isEdgeNode(node.point, pointMax, TOPRIGHT, columns);
                    bool botLeftEdge  = isEdgeNode(node.point, pointMax, BOTTOMLEFT, columns);
                    bool botRightEdge = isEdgeNode(node.point, pointMax, BOTTOMRIGHT, columns);

                    if (topEdge && leftEdge && !topLeftEdge)
                    {
                        node.type = node.type | (int)ParallelNavIslandNodeType.CornerEdge;
                        continue;
                    }

                    if (topEdge && rightEdge && !topRightEdge)
                    {
                        node.type = node.type | (int)ParallelNavIslandNodeType.CornerEdge;
                        continue;
                    }

                    if (botEdge && leftEdge && !botLeftEdge)
                    {
                        node.type = node.type | (int)ParallelNavIslandNodeType.CornerEdge;
                        continue;
                    }

                    if (botEdge && rightEdge && !botRightEdge)
                    {
                        node.type = node.type | (int)ParallelNavIslandNodeType.CornerEdge;
                        continue;
                    }
                }
            }
        }
示例#14
0
        public static bool AddBottom(PNavColumn[,] columns, PNavPoint point, out PNavPoint pOut, PNavPoint pointMax, int verticalDrop, int edgeGap, int islandIndex, PNavIsland island)
        {
            PNavColumn column = columns[point.x, point.z];
            PNavNode   node   = column.SurfaceNode();

            bool valid        = GetBottomPoint(point, pointMax, edgeGap, out pOut);
            bool connected    = false;
            bool alreadyAdded = false;

            if (valid)
            {
                PNavColumn c  = columns[pOut.x, pOut.z];
                PNavNode   sn = c.SurfaceNode();

                //already checked
                if (sn != null && sn.islandIndex >= 0)
                {
                    alreadyAdded = true;
                }

                connected = column.IsConnected(c, verticalDrop);

                if (connected && !alreadyAdded)
                {
                    sn.islandIndex = islandIndex;
                    island.nodes.Add(sn);
                }
            }

            if (!connected)
            {
                node.type = node.type | (int)ParallelNavIslandNodeType.BottomEdge;
            }

            return(connected && !alreadyAdded);
        }
示例#15
0
        public static void ApplyEdgeGap(PNavColumn[,] columns, PNavPoint pointMax, PNavIsland island, int edgeGap)
        {
            foreach (PNavNode node in island.nodes)
            {
                if (node.IsInner)
                {
                    //===remove narrow path
                    // check top and bot
                    bool top2Valid = isInnerNode(node.point, pointMax, TOP, 2, columns);
                    bool top1Valid = isInnerNode(node.point, pointMax, TOP, 1, columns);
                    bool bot1Valid = isInnerNode(node.point, pointMax, BOTTOM, 1, columns);
                    bool bot2Valid = isInnerNode(node.point, pointMax, BOTTOM, 2, columns);

                    if (top2Valid && top1Valid || top1Valid && bot1Valid || bot1Valid && bot2Valid)
                    {
                        // valid
                    }
                    else
                    {
                        node.walkable = false;
                    }

                    // check left and right
                    bool left2Valid  = isInnerNode(node.point, pointMax, LEFT, 2, columns);
                    bool left1Valid  = isInnerNode(node.point, pointMax, LEFT, 1, columns);
                    bool right1Valid = isInnerNode(node.point, pointMax, RIGHT, 1, columns);
                    bool right2Valid = isInnerNode(node.point, pointMax, RIGHT, 2, columns);

                    if (left2Valid && left1Valid || left1Valid && right1Valid || right1Valid && right2Valid)
                    {
                        // valid
                    }
                    else
                    {
                        node.walkable = false;
                    }

                    // diagonals
                    //bool topLeft2Valid = isInnerNode(node.point, pointMax, TOPLEFT, 2, columns);
                    //bool topLeft1Valid = isInnerNode(node.point, pointMax, TOPLEFT, 1, columns);
                    //bool botRight1Valid = isInnerNode(node.point, pointMax, BOTTOMRIGHT, 1, columns);
                    //bool botRight2Valid = isInnerNode(node.point, pointMax, BOTTOMRIGHT, 2, columns);

                    //if (topLeft2Valid && topLeft1Valid || topLeft1Valid && botRight1Valid || botRight1Valid && botRight2Valid)
                    //{
                    //    // valid
                    //}
                    //else
                    //{
                    //    node.walkable = false;
                    //}

                    //bool topRight2Valid = isInnerNode(node.point, pointMax, TOPRIGHT, 2, columns);
                    //bool topRight1Valid = isInnerNode(node.point, pointMax, TOPRIGHT, 1, columns);
                    //bool botLeft1Valid = isInnerNode(node.point, pointMax, BOTTOMLEFT, 1, columns);
                    //bool botLeft2Valid = isInnerNode(node.point, pointMax, BOTTOMLEFT, 2, columns);

                    //if (topRight2Valid && topRight1Valid || topRight1Valid && botLeft1Valid || botLeft1Valid && botLeft2Valid)
                    //{
                    //    // valid
                    //}
                    //else
                    //{
                    //    node.walkable = false;
                    //}

                    continue;
                }
                else
                {
                    node.walkable = false;

                    // remove edgeGap
                    //left
                    for (int i = 0; i < edgeGap; i++)
                    {
                        //left
                        {
                            PNavPoint pOut;
                            bool      valid = GetLeftPoint(node.point, pointMax, i, out pOut);
                            if (valid)
                            {
                                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();
                                if (n != null)
                                {
                                    n.walkable = false;
                                }
                            }
                        }

                        //right
                        {
                            PNavPoint pOut;
                            bool      valid = GetRightPoint(node.point, pointMax, i, out pOut);
                            if (valid)
                            {
                                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();
                                if (n != null)
                                {
                                    n.walkable = false;
                                }
                            }
                        }

                        //top
                        {
                            PNavPoint pOut;
                            bool      valid = GetTopPoint(node.point, pointMax, i, out pOut);
                            if (valid)
                            {
                                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();
                                if (n != null)
                                {
                                    n.walkable = false;
                                }
                            }
                        }

                        //bottom
                        {
                            PNavPoint pOut;
                            bool      valid = GetBottomPoint(node.point, pointMax, i, out pOut);
                            if (valid)
                            {
                                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();
                                if (n != null)
                                {
                                    n.walkable = false;
                                }
                            }
                        }
                    }
                }
            }
        }
        static bool CheckIfNodeIsValidEdge(PNavNode node, PNavColumn[,] columns, PNavPoint pointMax)
        {
            node.isEdge = false;

            node.edgeFlag = 0;

            bool allSurroundingAreInner = true;

            for (int i = 0; i < 8; i++)
            {
                walkables[i] = false;

                PNavPoint pOut;
                bool      valid = PNavMeshHelper.GetPoint(node.point, pointMax, points2[i], out pOut);

                if (valid)
                {
                    PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                    if (n != null)
                    {
                        if (n.walkable)
                        {
                            walkables[i]  = true;
                            node.edgeFlag = (byte)(node.edgeFlag | 1 << i);
                        }

                        if (!n.IsInner)
                        {
                            allSurroundingAreInner = false;
                        }
                    }
                }
            }

            if (!allSurroundingAreInner)
            {
                node.isEdge = true;
            }

            if (walkables[0] != walkables[4]) //left and right
            {
                node.isEdge = true;

                // if top and bot are not walkable, not valid
                if (!walkables[2] && !walkables[6])
                {
                    node.isEdge = false;
                }
            }

            if (walkables[2] != walkables[6]) // top and bot
            {
                node.isEdge = true;

                // if left and right are not walkable, not valid
                if (!walkables[0] && !walkables[4])
                {
                    node.isEdge = false;
                }
            }

            // if all diagonal nodes are not walkable, not valid
            if (!walkables[1] && !walkables[3] && !walkables[5] && !walkables[7])
            {
                node.isEdge = false;
            }

            return(node.isEdge);
        }
        static bool DetectEdgeLoop(PNavNode node, PNavEdgeLoop edgeLoop, int edgeLoopIndex, PNavColumn[,] columns, PNavPoint pointMax)
        {
            bool foundLoop = false;

            if (node == null || !node.walkable || node.edgeLoopIndex >= 0)
            {
                return(false);
            }

            bool isEdge = CheckIfNodeIsValidEdge(node, columns, pointMax);

            if (!isEdge)
            {
                return(false);
            }

            Stack <PNavNode> stack = new Stack <PNavNode>();

            stack.Push(node);

            while (stack.Count > 0)
            {
                PNavNode n = stack.Pop();

                //possible to be added more than once
                if (n.edgeLoopIndex >= 0)
                {
                    continue;
                }

                edgeLoop.nodes.Add(n);
                n.edgeLoopIndex = edgeLoopIndex;
                foundLoop       = true;

                for (int i = 0; i < 8; i++)
                {
                    PNavPoint pOut;
                    bool      valid = PNavMeshHelper.GetPoint(n.point, pointMax, points[i], out pOut);

                    if (valid)
                    {
                        PNavNode nPush = columns[pOut.x, pOut.z].SurfaceNode();
                        if (nPush != null)
                        {
                            if (!nPush.walkable || nPush.edgeLoopIndex >= 0)
                            {
                                continue;
                            }

                            bool isEdge1 = CheckIfNodeIsValidEdge(nPush, columns, pointMax);

                            if (!isEdge1)
                            {
                                continue;
                            }

                            stack.Push(nPush);
                        }
                    }
                }
            }

            return(foundLoop);
        }
        static bool DetectIsland(PNavColumn[,] columns, PNavPoint point, PNavPoint pointMax, int edgeGap, int verticalDrop, int islandIndex, PNavIsland island)
        {
            PNavColumn column = columns[point.x, point.z];

            if (column.type != ParallelNavColumnType.Walkable)
            {
                return(false);
            }

            PNavNode surfaceNode = column.SurfaceNode();

            if (surfaceNode == null)
            {
                return(false);
            }

            //already checked
            if (surfaceNode.islandIndex >= 0)
            {
                return(false);
            }

            surfaceNode.islandIndex = islandIndex;

            island.nodes.Add(surfaceNode);

            Queue <PNavPoint> queue = new Queue <PNavPoint>();

            queue.Enqueue(point);

            while (queue.Count > 0)
            {
                PNavPoint p = queue.Dequeue();

                PNavColumn c = columns[p.x, p.z];

                //check top edge
                PNavPoint pTopOut;

                bool addedTop = PNavMeshHelper.AddTop(columns, p, out pTopOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                if (addedTop)
                {
                    queue.Enqueue(pTopOut);
                }

                //check bottom edge
                PNavPoint pBottomOut;
                bool      addedBottom = PNavMeshHelper.AddBottom(columns, p, out pBottomOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                if (addedBottom)
                {
                    queue.Enqueue(pBottomOut);
                }

                //search left
                PNavPoint left = p;

                while (true)
                {
                    PNavPoint pLeftOut;

                    bool added = PNavMeshHelper.AddLeft(columns, left, out pLeftOut, pointMax, verticalDrop, edgeGap, islandIndex, island, queue);

                    if (!added)
                    {
                        break;
                    }
                    else
                    {
                        left = pLeftOut;
                    }
                }

                //search right

                PNavPoint right = p;

                while (true)
                {
                    PNavPoint pRightOut;

                    bool added = PNavMeshHelper.AddRight(columns, right, out pRightOut, pointMax, verticalDrop, edgeGap, islandIndex, island, queue);

                    if (!added)
                    {
                        break;
                    }
                    else
                    {
                        right = pRightOut;
                    }
                }
            }

            return(true);
        }