Inheritance: NavGraph, INavmesh, IRaycastableGraph, IFunnelGraph, IUpdatableGraph, INavmeshHolder
Example #1
0
		/** Updates shortcuts to the first graph of different types.
		 * Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
		 * But these references ease the use of the system, so I decided to keep them. It is the only reference to specific graph types in the pathfinding core.\n
		 */
		public void UpdateShortcuts () {
			navmesh = (NavMeshGraph)FindGraphOfType (typeof(NavMeshGraph));

#if !ASTAR_NO_GRID_GRAPH
			gridGraph = (GridGraph)FindGraphOfType (typeof(GridGraph));
#endif

#if !ASTAR_NO_POINT_GRAPH
			pointGraph = (PointGraph)FindGraphOfType (typeof(PointGraph));
#endif

			recastGraph = (RecastGraph)FindGraphOfType (typeof(RecastGraph));
		}
Example #2
0
		/** Updates shortcuts to the first graph of different types.
		 * Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
		 * But these references ease the use of the system, so I decided to keep them. It is the only reference to specific graph types in the pathfinding core.\n
		 */
		public void UpdateShortcuts () {
			navmesh = (NavMeshGraph)FindGraphOfType (typeof(NavMeshGraph));
			gridGraph = (GridGraph)FindGraphOfType (typeof(GridGraph));
			pointGraph = (PointGraph)FindGraphOfType (typeof(PointGraph));
			recastGraph = (RecastGraph)FindGraphOfType (typeof(RecastGraph));
		}
		/** Creates an outline of the navmesh for use in OnDrawGizmos in the editor */
		static Mesh CreateNavmeshOutlineVisualization (RecastGraph.NavmeshTile tile) {
			var sharedEdges = new bool[3];

			var mesh = new Mesh();

			mesh.hideFlags = HideFlags.DontSave;

			var colorList = ListPool<Color32>.Claim();
			var edgeList = ListPool<Int3>.Claim();

			for (int j = 0; j < tile.nodes.Length; j++) {
				sharedEdges[0] = sharedEdges[1] = sharedEdges[2] = false;

				var node = tile.nodes[j];
				for (int c = 0; c < node.connections.Length; c++) {
					var other = node.connections[c] as TriangleMeshNode;

					// Loop throgh neighbours to figure
					// out which edges are shared
					if (other != null && other.GraphIndex == node.GraphIndex) {
						for (int v = 0; v < 3; v++) {
							for (int v2 = 0; v2 < 3; v2++) {
								if (node.GetVertexIndex(v) == other.GetVertexIndex((v2+1)%3) && node.GetVertexIndex((v+1)%3) == other.GetVertexIndex(v2)) {
									// Found a shared edge with the other node
									sharedEdges[v] = true;
									v = 3;
									break;
								}
							}
						}
					}
				}

				for (int v = 0; v < 3; v++) {
					if (!sharedEdges[v]) {
						edgeList.Add(node.GetVertex(v));
						edgeList.Add(node.GetVertex((v+1)%3));
						var color = (Color32)AstarColor.GetAreaColor(node.Area);
						colorList.Add(color);
						colorList.Add(color);
					}
				}
			}

			// Use pooled lists to avoid excessive allocations
			var vertices = ListPool<Vector3>.Claim(edgeList.Count*2);
			var colors = ListPool<Color32>.Claim(edgeList.Count*2);
			var normals = ListPool<Vector3>.Claim(edgeList.Count*2);
			var tris = ListPool<int>.Claim(edgeList.Count*3);

			// Loop through each endpoint of the lines
			// and add 2 vertices for each
			for (int j = 0; j < edgeList.Count; j++) {
				var vertex = (Vector3)edgeList[j];
				vertices.Add(vertex);
				vertices.Add(vertex);

				// Encode the side of the line
				// in the alpha component
				var color = colorList[j];
				colors.Add(new Color32(color.r, color.g, color.b, 0));
				colors.Add(new Color32(color.r, color.g, color.b, 255));
			}

			// Loop through each line and add
			// one normal for each vertex
			for (int j = 0; j < edgeList.Count; j += 2) {
				var lineDir = (Vector3)(edgeList[j+1] - edgeList[j]);
				lineDir.Normalize();

				// Store the line direction in the normals
				// A line consists of 4 vertices
				// The line direction will be used to
				// offset the vertices to create a
				// line with a fixed pixel thickness
				normals.Add(lineDir);
				normals.Add(lineDir);
				normals.Add(lineDir);
				normals.Add(lineDir);
			}

			// Setup triangle indices
			// A triangle consists of 3 indices
			// A line (4 vertices) consists of 2 triangles, so 6 triangle indices
			for (int j = 0, v = 0; j < edgeList.Count*3; j += 6, v += 4) {
				// First triangle
				tris.Add(v+0);
				tris.Add(v+1);
				tris.Add(v+2);

				// Second triangle
				tris.Add(v+1);
				tris.Add(v+3);
				tris.Add(v+2);
			}

			// Set all data on the mesh
			mesh.SetVertices(vertices);
			mesh.SetTriangles(tris, 0);
			mesh.SetColors(colors);
			mesh.SetNormals(normals);

			// Upload all data and mark the mesh as unreadable
			mesh.UploadMeshData(true);

			// Release the lists back to the pool
			ListPool<Color32>.Release(colorList);
			ListPool<Int3>.Release(edgeList);

			ListPool<Vector3>.Release(vertices);
			ListPool<Color32>.Release(colors);
			ListPool<Vector3>.Release(normals);
			ListPool<int>.Release(tris);

			return mesh;
		}
		/** Exports the INavmesh graph to a .obj file */
		public static void ExportToFile (RecastGraph target) {
			//INavmesh graph = (INavmesh)target;
			if (target == null) return;

			RecastGraph.NavmeshTile[] tiles = target.GetTiles();

			if (tiles == null) {
				if (EditorUtility.DisplayDialog("Scan graph before exporting?", "The graph does not contain any mesh data. Do you want to scan it?", "Ok", "Cancel")) {
					AstarPathEditor.MenuScan();
					tiles = target.GetTiles();
					if (tiles == null) return;
				} else {
					return;
				}
			}

			string path = EditorUtility.SaveFilePanel("Export .obj", "", "navmesh.obj", "obj");
			if (path == "") return;

			//Generate .obj
			var sb = new System.Text.StringBuilder();

			string name = System.IO.Path.GetFileNameWithoutExtension(path);

			sb.Append("g ").Append(name).AppendLine();

			//Vertices start from 1
			int vCount = 1;

			//Define single texture coordinate to zero
			sb.Append("vt 0 0\n");

			for (int t = 0; t < tiles.Length; t++) {
				RecastGraph.NavmeshTile tile = tiles[t];

				if (tile == null) continue;

				Int3[] vertices = tile.verts;

				//Write vertices
				for (int i = 0; i < vertices.Length; i++) {
					var v = (Vector3)vertices[i];
					sb.Append(string.Format("v {0} {1} {2}\n", -v.x, v.y, v.z));
				}

				//Write triangles
				TriangleMeshNode[] nodes = tile.nodes;
				for (int i = 0; i < nodes.Length; i++) {
					TriangleMeshNode node = nodes[i];
					if (node == null) {
						Debug.LogError("Node was null or no TriangleMeshNode. Critical error. Graph type " + target.GetType().Name);
						return;
					}
					if (node.GetVertexArrayIndex(0) < 0 || node.GetVertexArrayIndex(0) >= vertices.Length) throw new System.Exception("ERR");

					sb.Append(string.Format("f {0}/1 {1}/1 {2}/1\n", (node.GetVertexArrayIndex(0) + vCount), (node.GetVertexArrayIndex(1) + vCount), (node.GetVertexArrayIndex(2) + vCount)));
				}

				vCount += vertices.Length;
			}

			string obj = sb.ToString();

			using (var sw = new System.IO.StreamWriter(path))
			{
				sw.Write(obj);
			}
		}
		/** Creates a mesh of the surfaces of the navmesh for use in OnDrawGizmos in the editor */
		Mesh CreateNavmeshSurfaceVisualization (RecastGraph.NavmeshTile tile) {
			var mesh = new Mesh();

			mesh.hideFlags = HideFlags.DontSave;

			var vertices = ListPool<Vector3>.Claim(tile.verts.Length);
			var colors = ListPool<Color32>.Claim(tile.verts.Length);

			for (int j = 0; j < tile.verts.Length; j++) {
				vertices.Add((Vector3)tile.verts[j]);
				colors.Add(new Color32());
			}

			// TODO: Uses AstarPath.active
			var debugPathData = AstarPath.active.debugPathData;

			for (int j = 0; j < tile.nodes.Length; j++) {
				var node = tile.nodes[j];
				for (int v = 0; v < 3; v++) {
					var color = target.NodeColor(node, debugPathData);
					colors[node.GetVertexArrayIndex(v)] = (Color32)color;//(Color32)AstarColor.GetAreaColor(node.Area);
				}
			}

			mesh.SetVertices(vertices);
			mesh.SetTriangles(tile.tris, 0);
			mesh.SetColors(colors);

			// Upload all data and mark the mesh as unreadable
			mesh.UploadMeshData(true);

			// Return lists to the pool
			ListPool<Vector3>.Release(vertices);
			ListPool<Color32>.Release(colors);

			return mesh;
		}
