Ejemplo n.º 1
0
        /** Prepares the path. Searches for start and end nodes and does some simple checking if a path is at all possible */
        public override void Prepare()
        {
            AstarProfiler.StartProfile("Get Nearest");

            //Initialize the NNConstraint
            nnConstraint.tags = enabledTags;
            NNInfo startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint, startHint);
            //Tell the NNConstraint which node was found as the start node if it is a PathNNConstraint and not a normal NNConstraint
            var pathNNConstraint = nnConstraint as PathNNConstraint;

            if (pathNNConstraint != null)
            {
                pathNNConstraint.SetStart(startNNInfo.node);
            }

            startPoint = startNNInfo.clampedPosition;

            startIntPoint = (Int3)startPoint;
            startNode     = startNNInfo.node;

            //If it is declared that this path type has an end point
            //Some path types might want to use most of the ABPath code, but will not have an explicit end point at this stage
            if (hasEndPoint)
            {
                NNInfo endNNInfo = AstarPath.active.GetNearest(endPoint, nnConstraint, endHint);
                endPoint = endNNInfo.clampedPosition;

                // Note, other methods assume hTarget is (Int3)endPoint
                hTarget     = (Int3)endPoint;
                endNode     = endNNInfo.node;
                hTargetNode = endNode;
            }

            AstarProfiler.EndProfile();

#if ASTARDEBUG
            if (startNode != null)
            {
                Debug.DrawLine((Vector3)startNode.position, startPoint, Color.blue);
            }
            if (endNode != null)
            {
                Debug.DrawLine((Vector3)endNode.position, endPoint, Color.blue);
            }
#endif

            if (startNode == null && (hasEndPoint && endNode == null))
            {
                Error();
                LogError("Couldn't find close nodes to the start point or the end point");
                return;
            }

            if (startNode == null)
            {
                Error();
                LogError("Couldn't find a close node to the start point");
                return;
            }

            if (endNode == null && hasEndPoint)
            {
                Error();
                LogError("Couldn't find a close node to the end point");
                return;
            }

            if (!startNode.Walkable)
            {
#if ASTARDEBUG
                Debug.DrawRay(startPoint, Vector3.up, Color.red);
                Debug.DrawLine(startPoint, (Vector3)startNode.position, Color.red);
#endif
                Error();
                LogError("The node closest to the start point is not walkable");
                return;
            }

            if (hasEndPoint && !endNode.Walkable)
            {
                Error();
                LogError("The node closest to the end point is not walkable");
                return;
            }

            if (hasEndPoint && startNode.Area != endNode.Area)
            {
                Error();
                LogError("There is no valid path to the target (start area: " + startNode.Area + ", target area: " + endNode.Area + ")");
                return;
            }
        }
Ejemplo n.º 2
0
        public override void Apply(Path p)
        {
            List <GraphNode> path       = p.path;
            List <Vector3>   vectorPath = p.vectorPath;

            if (path == null || path.Count == 0 || vectorPath == null || vectorPath.Count != path.Count)
            {
                return;
            }

            List <Vector3> funnelPath = ListPool <Vector3> .Claim();

            // Claim temporary lists and try to find lists with a high capacity
            List <Vector3> left = ListPool <Vector3> .Claim(path.Count + 1);

            List <Vector3> right = ListPool <Vector3> .Claim(path.Count + 1);

            AstarProfiler.StartProfile("Construct Funnel");

            // Add start point
            left.Add(vectorPath[0]);
            right.Add(vectorPath[0]);

            // Loop through all nodes in the path (except the last one)
            for (int i = 0; i < path.Count - 1; i++)
            {
                // Get the portal between path[i] and path[i+1] and add it to the left and right lists
                bool portalWasAdded = path[i].GetPortal(path[i + 1], left, right, false);

                if (!portalWasAdded)
                {
                    // Fallback, just use the positions of the nodes
                    left.Add((Vector3)path[i].position);
                    right.Add((Vector3)path[i].position);

                    left.Add((Vector3)path[i + 1].position);
                    right.Add((Vector3)path[i + 1].position);
                }
            }

            // Add end point
            left.Add(vectorPath[vectorPath.Count - 1]);
            right.Add(vectorPath[vectorPath.Count - 1]);

            if (!RunFunnel(left, right, funnelPath))
            {
                // If funnel algorithm failed, degrade to simple line
                funnelPath.Add(vectorPath[0]);
                funnelPath.Add(vectorPath[vectorPath.Count - 1]);
            }

#if BNICKSON_UPDATED
            if (0f != obstaclePadding)
            {
                PadFunnelPath(ref funnelPath, ref path, p);
            }
#endif

            // Release lists back to the pool
            ListPool <Vector3> .Release(p.vectorPath);

            p.vectorPath = funnelPath;

            ListPool <Vector3> .Release(left);

            ListPool <Vector3> .Release(right);
        }
