/** 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 ();
            }
        }
예제 #2
0
		public void UpdateArea (GraphUpdateObject guo) {

			Bounds b = guo.bounds;
			b.center -= forcedBounds.min;

			//Figure out which tiles are affected
			var r = new IntRect (Mathf.FloorToInt (b.min.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.min.z / (tileSizeZ*cellSize)), Mathf.FloorToInt (b.max.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.max.z / (tileSizeZ*cellSize)));
			//Clamp to bounds
			r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1));

			if (!guo.updatePhysics) {


				for ( int z=r.ymin;z<=r.ymax;z++) {
					for ( int x=r.xmin;x<=r.xmax;x++) {
						NavmeshTile tile = tiles[z*tileXCount + x];
						tile.flag = true;
					}
				}

				for ( int z=r.ymin;z<=r.ymax;z++) {
					for ( int x=r.xmin;x<=r.xmax;x++) {
						NavmeshTile tile = tiles[z*tileXCount + x];
						if ( tile.flag ) {
							tile.flag = false;

							NavMeshGraph.UpdateArea (guo, tile);
						}
					}
				}

				return;
			}

			if (!dynamic) {
				throw new System.Exception ("Recast graph must be marked as dynamic to enable graph updates with updatePhysics = true");
			}

			Voxelize vox = globalVox;

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



			AstarProfiler.StartProfile ("Init");

			/** \bug No bounds checking */

			//r.DebugDraw (Matrix4x4.TRS (forcedBounds.min, Quaternion.identity, new Vector3 (tileSize*cellSize, 1, tileSize*cellSize)), Color.red);

			//Debug.Break ();



			AstarProfiler.StartProfile ("RemoveConnections");



			for (int x=r.xmin;x<=r.xmax;x++) {
				for (int z=r.ymin;z<=r.ymax;z++) {
					RemoveConnectionsFromTile (tiles[x + z*tileXCount]);
				}
			}



			AstarProfiler.EndProfile ("RemoveConnections");

			AstarProfiler.StartProfile ("Build Tiles");

			for (int x=r.xmin;x<=r.xmax;x++) {
				for (int z=r.ymin;z<=r.ymax;z++) {
					BuildTileMesh (vox, x,z);
				}
			}



			AstarProfiler.EndProfile ("Build Tiles");


			AstarProfiler.StartProfile ("ConnectTiles");
			uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex (this);

			for (int x=r.xmin;x<=r.xmax;x++) {
				for (int z=r.ymin;z<=r.ymax;z++) {
					NavmeshTile tile = tiles[x + z*tileXCount];
					GraphNode[] nodes = tile.nodes;

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



			//Connect the newly create tiles with the old tiles and with each other
			r = r.Expand (1);
			//Clamp to bounds
			r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1));

			for (int x=r.xmin;x<=r.xmax;x++) {
				for (int z=r.ymin;z<=r.ymax;z++) {
					if (x < tileXCount-1 && r.Contains (x+1, z)) {
						ConnectTiles (tiles[x + z*tileXCount], tiles[x+1 + z*tileXCount]);
					}
					if (z < tileZCount-1 && r.Contains (x, z+1)) {
						ConnectTiles (tiles[x + z*tileXCount], tiles[x + (z+1)*tileXCount]);
					}
				}
			}

			AstarProfiler.EndProfile ("ConnectTiles");
			AstarProfiler.PrintResults ();
		}