Example #6
0
 public void RemoveConnectionsFromTo(RecastGraph.NavmeshTile a, RecastGraph.NavmeshTile b)
 {
     if (a == null || b == null)
     {
         return;
     }
     if (a == b)
     {
         return;
     }
     int num = b.x + b.z * this.tileXCount;
     for (int i = 0; i < a.nodes.Length; i++)
     {
         TriangleMeshNode triangleMeshNode = a.nodes[i];
         if (triangleMeshNode.connections != null)
         {
             for (int j = 0; j < triangleMeshNode.connections.Length; j++)
             {
                 TriangleMeshNode triangleMeshNode2 = triangleMeshNode.connections[j] as TriangleMeshNode;
                 if (triangleMeshNode2 != null)
                 {
                     int num2 = triangleMeshNode2.GetVertexIndex(0);
                     num2 = (num2 >> 12 & 524287);
                     if (num2 == num)
                     {
                         triangleMeshNode.RemoveConnection(triangleMeshNode.connections[j]);
                         j--;
                     }
                 }
             }
         }
     }
 }
Example #7
0
 public void RemoveConnectionsFromTile(RecastGraph.NavmeshTile tile)
 {
     if (tile.x > 0)
     {
         int num = tile.x - 1;
         for (int i = tile.z; i < tile.z + tile.d; i++)
         {
             this.RemoveConnectionsFromTo(this.tiles[num + i * this.tileXCount], tile);
         }
     }
     if (tile.x + tile.w < this.tileXCount)
     {
         int num2 = tile.x + tile.w;
         for (int j = tile.z; j < tile.z + tile.d; j++)
         {
             this.RemoveConnectionsFromTo(this.tiles[num2 + j * this.tileXCount], tile);
         }
     }
     if (tile.z > 0)
     {
         int num3 = tile.z - 1;
         for (int k = tile.x; k < tile.x + tile.w; k++)
         {
             this.RemoveConnectionsFromTo(this.tiles[k + num3 * this.tileXCount], tile);
         }
     }
     if (tile.z + tile.d < this.tileZCount)
     {
         int num4 = tile.z + tile.d;
         for (int l = tile.x; l < tile.x + tile.w; l++)
         {
             this.RemoveConnectionsFromTo(this.tiles[l + num4 * this.tileXCount], tile);
         }
     }
 }