Ejemplo n.º 3
0
        /** Main pathfinding method.
         * This method will calculate the paths in the pathfinding queue.
         *
         * \see CalculatePathsThreaded
         * \see StartPath
         */
        IEnumerator CalculatePaths(PathHandler pathHandler)
        {
            // Max number of ticks before yielding/sleeping
            long maxTicks   = (long)(astar.maxFrameTime * 10000);
            long targetTick = System.DateTime.UtcNow.Ticks + maxTicks;

            while (true)
            {
                // The path we are currently calculating
                Path p = null;

                AstarProfiler.StartProfile("Path Queue");

                // Try to get the next path to be calculated
                bool blockedBefore = false;
                while (p == null)
                {
                    try {
                        p              = queue.PopNoBlock(blockedBefore);
                        blockedBefore |= p == null;
                    } catch (ThreadControlQueue.QueueTerminationException) {
                        yield break;
                    }

                    if (p == null)
                    {
                        AstarProfiler.EndProfile();
                        yield return(null);

                        AstarProfiler.StartProfile("Path Queue");
                    }
                }

                AstarProfiler.EndProfile();

                AstarProfiler.StartProfile("Path Calc");

                IPathInternals ip = (IPathInternals)p;

                // Max number of ticks we are allowed to continue working in one run
                // One tick is 1/10000 of a millisecond
                maxTicks = (long)(astar.maxFrameTime * 10000);

                ip.PrepareBase(pathHandler);

                // Now processing the path
                // Will advance to Processing
                ip.AdvanceState(PathState.Processing);

                // Call some callbacks
                // It needs to be stored in a local variable to avoid race conditions
                var tmpOnPathPreSearch = OnPathPreSearch;
                if (tmpOnPathPreSearch != null)
                {
                    tmpOnPathPreSearch(p);
                }

                // Tick for when the path started, used for calculating how long time the calculation took
                long startTicks = System.DateTime.UtcNow.Ticks;
                long totalTicks = 0;

                AstarProfiler.StartFastProfile(8);

                AstarProfiler.StartFastProfile(0);
                //Prepare the path
                AstarProfiler.StartProfile("Path Prepare");
                ip.Prepare();
                AstarProfiler.EndProfile("Path Prepare");
                AstarProfiler.EndFastProfile(0);

                // Check if the Prepare call caused the path to complete
                // If this happens the path usually failed
                if (!p.IsDone())
                {
                    // For debug uses, we set the last computed path to p, so we can view debug info on it in the editor (scene view).
                    astar.debugPathData = ip.PathHandler;
                    astar.debugPathID   = p.pathID;

                    // Initialize the path, now ready to begin search
                    AstarProfiler.StartProfile("Path Initialize");
                    ip.Initialize();
                    AstarProfiler.EndProfile();

                    // The error can turn up in the Init function
                    while (!p.IsDone())
                    {
                        // Do some work on the path calculation.
                        // The function will return when it has taken too much time
                        // or when it has finished calculation
                        AstarProfiler.StartFastProfile(2);

                        AstarProfiler.StartProfile("Path Calc Step");
                        ip.CalculateStep(targetTick);
                        AstarProfiler.EndFastProfile(2);

                        AstarProfiler.EndProfile();

                        // If the path has finished calculation, we can break here directly instead of sleeping
                        // Improves latency
                        if (p.IsDone())
                        {
                            break;
                        }

                        AstarProfiler.EndFastProfile(8);
                        totalTicks += System.DateTime.UtcNow.Ticks - startTicks;
                        // Yield/sleep so other threads can work

                        AstarProfiler.EndProfile();
                        yield return(null);

                        AstarProfiler.StartProfile("Path Calc");

                        startTicks = System.DateTime.UtcNow.Ticks;
                        AstarProfiler.StartFastProfile(8);

                        // Cancel function (and thus the thread) if no more paths should be accepted.
                        // This is done when the A* object is about to be destroyed
                        // The path is returned and then this function will be terminated (see similar IF statement higher up in the function)
                        if (queue.IsTerminating)
                        {
                            p.FailWithError("AstarPath object destroyed");
                        }

                        targetTick = System.DateTime.UtcNow.Ticks + maxTicks;
                    }

                    totalTicks += System.DateTime.UtcNow.Ticks - startTicks;
                    p.duration  = totalTicks * 0.0001F;

                                        #if ProfileAstar
                    System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted);
                                        #endif
                }

                // Cleans up node tagging and other things
                ip.Cleanup();

                AstarProfiler.EndFastProfile(8);

                // Call the immediate callback
                // It needs to be stored in a local variable to avoid race conditions
                var tmpImmediateCallback = p.immediateCallback;
                if (tmpImmediateCallback != null)
                {
                    tmpImmediateCallback(p);
                }

                AstarProfiler.StartFastProfile(13);

                // It needs to be stored in a local variable to avoid race conditions
                var tmpOnPathPostSearch = OnPathPostSearch;
                if (tmpOnPathPostSearch != null)
                {
                    tmpOnPathPostSearch(p);
                }

                AstarProfiler.EndFastProfile(13);

                // Push the path onto the return stack
                // It will be detected by the main Unity thread and returned as fast as possible (the next late update)
                returnQueue.Enqueue(p);

                ip.AdvanceState(PathState.ReturnQueue);

                AstarProfiler.EndProfile();

                // Wait a bit if we have calculated a lot of paths
                if (System.DateTime.UtcNow.Ticks > targetTick)
                {
                    yield return(null);

                    targetTick = System.DateTime.UtcNow.Ticks + maxTicks;
                }
            }
        }
Ejemplo n.º 4
0
        public override void CalculateStep(long targetTick)
        {
            int counter = 0;

            //Continue to search while there hasn't ocurred an error and the end hasn't been found
            while (CompleteState == PathCompleteState.NotCalculated)
            {
                searchedNodes++;

//--- Here's the important stuff
                //Close the current node, if the current node satisfies the ending condition, the path is finished
                if (endingCondition.TargetFound(currentR))
                {
                    CompleteState = PathCompleteState.Complete;
                    break;
                }

                if (!currentR.flag1)
                {
                    //Add Node to allNodes
                    allNodes.Add(currentR.node);
                    currentR.flag1 = true;
                }

#if ASTARDEBUG
                Debug.DrawRay((Vector3)currentR.node.position, Vector3.up * 5, Color.cyan);
#endif

//--- Here the important stuff ends

                AstarProfiler.StartFastProfile(4);
                //Debug.DrawRay ((Vector3)currentR.node.Position, Vector3.up*2,Color.red);

                //Loop through all walkable neighbours of the node and add them to the open list.
                currentR.node.Open(this, currentR, pathHandler);

                AstarProfiler.EndFastProfile(4);

                //any nodes left to search?
                if (pathHandler.HeapEmpty())
                {
                    CompleteState = PathCompleteState.Complete;
                    break;
                }


                //Select the node with the lowest F score and remove it from the open list
                AstarProfiler.StartFastProfile(7);
                currentR = pathHandler.PopNode();
                AstarProfiler.EndFastProfile(7);

                //Check for time every 500 nodes, roughly every 0.5 ms usually
                if (counter > 500)
                {
                    //Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
                    if (System.DateTime.UtcNow.Ticks >= targetTick)
                    {
                        //Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
                        return;
                    }
                    counter = 0;

                    if (searchedNodes > 1000000)
                    {
                        throw new System.Exception("Probable infinite loop. Over 1,000,000 nodes searched");
                    }
                }

                counter++;
            }
        }
