Esempio n. 1
0
        /*public override bool ContainsConnection (Node node, Path p) {
         *      if (!node.IsWalkable (p)) {
         *              return false;
         *      }
         *
         *      if (connections != null) {
         *              for (int i=0;i<connections.Length;i++) {
         *                      if (connections[i] == node) {
         *                              return true;
         *                      }
         *              }
         *      }
         *
         *      int index = indices & 0xFFFFFF;
         *
         *      int[] neighbourOffsets = gridGraphs[indices >> 24].neighbourOffsets;
         *      GridNode[] nodes = gridGraphs[indices >> 24].nodes;
         *
         *      for (int i=0;i<8;i++) {
         *              if (((flags >> i) & 1) == 1) {
         *
         *                      Node other = nodes[index+neighbourOffsets[i]];
         *                      if (other == node) {
         *                              return true;
         *                      }
         *              }
         *      }
         *      return false;
         * }*/

        /** Updates the grid connections of this node and it's neighbour nodes to reflect walkability of this node */
        public void UpdateGridConnections()
        {
            GridGraph graph = gridGraphs[indices >> 24];

            int index = indices & 0xFFFFFF;

            int x = index % graph.width;
            int z = index / graph.width;

            graph.CalculateConnections(graph.nodes, x, z, this);

            int[] neighbourOffsets  = graph.neighbourOffsets;
            int[] neighbourOffsetsX = graph.neighbourXOffsets;
            int[] neighbourOffsetsZ = graph.neighbourZOffsets;

            for (int i = 0; i < 8; i++)
            {
                //if (((flags >> i) & 1) == 1) {

                int nx = x + neighbourOffsetsX[i];
                int nz = z + neighbourOffsetsZ[i];


                if (nx < 0 || nz < 0 || nx >= graph.width || nz >= graph.depth)
                {
                    continue;
                }

                GridNode node = (GridNode)graph.nodes[index + neighbourOffsets[i]];

                graph.CalculateConnections(graph.nodes, nx, nz, node);
                //}
            }
        }
Esempio n. 2
0
        /*public override bool ContainsConnection (Node node, Path p) {
         *      if (!node.IsWalkable (p)) {
         *              return false;
         *      }
         *
         *      if (connections != null) {
         *              for (int i=0;i<connections.Length;i++) {
         *                      if (connections[i] == node) {
         *                              return true;
         *                      }
         *              }
         *      }
         *
         *      int index = indices & 0xFFFFFF;
         *
         *      int[] neighbourOffsets = gridGraphs[indices >> 24].neighbourOffsets;
         *      GridNode[] nodes = gridGraphs[indices >> 24].nodes;
         *
         *      for (int i=0;i<8;i++) {
         *              if (((flags >> i) & 1) == 1) {
         *
         *                      Node other = nodes[index+neighbourOffsets[i]];
         *                      if (other == node) {
         *                              return true;
         *                      }
         *              }
         *      }
         *      return false;
         * }*/

        /** Updates the grid connections of this node and it's neighbour nodes to reflect walkability of this node */
        public void UpdateGridConnections()
        {
            GridGraph graph = gridGraphs[indices >> 24];

            int index = GetIndex();

            int x = index % graph.width;
            int z = index / graph.width;

            graph.CalculateConnections(graph.nodes, x, z, this);

            int[] neighbourOffsets  = graph.neighbourOffsets;
            int[] neighbourOffsetsX = graph.neighbourXOffsets;
            int[] neighbourOffsetsZ = graph.neighbourZOffsets;

            //Loop through neighbours
            for (int i = 0; i < 8; i++)
            {
                //Find the coordinates for the neighbour
                int nx = x + neighbourOffsetsX[i];
                int nz = z + neighbourOffsetsZ[i];

                //Make sure it is not out of bounds
                if (nx < 0 || nz < 0 || nx >= graph.width || nz >= graph.depth)
                {
                    continue;
                }

                GridNode node = (GridNode)graph.nodes[index + neighbourOffsets[i]];

                //Calculate connections for neighbour
                graph.CalculateConnections(graph.nodes, nx, nz, node);
            }
        }
