Ejemplo n.º 1
0
    public IEnumerator UpdateGraph()
    {
        Vector3 dir = this.target.position - this.graph.center;

        dir.x = Mathf.Round(dir.x / this.graph.nodeSize) * this.graph.nodeSize;
        dir.z = Mathf.Round(dir.z / this.graph.nodeSize) * this.graph.nodeSize;
        dir.y = 0f;
        if (dir == Vector3.zero)
        {
            yield break;
        }
        Int2 offset = new Int2(-Mathf.RoundToInt(dir.x / this.graph.nodeSize), -Mathf.RoundToInt(dir.z / this.graph.nodeSize));

        this.graph.center += dir;
        this.graph.GenerateMatrix();
        if (this.tmp == null || this.tmp.Length != this.graph.nodes.Length)
        {
            this.tmp = new GridNode[this.graph.nodes.Length];
        }
        int width = this.graph.width;
        int depth = this.graph.depth;

        GridNode[] nodes = this.graph.nodes;
        if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth)
        {
            for (int i = 0; i < depth; i++)
            {
                int num  = i * width;
                int num2 = (i + offset.y + depth) % depth * width;
                for (int j = 0; j < width; j++)
                {
                    this.tmp[num2 + (j + offset.x + width) % width] = nodes[num + j];
                }
            }
            yield return(null);

            for (int k = 0; k < depth; k++)
            {
                int num3 = k * width;
                for (int l = 0; l < width; l++)
                {
                    GridNode gridNode = this.tmp[num3 + l];
                    gridNode.NodeInGridIndex = num3 + l;
                    nodes[num3 + l]          = gridNode;
                }
            }
            IntRect r    = new IntRect(0, 0, offset.x, offset.y);
            int     minz = r.ymax;
            int     maxz = depth;
            if (r.xmin > r.xmax)
            {
                int xmax = r.xmax;
                r.xmax = width + r.xmin;
                r.xmin = width + xmax;
            }
            if (r.ymin > r.ymax)
            {
                int ymax = r.ymax;
                r.ymax = depth + r.ymin;
                r.ymin = depth + ymax;
                minz   = 0;
                maxz   = r.ymin;
            }
            r = r.Expand(this.graph.erodeIterations + 1);
            r = IntRect.Intersection(r, new IntRect(0, 0, width, depth));
            yield return(null);

            for (int m = r.ymin; m < r.ymax; m++)
            {
                for (int n = 0; n < width; n++)
                {
                    this.graph.UpdateNodePositionCollision(nodes[m * width + n], n, m, false);
                }
            }
            yield return(null);

            for (int num4 = minz; num4 < maxz; num4++)
            {
                for (int num5 = r.xmin; num5 < r.xmax; num5++)
                {
                    this.graph.UpdateNodePositionCollision(nodes[num4 * width + num5], num5, num4, false);
                }
            }
            yield return(null);

            for (int num6 = r.ymin; num6 < r.ymax; num6++)
            {
                for (int num7 = 0; num7 < width; num7++)
                {
                    this.graph.CalculateConnections(nodes, num7, num6, nodes[num6 * width + num7]);
                }
            }
            yield return(null);

            for (int num8 = minz; num8 < maxz; num8++)
            {
                for (int num9 = r.xmin; num9 < r.xmax; num9++)
                {
                    this.graph.CalculateConnections(nodes, num9, num8, nodes[num8 * width + num9]);
                }
            }
            yield return(null);

            for (int num10 = 0; num10 < depth; num10++)
            {
                for (int num11 = 0; num11 < width; num11++)
                {
                    if (num11 == 0 || num10 == 0 || num11 >= width - 1 || num10 >= depth - 1)
                    {
                        this.graph.CalculateConnections(nodes, num11, num10, nodes[num10 * width + num11]);
                    }
                }
            }
        }
        else
        {
            for (int num12 = 0; num12 < depth; num12++)
            {
                for (int num13 = 0; num13 < width; num13++)
                {
                    this.graph.UpdateNodePositionCollision(nodes[num12 * width + num13], num13, num12, false);
                }
            }
            for (int num14 = 0; num14 < depth; num14++)
            {
                for (int num15 = 0; num15 < width; num15++)
                {
                    this.graph.CalculateConnections(nodes, num15, num14, nodes[num14 * width + num15]);
                }
            }
        }
        if (this.floodFill)
        {
            yield return(null);

            AstarPath.active.QueueWorkItemFloodFill();
        }
        yield break;
    }
	/** 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 (nodes, 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 (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 ( 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 {

			// 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]);
				}
			}
		}
		
		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 ();
		}
	}
Ejemplo n.º 3
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();
        }
    }
Ejemplo n.º 4
0
    /** 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);
                }
            }
        }
    }
Ejemplo n.º 5
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 ();
		}
	}
    /** 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);
    }
Ejemplo n.º 7
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();
        }
    }