Ejemplo n.º 5
0
        protected NavmeshTile BuildTileMesh(Voxelize vox, int x, int z, int threadIndex = 0)
        {
            AstarProfiler.StartProfile("Build Tile");
            AstarProfiler.StartProfile("Init");

            vox.borderSize   = TileBorderSizeInVoxels;
            vox.forcedBounds = CalculateTileBoundsWithBorder(x, z);
            vox.width        = tileSizeX + vox.borderSize * 2;
            vox.depth        = tileSizeZ + vox.borderSize * 2;

            if (!useTiles && relevantGraphSurfaceMode == RelevantGraphSurfaceMode.OnlyForCompletelyInsideTile)
            {
                // This best reflects what the user would actually want
                vox.relevantGraphSurfaceMode = RelevantGraphSurfaceMode.RequireForAll;
            }
            else
            {
                vox.relevantGraphSurfaceMode = relevantGraphSurfaceMode;
            }

            vox.minRegionSize = Mathf.RoundToInt(minRegionSize / (cellSize * cellSize));

            AstarProfiler.EndProfile("Init");


            // Init voxelizer
            vox.Init();
            vox.VoxelizeInput(transform, CalculateTileBoundsWithBorder(x, z));

            AstarProfiler.StartProfile("Filter Ledges");


            vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight);

            AstarProfiler.EndProfile("Filter Ledges");

            AstarProfiler.StartProfile("Filter Low Height Spans");
            vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight);
            AstarProfiler.EndProfile("Filter Low Height Spans");

            vox.BuildCompactField();
            vox.BuildVoxelConnections();
            vox.ErodeWalkableArea(CharacterRadiusInVoxels);
            vox.BuildDistanceField();
            vox.BuildRegions();

            var cset = new VoxelContourSet();

            vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES | Voxelize.RC_CONTOUR_TESS_TILE_EDGES);

            VoxelMesh mesh;

            vox.BuildPolyMesh(cset, 3, out mesh);

            AstarProfiler.StartProfile("Build Nodes");

            // Position the vertices correctly in graph space (all tiles are laid out on the xz plane with the (0,0) tile at the origin)
            for (int i = 0; i < mesh.verts.Length; i++)
            {
                mesh.verts[i] *= Int3.Precision;
            }
            vox.transformVoxel2Graph.Transform(mesh.verts);

            NavmeshTile tile = CreateTile(vox, mesh, x, z, threadIndex);

            AstarProfiler.EndProfile("Build Nodes");

            AstarProfiler.EndProfile("Build Tile");
            return(tile);
        }
Ejemplo n.º 6
0
        /** Main pathfinding method (multithreaded).
         * This method will calculate the paths in the pathfinding queue when multithreading is enabled.
         *
         * \see CalculatePaths
         * \see StartPath
         *
         * \astarpro
         */
        void CalculatePathsThreaded(PathHandler pathHandler)
        {
#if !ASTAR_FAST_BUT_NO_EXCEPTIONS
            try {
#endif

            // Max number of ticks we are allowed to continue working in one run.
            // One tick is 1/10000 of a millisecond.
            // We need to check once in a while if the thread should be stopped.
            long maxTicks   = (long)(10 * 10000);
            long targetTick = System.DateTime.UtcNow.Ticks + maxTicks;

            while (true)
            {
                // The path we are currently calculating
                Path path = queue.Pop();
                // Access the internal implementation methods
                IPathInternals ipath = (IPathInternals)path;


                AstarProfiler.StartFastProfile(0);
                ipath.PrepareBase(pathHandler);

                // Now processing the path
                // Will advance to Processing
                ipath.AdvanceState(PathState.Processing);

                // Call some callbacks
                if (OnPathPreSearch != null)
                {
                    OnPathPreSearch(path);
                }

                // Tick for when the path started, used for calculating how long time the calculation took
                long startTicks = System.DateTime.UtcNow.Ticks;

                // Prepare the path
                ipath.Prepare();

                AstarProfiler.EndFastProfile(0);

                if (!path.IsDone())
                {
                    // For visualization purposes, we set the last computed path to p, so we can view debug info on it in the editor (scene view).
                    astar.debugPathData = ipath.PathHandler;
                    astar.debugPathID   = path.pathID;

                    AstarProfiler.StartFastProfile(1);

                    // Initialize the path, now ready to begin search
                    ipath.Initialize();

                    AstarProfiler.EndFastProfile(1);

                    // Loop while the path has not been fully calculated
                    while (!path.IsDone())
                    {
                        // Do some work on the path calculation.
                        // The function will return when it has taken too much time
                        // or when it has finished calculation
                        AstarProfiler.StartFastProfile(2);
                        ipath.CalculateStep(targetTick);
                        AstarProfiler.EndFastProfile(2);

                        targetTick = System.DateTime.UtcNow.Ticks + maxTicks;

                        // Cancel function (and thus the thread) if no more paths should be accepted.
                        // This is done when the A* object is about to be destroyed
                        // The path is returned and then this function will be terminated
                        if (queue.IsTerminating)
                        {
                            path.FailWithError("AstarPath object destroyed");
                        }
                    }

                    path.duration = (System.DateTime.UtcNow.Ticks - startTicks) * 0.0001F;

#if ProfileAstar
                    System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted);
                    System.Threading.Interlocked.Add(ref AstarPath.TotalSearchTime, System.DateTime.UtcNow.Ticks - startTicks);
#endif
                }

                // Cleans up node tagging and other things
                ipath.Cleanup();

                AstarProfiler.StartFastProfile(9);

                if (path.immediateCallback != null)
                {
                    path.immediateCallback(path);
                }

                if (OnPathPostSearch != null)
                {
                    OnPathPostSearch(path);
                }

                // Push the path onto the return stack
                // It will be detected by the main Unity thread and returned as fast as possible (the next late update hopefully)
                returnQueue.Enqueue(path);

                // Will advance to ReturnQueue
                ipath.AdvanceState(PathState.ReturnQueue);

                AstarProfiler.EndFastProfile(9);
            }
#if !ASTAR_FAST_BUT_NO_EXCEPTIONS
        }

        catch (System.Exception e) {
#if !NETFX_CORE
            if (e is ThreadAbortException || e is ThreadControlQueue.QueueTerminationException)
#else
            if (e is ThreadControlQueue.QueueTerminationException)
#endif
            {
                if (astar.logPathResults == PathLog.Heavy)
                {
                    Debug.LogWarning("Shutting down pathfinding thread #" + pathHandler.threadID);
                }
                return;
            }
            Debug.LogException(e);
            Debug.LogError("Unhandled exception during pathfinding. Terminating.");
            // Unhandled exception, kill pathfinding
            queue.TerminateReceivers();
        }
#endif

            Debug.LogError("Error : This part should never be reached.");
            queue.ReceiverTerminated();
        }