Esempio n. 3
0
    public void SetWalableInfoAllMap(Func <int, int, bool> isWalkableFunc)
    {
        AstarPath.active.AddWorkItem(new AstarWorkItem(ctx =>
        {
            for (int i = 0; i < _Depth; i++)
            {
                for (int j = 0; j < _Width; j++)
                {
                    var node      = _GridGraph.GetNode(j, i);
                    node.Walkable = isWalkableFunc(j, i);
                }
            }

            _GridGraph.GetNodes(node => _GridGraph.CalculateConnections((GridNodeBase)node));
        }));
    }
Esempio n. 4
0
    // Generates a grid graph for the A* Pathfinding system.
    private void generateGridGraph(int width, int height)
    {
        AstarData data     = AstarPath.active.data;
        GridGraph gg       = data.AddGraph(typeof(GridGraph)) as GridGraph;
        float     nodeSize = 1f;

        gg.center = new Vector3((width / 2) - 0.5f, 0, (height / 2) - 0.5f);
        gg.SetDimensions(width, height, nodeSize);
        gg.neighbours = NumNeighbours.Four;
        AstarPath.active.Scan();
        AstarPath.active.AddWorkItem(new AstarWorkItem(ctx => {
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    var node      = gg.GetNode(x, y);
                    node.Walkable = walkable[x, y];
                }
            }
            gg.GetNodes(node => gg.CalculateConnections((GridNodeBase)node));
        }));
    }
Esempio n. 5
0
        /** Removes a connection from the node.
         * This can be a standard connection or a grid connection
         * \returns True if a connection was removed, false otherwsie */
        public override bool RemoveConnection(Node node)
        {
            bool standard = base.RemoveConnection(node);

            GridGraph graph = gridGraphs[indices >> 24];

            int index = indices & 0xFFFFFF;

            int x = index % graph.width;
            int z = index / graph.width;

            graph.CalculateConnections(graph.nodes, x, z, this);

            int[] neighbourOffsets  = graph.neighbourOffsets;
            int[] neighbourOffsetsX = graph.neighbourXOffsets;
            int[] neighbourOffsetsZ = graph.neighbourZOffsets;

            for (int i = 0; i < 8; i++)
            {
                int nx = x + neighbourOffsetsX[i];
                int nz = z + neighbourOffsetsZ[i];

                if (nx < 0 || nz < 0 || nx >= graph.width || nz >= graph.depth)
                {
                    continue;
                }

                GridNode gNode = (GridNode)graph.nodes[index + neighbourOffsets[i]];
                if (gNode == node)
                {
                    SetConnection(i, 0);
                    return(true);
                }
            }
            return(standard);
        }