Example #8
0
 public void ConnectTileWithNeighbours(RecastGraph.NavmeshTile tile)
 {
     if (tile.x > 0)
     {
         int num = tile.x - 1;
         for (int i = tile.z; i < tile.z + tile.d; i++)
         {
             this.ConnectTiles(this.tiles[num + i * this.tileXCount], tile);
         }
     }
     if (tile.x + tile.w < this.tileXCount)
     {
         int num2 = tile.x + tile.w;
         for (int j = tile.z; j < tile.z + tile.d; j++)
         {
             this.ConnectTiles(this.tiles[num2 + j * this.tileXCount], tile);
         }
     }
     if (tile.z > 0)
     {
         int num3 = tile.z - 1;
         for (int k = tile.x; k < tile.x + tile.w; k++)
         {
             this.ConnectTiles(this.tiles[k + num3 * this.tileXCount], tile);
         }
     }
     if (tile.z + tile.d < this.tileZCount)
     {
         int num4 = tile.z + tile.d;
         for (int l = tile.x; l < tile.x + tile.w; l++)
         {
             this.ConnectTiles(this.tiles[l + num4 * this.tileXCount], tile);
         }
     }
 }
Example #9
0
 private void ConnectTiles(RecastGraph.NavmeshTile tile1, RecastGraph.NavmeshTile tile2)
 {
     if (tile1 == null)
     {
         return;
     }
     if (tile2 == null)
     {
         return;
     }
     if (tile1.nodes == null)
     {
         throw new ArgumentException("tile1 does not contain any nodes");
     }
     if (tile2.nodes == null)
     {
         throw new ArgumentException("tile2 does not contain any nodes");
     }
     int num = Mathf.Clamp(tile2.x, tile1.x, tile1.x + tile1.w - 1);
     int num2 = Mathf.Clamp(tile1.x, tile2.x, tile2.x + tile2.w - 1);
     int num3 = Mathf.Clamp(tile2.z, tile1.z, tile1.z + tile1.d - 1);
     int num4 = Mathf.Clamp(tile1.z, tile2.z, tile2.z + tile2.d - 1);
     int num5;
     int i;
     int num6;
     int num7;
     float num8;
     if (num == num2)
     {
         num5 = 2;
         i = 0;
         num6 = num3;
         num7 = num4;
         num8 = (float)this.tileSizeZ * this.cellSize;
     }
     else
     {
         if (num3 != num4)
         {
             throw new ArgumentException("Tiles are not adjacent (neither x or z coordinates match)");
         }
         num5 = 0;
         i = 2;
         num6 = num;
         num7 = num2;
         num8 = (float)this.tileSizeX * this.cellSize;
     }
     if (Math.Abs(num6 - num7) != 1)
     {
         UnityEngine.Debug.Log(string.Concat(new object[]
         {
             tile1.x,
             " ",
             tile1.z,
             " ",
             tile1.w,
             " ",
             tile1.d,
             "\n",
             tile2.x,
             " ",
             tile2.z,
             " ",
             tile2.w,
             " ",
             tile2.d,
             "\n",
             num,
             " ",
             num3,
             " ",
             num2,
             " ",
             num4
         }));
         throw new ArgumentException(string.Concat(new object[]
         {
             "Tiles are not adjacent (tile coordinates must differ by exactly 1. Got '",
             num6,
             "' and '",
             num7,
             "')"
         }));
     }
     int num9 = (int)Math.Round((double)(((float)Math.Max(num6, num7) * num8 + this.forcedBounds.min[num5]) * 1000f));
     TriangleMeshNode[] nodes = tile1.nodes;
     TriangleMeshNode[] nodes2 = tile2.nodes;
     for (int j = 0; j < nodes.Length; j++)
     {
         TriangleMeshNode triangleMeshNode = nodes[j];
         int vertexCount = triangleMeshNode.GetVertexCount();
         for (int k = 0; k < vertexCount; k++)
         {
             Int3 vertex = triangleMeshNode.GetVertex(k);
             Int3 vertex2 = triangleMeshNode.GetVertex((k + 1) % vertexCount);
             if (Math.Abs(vertex[num5] - num9) < 2 && Math.Abs(vertex2[num5] - num9) < 2)
             {
                 int num10 = Math.Min(vertex[i], vertex2[i]);
                 int num11 = Math.Max(vertex[i], vertex2[i]);
                 if (num10 != num11)
                 {
                     for (int l = 0; l < nodes2.Length; l++)
                     {
                         TriangleMeshNode triangleMeshNode2 = nodes2[l];
                         int vertexCount2 = triangleMeshNode2.GetVertexCount();
                         for (int m = 0; m < vertexCount2; m++)
                         {
                             Int3 vertex3 = triangleMeshNode2.GetVertex(m);
                             Int3 vertex4 = triangleMeshNode2.GetVertex((m + 1) % vertexCount);
                             if (Math.Abs(vertex3[num5] - num9) < 2 && Math.Abs(vertex4[num5] - num9) < 2)
                             {
                                 int num12 = Math.Min(vertex3[i], vertex4[i]);
                                 int num13 = Math.Max(vertex3[i], vertex4[i]);
                                 if (num12 != num13)
                                 {
                                     if (num11 > num12 && num10 < num13 && ((vertex == vertex3 && vertex2 == vertex4) || (vertex == vertex4 && vertex2 == vertex3) || Polygon.DistanceSegmentSegment3D((Vector3)vertex, (Vector3)vertex2, (Vector3)vertex3, (Vector3)vertex4) < this.walkableClimb * this.walkableClimb))
                                     {
                                         uint costMagnitude = (uint)(triangleMeshNode.position - triangleMeshNode2.position).costMagnitude;
                                         triangleMeshNode.AddConnection(triangleMeshNode2, costMagnitude);
                                         triangleMeshNode2.AddConnection(triangleMeshNode, costMagnitude);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
 }