Ejemplo n.º 7
0
        /** Main pathfinding method (multithreaded).
         * This method will calculate the paths in the pathfinding queue when multithreading is enabled.
         *
         * \see CalculatePaths
         * \see StartPath
         *
         * \astarpro
         */
        void CalculatePathsThreaded(PathThreadInfo threadInfo)
        {
#if !ASTAR_FAST_BUT_NO_EXCEPTIONS
            try {
#endif

            //Initialize memory for this thread
            PathHandler runData = threadInfo.runData;

            if (runData.nodes == null)
            {
                throw new System.NullReferenceException("NodeRuns must be assigned to the threadInfo.runData.nodes field before threads are started\nthreadInfo is an argument to the thread functions");
            }

            //Max number of ticks before yielding/sleeping
            long maxTicks   = (long)(astar.maxFrameTime * 10000);
            long targetTick = System.DateTime.UtcNow.Ticks + maxTicks;

            while (true)
            {
                // The path we are currently calculating
                Path p = queue.Pop();
                // Access the internal implementation methods
                IPathInternals ip = (IPathInternals)p;

                //Max number of ticks we are allowed to continue working in one run
                //One tick is 1/10000 of a millisecond
                maxTicks = (long)(astar.maxFrameTime * 10000);


                AstarProfiler.StartFastProfile(0);
                ip.PrepareBase(runData);

                //Now processing the path
                //Will advance to Processing
                ip.AdvanceState(PathState.Processing);

                //Call some callbacks
                if (OnPathPreSearch != null)
                {
                    OnPathPreSearch(p);
                }

                //Tick for when the path started, used for calculating how long time the calculation took
                long startTicks = System.DateTime.UtcNow.Ticks;
                long totalTicks = 0;

                //Prepare the path
                ip.Prepare();

                AstarProfiler.EndFastProfile(0);

                if (!p.IsDone())
                {
                    //For debug uses, we set the last computed path to p, so we can view debug info on it in the editor (scene view).
                    astar.debugPathData = ip.PathHandler;
                    astar.debugPathID   = p.pathID;

                    AstarProfiler.StartFastProfile(1);

                    //Initialize the path, now ready to begin search
                    ip.Initialize();

                    AstarProfiler.EndFastProfile(1);

                    //The error can turn up in the Init function
                    while (!p.IsDone())
                    {
                        //Do some work on the path calculation.
                        //The function will return when it has taken too much time
                        //or when it has finished calculation
                        AstarProfiler.StartFastProfile(2);
                        ip.CalculateStep(targetTick);

                        AstarProfiler.EndFastProfile(2);

                        // If the path has finished calculation, we can break here directly instead of sleeping
                        if (p.IsDone())
                        {
                            break;
                        }

                        // Yield/sleep so other threads can work
                        totalTicks += System.DateTime.UtcNow.Ticks - startTicks;
                        Thread.Sleep(0);
                        startTicks = System.DateTime.UtcNow.Ticks;

                        targetTick = startTicks + maxTicks;

                        // Cancel function (and thus the thread) if no more paths should be accepted.
                        // This is done when the A* object is about to be destroyed
                        // The path is returned and then this function will be terminated
                        if (queue.IsTerminating)
                        {
                            p.Error();
                        }
                    }

                    totalTicks += System.DateTime.UtcNow.Ticks - startTicks;
                    p.duration  = totalTicks * 0.0001F;

#if ProfileAstar
                    System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted);
                    System.Threading.Interlocked.Add(ref AstarPath.TotalSearchTime, totalTicks);
#endif
                }

                // Cleans up node tagging and other things
                ip.Cleanup();

                AstarProfiler.StartFastProfile(9);

                if (p.immediateCallback != null)
                {
                    p.immediateCallback(p);
                }

                if (OnPathPostSearch != null)
                {
                    OnPathPostSearch(p);
                }

                // Push the path onto the return stack
                // It will be detected by the main Unity thread and returned as fast as possible (the next late update hopefully)
                returnQueue.Enqueue(p);

                // Will advance to ReturnQueue
                ip.AdvanceState(PathState.ReturnQueue);

                AstarProfiler.EndFastProfile(9);

                // Wait a bit if we have calculated a lot of paths
                if (System.DateTime.UtcNow.Ticks > targetTick)
                {
                    Thread.Sleep(1);
                    targetTick = System.DateTime.UtcNow.Ticks + maxTicks;
                }
            }
#if !ASTAR_FAST_BUT_NO_EXCEPTIONS
        }

        catch (System.Exception e) {
#if !NETFX_CORE
            if (e is ThreadAbortException || e is ThreadControlQueue.QueueTerminationException)
#else
            if (e is ThreadControlQueue.QueueTerminationException)
#endif
            {
                if (astar.logPathResults == PathLog.Heavy)
                {
                    Debug.LogWarning("Shutting down pathfinding thread #" + threadInfo.threadIndex);
                }
                return;
            }
            Debug.LogException(e);
            Debug.LogError("Unhandled exception during pathfinding. Terminating.");
            //Unhandled exception, kill pathfinding
            queue.TerminateReceivers();
        }
#endif

            Debug.LogError("Error : This part should never be reached.");
            queue.ReceiverTerminated();
        }