Esempio n. 6
0
    IEnumerator UpdateGraphCoroutine()
    {
        // Find the direction
        // that we want to move the graph in
        var dir = target.position - graph.center;

        // Snap to a whole number of nodes
        dir.x = Mathf.Round(dir.x / graph.nodeSize) * graph.nodeSize;
        dir.z = Mathf.Round(dir.z / graph.nodeSize) * graph.nodeSize;
        dir.y = 0;

        // Nothing do to
        if (dir == Vector3.zero)
        {
            yield break;
        }

        // Number of nodes to offset in each
        // direction
        var offset = new Int2(-Mathf.RoundToInt(dir.x / graph.nodeSize), -Mathf.RoundToInt(dir.z / graph.nodeSize));

        // Move the center
        graph.center += dir;
        graph.GenerateMatrix();

        // Create a temporary buffer
        // required for the calculations
        if (tmp == null || tmp.Length != graph.nodes.Length)
        {
            tmp = new GridNode[graph.nodes.Length];
        }

        // Cache some variables for easier access
        var width = graph.width;
        var depth = graph.depth;
        var nodes = graph.nodes;

        // Check if we have moved
        // less than a whole graph
        // width in any direction
        if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth)
        {
            // Offset each node by the #offset variable
            // nodes which would end up outside the graph
            // will wrap around to the other side of it
            for (var z = 0; z < depth; z++)
            {
                var pz = z * width;
                var tz = ((z + offset.y + depth) % depth) * width;
                for (var x = 0; x < width; x++)
                {
                    tmp[tz + ((x + offset.x + width) % width)] = nodes[pz + x];
                }
            }

            yield return(null);

            // Copy the nodes back to the graph
            // and set the correct indices
            for (var z = 0; z < depth; z++)
            {
                var pz = z * width;
                for (var x = 0; x < width; x++)
                {
                    var node = tmp[pz + x];
                    node.NodeInGridIndex = pz + x;
                    nodes[pz + x]        = node;
                }
            }


            var r    = new IntRect(0, 0, offset.x, offset.y);
            var minz = r.ymax;
            var maxz = depth;

            // If offset.x < 0, adjust the rect
            if (r.xmin > r.xmax)
            {
                var tmp2 = r.xmax;
                r.xmax = width + r.xmin;
                r.xmin = width + tmp2;
            }

            // If offset.y < 0, adjust the rect
            if (r.ymin > r.ymax)
            {
                var tmp2 = r.ymax;
                r.ymax = depth + r.ymin;
                r.ymin = depth + tmp2;

                minz = 0;
                maxz = r.ymin;
            }

            // Make sure erosion is taken into account
            // Otherwise we would end up with ugly artifacts
            r = r.Expand(graph.erodeIterations + 1);

            // Makes sure the rect stays inside the grid
            r = IntRect.Intersection(r, new IntRect(0, 0, width, depth));

            yield return(null);

            // Update all nodes along one edge of the graph
            // With the same width as the rect
            for (var z = r.ymin; z < r.ymax; z++)
            {
                for (var x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            // Update all nodes along the other edge of the graph
            // With the same width as the rect
            for (var z = minz; z < maxz; z++)
            {
                for (var x = r.xmin; x < r.xmax; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes
            // that might have changed
            for (var z = r.ymin; z < r.ymax; z++)
            {
                for (var x = 0; x < width; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes
            // that might have changed
            for (var z = minz; z < maxz; z++)
            {
                for (var x = r.xmin; x < r.xmax; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes along the boundary
            // of the graph, these always need to be updated
            /** \todo Optimize to not traverse all nodes in the graph, only those at the edges */
            for (var z = 0; z < depth; z++)
            {
                for (var x = 0; x < width; x++)
                {
                    if (x == 0 || z == 0 || x >= width - 1 || z >= depth - 1)
                    {
                        graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                    }
                }
            }
        }
        else
        {
            // Just update all nodes
            for (var z = 0; z < depth; z++)
            {
                for (var x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            // Recalculate the connections of all nodes
            for (var z = 0; z < depth; z++)
            {
                for (var x = 0; x < width; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }
        }

        if (floodFill)
        {
            yield return(null);

            // Make sure the areas for the graph
            // have been recalculated
            // not doing this can cause pathfinding to fail
            AstarPath.active.QueueWorkItemFloodFill();
        }
    }
    /** Async method for moving the graph */
    IEnumerator UpdateGraphCoroutine()
    {
        // Find the direction that we want to move the graph in.
        // Calcuculate this in graph space (where a distance of one is the size of one node)
        Vector3 dir = PointToGraphSpace(target.position) - PointToGraphSpace(graph.center);

        // Snap to a whole number of nodes
        dir.x = Mathf.Round(dir.x);
        dir.z = Mathf.Round(dir.z);
        dir.y = 0;

        // Nothing do to
        if (dir == Vector3.zero)
        {
            yield break;
        }

        // Number of nodes to offset in each direction
        Int2 offset = new Int2(-Mathf.RoundToInt(dir.x), -Mathf.RoundToInt(dir.z));

        // Move the center (this is in world units, so we need to convert it back from graph space)
        graph.center += graph.transform.TransformVector(dir);
        graph.UpdateTransform();

        // Cache some variables for easier access
        int width = graph.width;
        int depth = graph.depth;

        GridNodeBase[] nodes;
        // Layers are required when handling LayeredGridGraphs
        int layers = 1;

        nodes = graph.nodes;

        // Create a temporary buffer required for the calculations
        if (buffer == null || buffer.Length != width * depth)
        {
            buffer = new GridNodeBase[width * depth];
        }

        // Check if we have moved less than a whole graph width all directions
        // If we have moved more than this we can just as well recalculate the whole graph
        if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth)
        {
            IntRect recalculateRect = new IntRect(0, 0, offset.x, offset.y);

            // If offset.x < 0, adjust the rect
            if (recalculateRect.xmin > recalculateRect.xmax)
            {
                int tmp2 = recalculateRect.xmax;
                recalculateRect.xmax = width + recalculateRect.xmin;
                recalculateRect.xmin = width + tmp2;
            }

            // If offset.y < 0, adjust the rect
            if (recalculateRect.ymin > recalculateRect.ymax)
            {
                int tmp2 = recalculateRect.ymax;
                recalculateRect.ymax = depth + recalculateRect.ymin;
                recalculateRect.ymin = depth + tmp2;
            }

            // Connections need to be recalculated for the neighbours as well, so we need to expand the rect by 1
            var connectionRect = recalculateRect.Expand(1);

            // Makes sure the rect stays inside the grid
            connectionRect = IntRect.Intersection(connectionRect, new IntRect(0, 0, width, depth));

            // Offset each node by the #offset variable
            // nodes which would end up outside the graph
            // will wrap around to the other side of it
            for (int l = 0; l < layers; l++)
            {
                int layerOffset = l * width * depth;
                for (int z = 0; z < depth; z++)
                {
                    int pz = z * width;
                    int tz = ((z + offset.y + depth) % depth) * width;
                    for (int x = 0; x < width; x++)
                    {
                        buffer[tz + ((x + offset.x + width) % width)] = nodes[layerOffset + pz + x];
                    }
                }

                yield return(null);

                // Copy the nodes back to the graph
                // and set the correct indices
                for (int z = 0; z < depth; z++)
                {
                    int pz = z * width;
                    for (int x = 0; x < width; x++)
                    {
                        int newIndex = pz + x;
                        var node     = buffer[newIndex];
                        if (node != null)
                        {
                            node.NodeInGridIndex = newIndex;
                        }
                        nodes[layerOffset + newIndex] = node;
                    }

                    // Calculate the limits for the region that has been wrapped
                    // to the other side of the graph
                    int xmin, xmax;
                    if (z >= recalculateRect.ymin && z < recalculateRect.ymax)
                    {
                        xmin = 0;
                        xmax = depth;
                    }
                    else
                    {
                        xmin = recalculateRect.xmin;
                        xmax = recalculateRect.xmax;
                    }

                    for (int x = xmin; x < xmax; x++)
                    {
                        var node = buffer[pz + x];
                        if (node != null)
                        {
                            // Clear connections on all nodes that are wrapped and placed on the other side of the graph.
                            // This is both to clear any custom connections (which do not really make sense after moving the node)
                            // and to prevent possible exceptions when the node will later (possibly) be destroyed because it was
                            // not needed anymore (only for layered grid graphs).
                            node.ClearConnections(false);
                        }
                    }
                }

                yield return(null);
            }

            // The calculation will only update approximately this number of
            // nodes per frame. This is used to keep CPU load per frame low
            int yieldEvery = 1000;
            // To avoid the update taking too long, make yieldEvery somewhat proportional to the number of nodes that we are going to update
            int approxNumNodesToUpdate = Mathf.Max(Mathf.Abs(offset.x), Mathf.Abs(offset.y)) * Mathf.Max(width, depth);
            yieldEvery = Mathf.Max(yieldEvery, approxNumNodesToUpdate / 10);
            int counter = 0;

            // Recalculate the nodes
            // Take a look at the image in the docs for the UpdateGraph method
            // to see which nodes are being recalculated.
            for (int z = 0; z < depth; z++)
            {
                int xmin, xmax;
                if (z >= recalculateRect.ymin && z < recalculateRect.ymax)
                {
                    xmin = 0;
                    xmax = width;
                }
                else
                {
                    xmin = recalculateRect.xmin;
                    xmax = recalculateRect.xmax;
                }

                for (int x = xmin; x < xmax; x++)
                {
                    graph.RecalculateCell(x, z, false, false);
                }

                counter += (xmax - xmin);

                if (counter > yieldEvery)
                {
                    counter = 0;
                    yield return(null);
                }
            }

            for (int z = 0; z < depth; z++)
            {
                int xmin, xmax;
                if (z >= connectionRect.ymin && z < connectionRect.ymax)
                {
                    xmin = 0;
                    xmax = width;
                }
                else
                {
                    xmin = connectionRect.xmin;
                    xmax = connectionRect.xmax;
                }

                for (int x = xmin; x < xmax; x++)
                {
                    graph.CalculateConnections(x, z);
                }

                counter += (xmax - xmin);

                if (counter > yieldEvery)
                {
                    counter = 0;
                    yield return(null);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes along the boundary
            // of the graph, these always need to be updated
            /** \todo Optimize to not traverse all nodes in the graph, only those at the edges */
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x == 0 || z == 0 || x == width - 1 || z == depth - 1)
                    {
                        graph.CalculateConnections(x, z);
                    }
                }
            }

            // We need to clear the Area if we are not using flood filling.
            // This will make pathfinding always work, but it may be slow
            // to figure out that no path exists if none does.
            // (of course, if there are regions between which no valid
            // paths exist, then the #floodFill field should not
            // be set to false anyway).
            if (!floodFill)
            {
                graph.GetNodes(node => node.Area = 1);
            }
        }
        else
        {
            // The calculation will only update approximately this number of
            // nodes per frame. This is used to keep CPU load per frame low
            int yieldEvery = Mathf.Max(depth * width / 20, 1000);
            int counter    = 0;
            // Just update all nodes
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.RecalculateCell(x, z);
                }
                counter += width;
                if (counter > yieldEvery)
                {
                    counter = 0;
                    yield return(null);
                }
            }

            // Recalculate the connections of all nodes
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.CalculateConnections(x, z);
                }
                counter += width;
                if (counter > yieldEvery)
                {
                    counter = 0;
                    yield return(null);
                }
            }
        }
    }
    /** Async method for moving the graph */
    IEnumerator UpdateGraphCoroutine()
    {
        // Find the direction
        // that we want to move the graph in.
        // Calcuculate this in graph space (where a distance of one is the size of one node)
        Vector3 dir = PointToGraphSpace(target.position) - PointToGraphSpace(graph.center);

        // Snap to a whole number of nodes
        dir.x = Mathf.Round(dir.x);
        dir.z = Mathf.Round(dir.z);
        dir.y = 0;

        // Nothing do to
        if (dir == Vector3.zero)
        {
            yield break;
        }

        // Number of nodes to offset in each direction
        Int2 offset = new Int2(-Mathf.RoundToInt(dir.x), -Mathf.RoundToInt(dir.z));

        // Move the center (this is in world units, so we need to convert it back from graph space)
        graph.center += graph.matrix.MultiplyVector(dir);
        graph.GenerateMatrix();

        // Create a temporary buffer
        // required for the calculations
        if (tmp == null || tmp.Length != graph.nodes.Length)
        {
            tmp = new GridNode[graph.nodes.Length];
        }

        // Cache some variables for easier access
        int width = graph.width;
        int depth = graph.depth;

        GridNode[] nodes = graph.nodes;

        // Check if we have moved
        // less than a whole graph
        // width in any direction
        if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth)
        {
            // Offset each node by the #offset variable
            // nodes which would end up outside the graph
            // will wrap around to the other side of it
            for (int z = 0; z < depth; z++)
            {
                int pz = z * width;
                int tz = ((z + offset.y + depth) % depth) * width;
                for (int x = 0; x < width; x++)
                {
                    tmp[tz + ((x + offset.x + width) % width)] = nodes[pz + x];
                }
            }

            yield return(null);

            // Copy the nodes back to the graph
            // and set the correct indices
            for (int z = 0; z < depth; z++)
            {
                int pz = z * width;
                for (int x = 0; x < width; x++)
                {
                    GridNode node = tmp[pz + x];
                    node.NodeInGridIndex = pz + x;
                    nodes[pz + x]        = node;
                }
            }


            IntRect r    = new IntRect(0, 0, offset.x, offset.y);
            int     minz = r.ymax;
            int     maxz = depth;

            // If offset.x < 0, adjust the rect
            if (r.xmin > r.xmax)
            {
                int tmp2 = r.xmax;
                r.xmax = width + r.xmin;
                r.xmin = width + tmp2;
            }

            // If offset.y < 0, adjust the rect
            if (r.ymin > r.ymax)
            {
                int tmp2 = r.ymax;
                r.ymax = depth + r.ymin;
                r.ymin = depth + tmp2;

                minz = 0;
                maxz = r.ymin;
            }

            // Make sure erosion is taken into account
            // Otherwise we would end up with ugly artifacts
            r = r.Expand(graph.erodeIterations + 1);

            // Makes sure the rect stays inside the grid
            r = IntRect.Intersection(r, new IntRect(0, 0, width, depth));

            yield return(null);

            // Update all nodes along one edge of the graph
            // With the same width as the rect
            for (int z = r.ymin; z < r.ymax; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            // Update all nodes along the other edge of the graph
            // With the same width as the rect
            for (int z = minz; z < maxz; z++)
            {
                for (int x = r.xmin; x < r.xmax; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes
            // that might have changed
            for (int z = r.ymin; z < r.ymax; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.CalculateConnections(x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes
            // that might have changed
            for (int z = minz; z < maxz; z++)
            {
                for (int x = r.xmin; x < r.xmax; x++)
                {
                    graph.CalculateConnections(x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            // Calculate all connections for the nodes along the boundary
            // of the graph, these always need to be updated
            /** \todo Optimize to not traverse all nodes in the graph, only those at the edges */
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x == 0 || z == 0 || x >= width - 1 || z >= depth - 1)
                    {
                        graph.CalculateConnections(x, z, nodes[z * width + x]);
                    }
                }
            }
        }
        else
        {
            // Just update all nodes
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            // Recalculate the connections of all nodes
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }
        }

        yield return(null);
    }
Esempio n. 9
0
    public IEnumerator UpdateGraph()
    {
        Vector3 dir = target.position - graph.center;

        // Snap to a whole number of nodes
        dir.x = Mathf.Round(dir.x / graph.nodeSize) * graph.nodeSize;
        dir.z = Mathf.Round(dir.z / graph.nodeSize) * graph.nodeSize;
        dir.y = 0;

        if (dir == Vector3.zero)
        {
            yield break;
        }

        Int2 offset = new Int2(-Mathf.RoundToInt(dir.x / graph.nodeSize), -Mathf.RoundToInt(dir.z / graph.nodeSize));

        // Move the center
        graph.center += dir;
        graph.GenerateMatrix();

        if (tmp == null || tmp.Length != graph.nodes.Length)
        {
            tmp = new GridNode[graph.nodes.Length];
        }

        int width = graph.width;
        int depth = graph.depth;

        GridNode[] nodes = graph.nodes;

        if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth)
        {
            for (int z = 0; z < depth; z++)
            {
                int pz = z * width;
                int tz = ((z + offset.y + depth) % depth) * width;
                for (int x = 0; x < width; x++)
                {
                    tmp[tz + ((x + offset.x + width) % width)] = nodes[pz + x];
                }
            }

            yield return(null);

            for (int z = 0; z < depth; z++)
            {
                int pz = z * width;
                for (int x = 0; x < width; x++)
                {
                    GridNode node = tmp[pz + x];
                    node.NodeInGridIndex = pz + x;
                    nodes[pz + x]        = node;
                }
            }

            IntRect r    = new IntRect(0, 0, offset.x, offset.y);
            int     minz = r.ymax;
            int     maxz = depth;

            if (r.xmin > r.xmax)
            {
                int tmp2 = r.xmax;
                r.xmax = width + r.xmin;
                r.xmin = width + tmp2;
            }
            if (r.ymin > r.ymax)
            {
                int tmp2 = r.ymax;
                r.ymax = depth + r.ymin;
                r.ymin = depth + tmp2;

                minz = 0;
                maxz = r.ymin;
            }

            //Debug.Log ( "R1 " + r );
            r = r.Expand(graph.erodeIterations + 1);
            r = IntRect.Intersection(r, new IntRect(0, 0, width, depth));

            //Debug.Log ( "R2 " + r );

            yield return(null);

            for (int z = r.ymin; z < r.ymax; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            for (int z = minz; z < maxz; z++)
            {
                for (int x = r.xmin; x < r.xmax; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            yield return(null);

            for (int z = r.ymin; z < r.ymax; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            for (int z = minz; z < maxz; z++)
            {
                for (int x = r.xmin; x < r.xmax; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }

            yield return(null);

            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x == 0 || z == 0 || x >= width - 1 || z >= depth - 1)
                    {
                        graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                    }
                }
            }
        }
        else
        {
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.UpdateNodePositionCollision(nodes[z * width + x], x, z, false);
                }
            }

            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    graph.CalculateConnections(nodes, x, z, nodes[z * width + x]);
                }
            }
        }

        if (floodFill)
        {
            yield return(null);

            AstarPath.active.QueueWorkItemFloodFill();
        }
    }