Ejemplo n.º 8
0
        /** Calculates the path until completed or until the time has passed \a targetTick.
         * Usually a check is only done every 500 nodes if the time has passed \a targetTick.
         * Time/Ticks are got from System.DateTime.UtcNow.Ticks.
         *
         * Basic outline of what the function does for the standard path (Pathfinding.ABPath).
         * \code
         * while the end has not been found and no error has ocurred
         * check if we have reached the end
         * if so, exit and return the path
         *
         * open the current node, i.e loop through its neighbours, mark them as visited and put them on a heap
         *
         * check if there are still nodes left to process (or have we searched the whole graph)
         * if there are none, flag error and exit
         *
         * pop the next node of the heap and set it as current
         *
         * check if the function has exceeded the time limit
         * if so, return and wait for the function to get called again
         * \endcode
         */
        public override void CalculateStep(long targetTick)
        {
            int counter = 0;

            //Continue to search while there hasn't ocurred an error and the end hasn't been found
            while (CompleteState == PathCompleteState.NotCalculated)
            {
                searchedNodes++;

                //Close the current node, if the current node is the target node then the path is finished
                if (currentR.node == endNode)
                {
                    CompleteState = PathCompleteState.Complete;
                    break;
                }

                if (currentR.H < partialBestTarget.H)
                {
                    partialBestTarget = currentR;
                }

                AstarProfiler.StartFastProfile(4);
                //Debug.DrawRay ((Vector3)currentR.node.Position, Vector3.up*2,Color.red);

                //Loop through all walkable neighbours of the node and add them to the open list.
                currentR.node.Open(this, currentR, pathHandler);

                AstarProfiler.EndFastProfile(4);

                //any nodes left to search?
                if (pathHandler.HeapEmpty())
                {
                    Error();
                    LogError("No open points, whole area searched");
                    return;
                }


                //Select the node with the lowest F score and remove it from the open list
                AstarProfiler.StartFastProfile(7);
                currentR = pathHandler.PopNode();
                AstarProfiler.EndFastProfile(7);

                //Check for time every 500 nodes, roughly every 0.5 ms usually
                if (counter > 500)
                {
                    //Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
                    if (System.DateTime.UtcNow.Ticks >= targetTick)
                    {
                        //Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
                        return;
                    }
                    counter = 0;

                    if (searchedNodes > 1000000)
                    {
                        throw new System.Exception("Probable infinite loop. Over 1,000,000 nodes searched");
                    }
                }

                counter++;
            }


            AstarProfiler.StartProfile("Trace");

            if (CompleteState == PathCompleteState.Complete)
            {
                Trace(currentR);
            }
            else if (calculatePartial && partialBestTarget != null)
            {
                CompleteState = PathCompleteState.Partial;
                Trace(partialBestTarget);
            }

            AstarProfiler.EndProfile();
        }
Ejemplo n.º 9
0
        protected override void Prepare()
        {
            AstarProfiler.StartProfile("Get Nearest");


            nnConstraint.tags = enabledTags;
            var startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint);

            //Tell the NNConstraint which node was found as the start node if it is a PathNNConstraint and not a normal NNConstraint
            var pathNNConstraint = nnConstraint as PathNNConstraint;

            if (pathNNConstraint != null)
            {
                pathNNConstraint.SetStart(startNNInfo.node);
            }

            startPoint = startNNInfo.position;

            startIntPoint = (Int3)startPoint;
            startNode     = startNNInfo.node;

            if (startNode == null)
            {
                FailWithError("Couldn't find a node close to the start point");
                return;
            }

            if (!CanTraverse(startNode))
            {
                FailWithError("The node closest to the start point could not be traversed");
                return;
            }

            // If it is declared that this path type has an end point
            if (hasEndPoint)
            {
                var endNNInfo = AstarPath.active.GetNearest(endPoint, nnConstraint);
                endPoint = endNNInfo.position;
                endNode  = endNNInfo.node;

                if (endNode == null)
                {
                    FailWithError("Couldn't find a node close to the end point");
                    return;
                }

                // This should not trigger unless the user has modified the NNConstraint
                if (!CanTraverse(endNode))
                {
                    FailWithError("The node closest to the end point could not be traversed");
                    return;
                }

                // This should not trigger unless the user has modified the NNConstraint
                if (startNode.Area != endNode.Area)
                {
                    FailWithError("There is no valid path to the target");
                    return;
                }

#if !ASTAR_NO_GRID_GRAPH
                if (!EndPointGridGraphSpecialCase(endNNInfo.node))
#endif
                {
                    // Note, other methods assume hTarget is (Int3)endPoint
                    hTarget     = (Int3)endPoint;
                    hTargetNode = endNode;

                    // Mark end node with flag1 to mark it as a target point
                    pathHandler.GetPathNode(endNode).flag1 = true;
                }
            }

            AstarProfiler.EndProfile();
        }
Ejemplo n.º 10
0
        protected void ScanAllTiles(OnScanStatus statusCallback)
        {
#if ASTARDEBUG
            System.Console.WriteLine("Recast Graph -- Collecting Meshes");
#endif

#if BNICKSON_UPDATED
            editorTileSize = (int)(EditorVars.GridSize / cellSize);
#endif

            //----

            //Voxel grid size
            int gw = (int)(forcedBounds.size.x / cellSize + 0.5f);
            int gd = (int)(forcedBounds.size.z / cellSize + 0.5f);

            if (!useTiles)
            {
                tileSizeX = gw;
                tileSizeZ = gd;
            }
            else
            {
                tileSizeX = editorTileSize;
                tileSizeZ = editorTileSize;
            }

            //Number of tiles
            int tw = (gw + tileSizeX - 1) / tileSizeX;
            int td = (gd + tileSizeZ - 1) / tileSizeZ;

            tileXCount = tw;
            tileZCount = td;

            if (tileXCount * tileZCount > TileIndexMask + 1)
            {
                throw new System.Exception("Too many tiles (" + (tileXCount * tileZCount) + ") maximum is " + (TileIndexMask + 1) +
                                           "\nTry disabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* inspector.");
            }

            tiles = new NavmeshTile[tileXCount * tileZCount];

#if ASTARDEBUG
            System.Console.WriteLine("Recast Graph -- Creating Voxel Base");
#endif

            // If this is true, just fill the graph with empty tiles
            if (scanEmptyGraph)
            {
                for (int z = 0; z < td; z++)
                {
                    for (int x = 0; x < tw; x++)
                    {
                        tiles[z * tileXCount + x] = NewEmptyTile(x, z);
                    }
                }
                return;
            }

            AstarProfiler.StartProfile("Finding Meshes");
            List <ExtraMesh> extraMeshes;

#if !NETFX_CORE || UNITY_EDITOR
            System.Console.WriteLine("Collecting Meshes");
#endif
            CollectMeshes(out extraMeshes, forcedBounds);

            AstarProfiler.EndProfile("Finding Meshes");

            // A walkableClimb higher than walkableHeight can cause issues when generating the navmesh since then it can in some cases
            // Both be valid for a character to walk under an obstacle and climb up on top of it (and that cannot be handled with navmesh without links)
            // The editor scripts also enforce this but we enforce it here too just to be sure
            walkableClimb = Mathf.Min(walkableClimb, walkableHeight);

            //Create the voxelizer and set all settings
            var vox = new Voxelize(cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);
            vox.inputExtraMeshes = extraMeshes;

            vox.maxEdgeLength = maxEdgeLength;

            int lastInfoCallback = -1;
            var watch            = System.Diagnostics.Stopwatch.StartNew();

            //Generate all tiles
            for (int z = 0; z < td; z++)
            {
                for (int x = 0; x < tw; x++)
                {
                    int tileNum = z * tileXCount + x;
#if !NETFX_CORE || UNITY_EDITOR
                    System.Console.WriteLine("Generating Tile #" + (tileNum) + " of " + td * tw);
#endif

                    //Call statusCallback only 10 times since it is very slow in the editor
                    if (statusCallback != null && (tileNum * 10 / tiles.Length > lastInfoCallback || watch.ElapsedMilliseconds > 2000))
                    {
                        lastInfoCallback = tileNum * 10 / tiles.Length;
                        watch.Reset();
                        watch.Start();

                        statusCallback(new Progress(Mathf.Lerp(0.1f, 0.9f, tileNum / (float)tiles.Length), "Building Tile " + tileNum + "/" + tiles.Length));
                    }

                    BuildTileMesh(vox, x, z);
                }
            }

#if !NETFX_CORE
            System.Console.WriteLine("Assigning Graph Indices");
#endif

            if (statusCallback != null)
            {
                statusCallback(new Progress(0.9f, "Connecting tiles"));
            }

            //Assign graph index to nodes
            uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex(this);

            GraphNodeDelegateCancelable del = delegate(GraphNode n) {
                n.GraphIndex = graphIndex;
                return(true);
            };
            GetNodes(del);

#if BNICKSON_UPDATED
#if DEBUG
            if (useCenterTileOnly && (3 != tileXCount || 3 != tileZCount))
            {
                EB.Debug.LogError("RecastGenerator.ScanAllTiles() : Incorrect amount of tiles generated if ceneter tile is all that is required");
            }
#endif

            int centerXTile = (tileXCount / 2);
            int centerZTile = (tileZCount / 2);
#endif

            for (int z = 0; z < td; z++)
            {
                for (int x = 0; x < tw; x++)
                {
#if BNICKSON_UPDATED
                    // if we're only using the center tile, and this is not the center tile
                    if (useCenterTileOnly && !(centerZTile == z && centerXTile == x))
                    {
                        continue;
                    }
#endif

#if !NETFX_CORE
                    System.Console.WriteLine("Connecing Tile #" + (z * tileXCount + x) + " of " + td * tw);
#endif
                    if (x < tw - 1)
                    {
                        ConnectTiles(tiles[x + z * tileXCount], tiles[x + 1 + z * tileXCount]);
                    }
                    if (z < td - 1)
                    {
                        ConnectTiles(tiles[x + z * tileXCount], tiles[x + (z + 1) * tileXCount]);
                    }
                }
            }

            AstarProfiler.PrintResults();
        }
Ejemplo n.º 11
0
        /** Calculates the path until completed or until the time has passed \a targetTick.
         * Usually a check is only done every 500 nodes if the time has passed \a targetTick.
         * Time/Ticks are got from System.DateTime.UtcNow.Ticks.
         *
         * Basic outline of what the function does for the standard path (Pathfinding.ABPath).
         * \code
         * while the end has not been found and no error has ocurred
         * check if we have reached the end
         * if so, exit and return the path
         *
         * open the current node, i.e loop through its neighbours, mark them as visited and put them on a heap
         *
         * check if there are still nodes left to process (or have we searched the whole graph)
         * if there are none, flag error and exit
         *
         * pop the next node of the heap and set it as current
         *
         * check if the function has exceeded the time limit
         * if so, return and wait for the function to get called again
         * \endcode
         */
        public override void CalculateStep(long targetTick)
        {
            int counter = 0;

            //Continue to search while there hasn't ocurred an error and the end hasn't been found
            while (CompleteState == PathCompleteState.NotCalculated)
            {
                searchedNodes++;

                //Close the current node, if the current node is the target node then the path is finished
                if (currentR.node == endNode)
                {
                    CompleteState = PathCompleteState.Complete;
                    break;
                }

                if (currentR.h < partialBestTarget.h)
                {
                    partialBestTarget = currentR;
                }

                //Loop through all walkable neighbours of the node and add them to the open list.
                currentR.node.Open(runData, currentR, hTarget, this);

                //any nodes left to search?
                if (runData.open.numberOfItems <= 1)
                {
                    Error();
                    LogError("No open points, whole area searched");
                    return;
                }

                //Select the node with the lowest F score and remove it from the open list
                currentR = runData.open.Remove();

                //Check for time every 500 nodes, roughly every 0.5 ms usually
                if (counter > 500)
                {
                    //Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
                    if (System.DateTime.UtcNow.Ticks >= targetTick)
                    {
                        //Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
                        return;
                    }
                    counter = 0;
                }

                counter++;
            }

            AstarProfiler.StartProfile("Trace");

            if (CompleteState == PathCompleteState.Complete)
            {
                Trace(currentR);
            }
            else if (calculatePartial && partialBestTarget != null)
            {
                CompleteState = PathCompleteState.Partial;
                Trace(partialBestTarget);
            }

            AstarProfiler.EndProfile();
        }
Ejemplo n.º 12
0
        /** Prepares the path. Searches for start and end nodes and does some simple checking if a path is at all possible */
        public override void Prepare()
        {
            AstarProfiler.StartProfile("Get Nearest");

            //Initialize the NNConstraint
            nnConstraint.tags = enabledTags;
            NNInfo startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint, startHint);

            //Tell the NNConstraint which node was found as the start node if it is a PathNNConstraint and not a normal NNConstraint
            PathNNConstraint pathNNConstraint = nnConstraint as PathNNConstraint;

            if (pathNNConstraint != null)
            {
                pathNNConstraint.SetStart(startNNInfo.node);
            }

            startPoint    = startNNInfo.clampedPosition;
            startIntPoint = (Int3)startPoint;
            startNode     = startNNInfo.node;

            //If it is declared that this path type has an end point
            //Some path types might want to use most of the ABPath code, but will not have an explicit end point at start
            if (hasEndPoint)
            {
                NNInfo endNNInfo = AstarPath.active.GetNearest(endPoint, nnConstraint, endHint);
                endPoint = endNNInfo.clampedPosition;
                hTarget  = (Int3)endPoint;
                endNode  = endNNInfo.node;
            }

            AstarProfiler.EndProfile();


            if (startNode == null && (hasEndPoint && endNode == null))
            {
                Error();
                LogError("Couldn't find close nodes to the start point or the end point");
                return;
            }
            if (startNode == null)
            {
                Error();
                LogError("Couldn't find a close node to the start point");
                return;
            }
            if (endNode == null && hasEndPoint)
            {
                Error();
                LogError("Couldn't find a close node to the end point");
                return;
            }

            if (!startNode.walkable)
            {
                Error();
                LogError("The node closest to the start point is not walkable");
                return;
            }

            if (hasEndPoint && !endNode.walkable)
            {
                Error();
                LogError("The node closest to the end point is not walkable");
                return;
            }

            if (hasEndPoint && startNode.area != endNode.area)
            {
                Error();
                LogError("There is no valid path to the target (start area: " + startNode.area + ", target area: " + endNode.area + ")");
                return;
            }
        }
Ejemplo n.º 13
0
        void IUpdatableGraph.UpdateArea(GraphUpdateObject guo)
        {
            // Figure out which tiles are affected
            // Expand TileBorderSizeInWorldUnits voxels in all directions to make sure
            // all tiles that could be affected by the update are recalculated.
            var affectedTiles = GetTouchingTiles(guo.bounds, TileBorderSizeInWorldUnits);

            if (!guo.updatePhysics)
            {
                for (int z = affectedTiles.ymin; z <= affectedTiles.ymax; z++)
                {
                    for (int x = affectedTiles.xmin; x <= affectedTiles.xmax; x++)
                    {
                        NavmeshTile tile = tiles[z * tileXCount + x];
                        NavMeshGraph.UpdateArea(guo, tile);
                    }
                }
                return;
            }

            Voxelize vox = globalVox;

            if (vox == null)
            {
                throw new System.InvalidOperationException("No Voxelizer object. UpdateAreaInit should have been called before this function.");
            }

            AstarProfiler.StartProfile("Build Tiles");

            var allMeshes = vox.inputMeshes;
            // Build the new tiles
            // If we are updating more than one tile it makes sense to do a more optimized pass for assigning each mesh to the buckets that it intersects.
            var buckets = PutMeshesIntoTileBuckets(vox.inputMeshes, affectedTiles);

            for (int x = affectedTiles.xmin; x <= affectedTiles.xmax; x++)
            {
                for (int z = affectedTiles.ymin; z <= affectedTiles.ymax; z++)
                {
                    vox.inputMeshes = buckets[(z - affectedTiles.ymin) * affectedTiles.Width + (x - affectedTiles.xmin)];
                    stagingTiles.Add(BuildTileMesh(vox, x, z));
                }
            }

            for (int i = 0; i < buckets.Length; i++)
            {
                ListPool <RasterizationMesh> .Release(buckets[i]);
            }
            for (int i = 0; i < allMeshes.Count; i++)
            {
                allMeshes[i].Pool();
            }
            ListPool <RasterizationMesh> .Release(ref allMeshes);

            vox.inputMeshes = null;

            uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(this);

            // Set the correct graph index
            for (int i = 0; i < stagingTiles.Count; i++)
            {
                NavmeshTile tile  = stagingTiles[i];
                GraphNode[] nodes = tile.nodes;

                for (int j = 0; j < nodes.Length; j++)
                {
                    nodes[j].GraphIndex = graphIndex;
                }
            }

            AstarProfiler.EndProfile("Build Tiles");
        }
Ejemplo n.º 14
0
        /// <summary>Prepares the path. Searches for start and end nodes and does some simple checking if a path is at all possible</summary>
        protected override void Prepare()
        {
            AstarProfiler.StartProfile("Get Nearest");

            //Initialize the NNConstraint
            nnConstraint.tags = enabledTags;
            var startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint);

            //Tell the NNConstraint which node was found as the start node if it is a PathNNConstraint and not a normal NNConstraint
            var pathNNConstraint = nnConstraint as PathNNConstraint;

            if (pathNNConstraint != null)
            {
                pathNNConstraint.SetStart(startNNInfo.node);
            }

            startPoint = startNNInfo.position;

            startIntPoint = (Int3)startPoint;
            startNode     = startNNInfo.node;

            if (startNode == null)
            {
                FailWithError("Couldn't find a node close to the start point");
                return;
            }

            if (!CanTraverse(startNode))
            {
                FailWithError("The node closest to the start point could not be traversed");
                return;
            }

            // If it is declared that this path type has an end point
            // Some path types might want to use most of the ABPath code, but will not have an explicit end point at this stage
            if (hasEndPoint)
            {
                var endNNInfo = AstarPath.active.GetNearest(endPoint, nnConstraint);
                endPoint = endNNInfo.position;
                endNode  = endNNInfo.node;

                if (endNode == null)
                {
                    FailWithError("Couldn't find a node close to the end point");
                    return;
                }

                // This should not trigger unless the user has modified the NNConstraint
                if (!CanTraverse(endNode))
                {
                    FailWithError("The node closest to the end point could not be traversed");
                    return;
                }

                // This should not trigger unless the user has modified the NNConstraint
                if (startNode.Area != endNode.Area)
                {
                    FailWithError("There is no valid path to the target");
                    return;
                }

#if !ASTAR_NO_GRID_GRAPH
                // Potentially we want to special case grid graphs a bit
                // to better support some kinds of games
                // If this returns true it will overwrite the
                // endNode, endPoint, hTarget and hTargetNode fields
                if (!EndPointGridGraphSpecialCase(endNNInfo.node))
#endif
                {
                    // Note, other methods assume hTarget is (Int3)endPoint
                    hTarget     = (Int3)endPoint;
                    hTargetNode = endNode;

                    // Mark end node with flag1 to mark it as a target point
                    pathHandler.GetPathNode(endNode).flag1 = true;
                }
            }

            AstarProfiler.EndProfile();
        }
Ejemplo n.º 15
0
        protected override void CalculateStep(long targetTick)
        {
            int counter = 0;

            // Continue to search as long as we haven't encountered an error and we haven't found the target
            while (CompleteState == PathCompleteState.NotCalculated)
            {
                // @Performance Just for debug info
                searchedNodes++;

                // The node might be the target node for one of the paths
                if (currentR.flag1)
                {
                    // Close the current node, if the current node is the target node then the path is finnished
                    for (int i = 0; i < targetNodes.Length; i++)
                    {
                        if (!targetsFound[i] && currentR.node == targetNodes[i])
                        {
                            FoundTarget(currentR, i);
                            if (CompleteState != PathCompleteState.NotCalculated)
                            {
                                break;
                            }
                        }
                    }

                    if (targetNodeCount <= 0)
                    {
                        CompleteState = PathCompleteState.Complete;
                        break;
                    }
                }

                // Loop through all walkable neighbours of the node and add them to the open list.
                currentR.node.Open(this, currentR, pathHandler);

                // Any nodes left to search?
                if (pathHandler.heap.isEmpty)
                {
                    CompleteState = PathCompleteState.Complete;
                    break;
                }

                // Select the node with the lowest F score and remove it from the open list
                AstarProfiler.StartFastProfile(7);
                currentR = pathHandler.heap.Remove();
                AstarProfiler.EndFastProfile(7);

                // Check for time every 500 nodes, roughly every 0.5 ms usually
                if (counter > 500)
                {
                    // Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
                    if (System.DateTime.UtcNow.Ticks >= targetTick)
                    {
                        // Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
                        return;
                    }

                    counter = 0;
                }

                counter++;
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Calculates the path until completed or until the time has passed targetTick.
        /// Usually a check is only done every 500 nodes if the time has passed targetTick.
        /// Time/Ticks are got from System.DateTime.UtcNow.Ticks.
        ///
        /// Basic outline of what the function does for the standard path (Pathfinding.ABPath).
        /// <code>
        /// while the end has not been found and no error has occurred
        /// check if we have reached the end
        /// if so, exit and return the path
        ///
        /// open the current node, i.e loop through its neighbours, mark them as visited and put them on a heap
        ///
        /// check if there are still nodes left to process (or have we searched the whole graph)
        /// if there are none, flag error and exit
        ///
        /// pop the next node of the heap and set it as current
        ///
        /// check if the function has exceeded the time limit
        /// if so, return and wait for the function to get called again
        /// </code>
        /// </summary>
        protected override void CalculateStep(long targetTick)
        {
            int counter = 0;

            // Continue to search as long as we haven't encountered an error and we haven't found the target
            while (CompleteState == PathCompleteState.NotCalculated)
            {
                searchedNodes++;

                // Close the current node, if the current node is the target node then the path is finished
                if (currentR.flag1)
                {
                    // We found a target point
                    // Mark that node as the end point
                    CompleteWith(currentR.node);
                    break;
                }

                if (currentR.H < partialBestTarget.H)
                {
                    partialBestTarget = currentR;
                }

                AstarProfiler.StartFastProfile(4);

                // Loop through all walkable neighbours of the node and add them to the open list.
                currentR.node.Open(this, currentR, pathHandler);

                AstarProfiler.EndFastProfile(4);

                // Any nodes left to search?
                if (pathHandler.heap.isEmpty)
                {
                    if (calculatePartial && partialBestTarget != null)
                    {
                        CompleteState = PathCompleteState.Partial;
                        Trace(partialBestTarget);
                    }
                    else
                    {
                        FailWithError("Searched whole area but could not find target");
                    }
                    return;
                }

                // Select the node with the lowest F score and remove it from the open list
                AstarProfiler.StartFastProfile(7);
                currentR = pathHandler.heap.Remove();
                AstarProfiler.EndFastProfile(7);

                // Check for time every 500 nodes, roughly every 0.5 ms usually
                if (counter > 500)
                {
                    // Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
                    if (System.DateTime.UtcNow.Ticks >= targetTick)
                    {
                        // Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
                        return;
                    }
                    counter = 0;

                    // Mostly for development
                    if (searchedNodes > 1000000)
                    {
                        throw new System.Exception("Probable infinite loop. Over 1,000,000 nodes searched");
                    }
                }

                counter++;
            }

            AstarProfiler.StartProfile("Trace");

            if (CompleteState == PathCompleteState.Complete)
            {
                Trace(currentR);
            }
            else if (calculatePartial && partialBestTarget != null)
            {
                CompleteState = PathCompleteState.Partial;
                Trace(partialBestTarget);
            }

            AstarProfiler.EndProfile();
        }
Ejemplo n.º 17
0
        public override void Scan()
        {
            AstarProfiler.Reset();
            //AstarProfiler.StartProfile ("Base Scan");

            //base.Scan ();

            //AstarProfiler.EndProfile ("Base Scan");
            if (useCRecast)
            {
                ScanCRecast();
            }
            else
            {
                MeshFilter[] filters;
                ExtraMesh[]  extraMeshes;

                if (!CollectMeshes(out filters, out extraMeshes))
                {
                    nodes = new Node[0];
                    return;
                }

                Voxelize vox = new Voxelize(cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);

                vox.maxEdgeLength      = maxEdgeLength;
                vox.forcedBounds       = forcedBounds;
                vox.includeOutOfBounds = includeOutOfBounds;


                //g.GetComponent<Voxelize>();
                vox.VoxelizeMesh(filters, extraMeshes);

                /*bool[,] open = new bool[width,depth];
                 * int[,] visited = new int[width+1,depth+1];
                 *
                 * for (int z=0;z<depth;z++) {
                 *      for (int x = 0;x < width;x++) {
                 *              open[x,z] = graphNodes[z*width+x].walkable;
                 *      }
                 * }*/

                /*for (int i=0;i<depth*width;i++) {
                 *      open[i] = graphNodes[i].walkable;
                 * }
                 *
                 *
                 * int wd = width*depth;
                 *
                 * List<int> boundary = new List<int>();
                 *
                 * int p = 0;
                 *
                 * for (int i=0;i<wd;i++) {
                 *      if (!open[i]) {
                 *              boundary.Add (i);
                 *
                 *              p = i;
                 *
                 *              int backtrack = i-1;
                 *
                 *
                 *      }*/

                vox.ErodeWalkableArea(Mathf.CeilToInt(2 * characterRadius / cellSize));


                vox.BuildDistanceField();

                vox.BuildRegions();

                VoxelContourSet cset = new VoxelContourSet();

                vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES);

                VoxelMesh mesh;

                vox.BuildPolyMesh(cset, 3, out mesh);


                Vector3[] vertices = new Vector3[mesh.verts.Length];

                AstarProfiler.StartProfile("Build Nodes");

                for (int i = 0; i < vertices.Length; i++)
                {
                    vertices[i] = (Vector3)mesh.verts[i];
                }

                matrix = Matrix4x4.TRS(vox.voxelOffset, Quaternion.identity, Int3.Precision * Voxelize.CellScale);
                //Int3.Precision*Voxelize.CellScale+(Int3)vox.voxelOffset

                //GenerateNodes (this,vectorVertices,triangles, out originalVertices, out _vertices);

                NavMeshGraph.GenerateNodes(this, vertices, mesh.tris, out _vectorVertices, out _vertices);

                AstarProfiler.EndProfile("Build Nodes");

                AstarProfiler.PrintResults();
            }
        }