public void CalculateAllZonesMinMax(out Vector3 outMin, out Vector3 outMax) { Transform zonesRoot = GetZonesRoot(); // set min to highest possible x,z initially and max to lowest possible x,z initially (y isn't set) outMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); outMax = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue); Vector3 tempMin = new Vector3(); Vector3 tempMax = new Vector3(); // walk zones to generate the bounding box encompassing the entire level (all zones) foreach (Transform zone in zonesRoot.transform) { ZoneDescriptor.CalculateZoneMinAndMax(ref tempMin, ref tempMax, zone); outMin.x = tempMin.x < outMin.x ? tempMin.x : outMin.x; outMax.x = tempMax.x > outMax.x ? tempMax.x : outMax.x; outMin.y = tempMin.y < outMin.y ? tempMin.y : outMin.y; outMax.y = tempMax.y > outMax.y ? tempMax.y : outMax.y; outMin.z = tempMin.z < outMin.z ? tempMin.z : outMin.z; outMax.z = tempMax.z > outMax.z ? tempMax.z : outMax.z; } }
// generate a nav mesh with one tile per zone protected void GenerateTilesForZones(AStarPathfindingWalkableArea[] walkAreas) { if (null == walkAreas || 0 == walkAreas.Length) { EB.Debug.LogWarning("GenerateTilesForZones: walkAreas is empty"); return; } LevelHelper levelHelper = GameObject.FindObjectOfType(typeof(LevelHelper)) as LevelHelper; if (null == levelHelper) { EB.Debug.LogWarning("GenerateTilesForZones: LevelHelper not found"); return; } Vector3 NavMeshBoundingBoxMin; Vector3 NavMeshBoundingBoxMax; levelHelper.CalculateAllZonesMinMax(out NavMeshBoundingBoxMin, out NavMeshBoundingBoxMax); // set the entire bounds and center of the recast graph forcedBoundsSize = NavMeshBoundingBoxMax - NavMeshBoundingBoxMin; forcedBoundsCenter = NavMeshBoundingBoxMin + (forcedBoundsSize * 0.5f); tileSizeX = tileSizeZ = (int)(EditorVars.GridSize / cellSize); // this line sets the tile size so that each tile will hold the size of a zone CalculateNumberOfTiles(ref tileXCount, ref tileZCount); #if DEBUG int correctTilesXCount = (Mathf.CeilToInt(forcedBoundsSize.x / EditorVars.GridSize)); // this would fail if GridSize is less than 1f int correctTilesZCount = (Mathf.CeilToInt(forcedBoundsSize.z / EditorVars.GridSize)); // this would fail if GridSize is less than 1f if (correctTilesXCount != tileXCount || correctTilesZCount != tileZCount) { EB.Debug.LogError("Incorrect number of tiles generated"); } #endif tiles = new NavmeshTile[tileXCount * tileZCount]; // ignore this setting scanEmptyGraph = false; Vector3 tempZoneMin = new Vector3(); Vector3 tempZoneMax = new Vector3(); // go over all the walkable areas and put there mesh into a tile foreach (AStarPathfindingWalkableArea walk in walkAreas) { ZoneDescriptor zoneDescriptor = (ZoneDescriptor)GameUtils.FindFirstComponentUpwards <ZoneDescriptor>(walk.transform); if (zoneDescriptor != null) { ZoneDescriptor.CalculateZoneMinAndMax(ref tempZoneMin, ref tempZoneMax, zoneDescriptor.gameObject.transform); // 1f is added to avoid floating point inacuracy (avoids 63.999/64 = 0, 64.99/64=1 which is correct) int z = (int)(((tempZoneMin.z + 1f) - NavMeshBoundingBoxMin.z) / EditorVars.GridSize); int x = (int)(((tempZoneMin.x + 1f) - NavMeshBoundingBoxMin.x) / EditorVars.GridSize); MeshFilter meshFilter = walk.gameObject.GetComponent <MeshFilter>(); if (null != meshFilter.sharedMesh) { // the Vector3 vertices in the mesh need to be converted to the APP Int3 format Int3[] Int3Verts = new Int3[meshFilter.sharedMesh.vertices.Length]; for (int i = 0; i < Int3Verts.Length; ++i) { Vector3 tempVert = new Vector3(meshFilter.sharedMesh.vertices[i].x, meshFilter.sharedMesh.vertices[i].y, meshFilter.sharedMesh.vertices[i].z); tempVert = walk.transform.TransformPoint(tempVert); // get the world space position, rather than local space // clamp the verts to the edges of the zone boundaries if they are close, this is so that the different tiles are linked together accurately const float Tol = 0.01f; tempVert.x = (tempVert.x <= tempZoneMin.x + Tol) ? tempZoneMin.x : tempVert.x; tempVert.x = (tempVert.x >= tempZoneMax.x - Tol) ? tempZoneMax.x : tempVert.x; tempVert.z = (tempVert.z <= tempZoneMin.z + Tol) ? tempZoneMin.z : tempVert.z; tempVert.z = (tempVert.z >= tempZoneMax.z - Tol) ? tempZoneMax.z : tempVert.z; Int3Verts[i] = (Int3)tempVert; } NavmeshTile tile = CreateTile(meshFilter.sharedMesh.triangles, Int3Verts, x, z); tiles[Convert2DArrayCoordTo1DArrayCoord(x, z, tileXCount)] = tile; } } } //Assign graph index to nodes uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex(this); GraphNodeDelegateCancelable del = delegate(GraphNode n) { n.GraphIndex = graphIndex; return(true); }; GetNodes(del); // connect each tile to one and other for (int z = 0; z < tileZCount; z++) { for (int x = 0; x < tileXCount; x++) { // make sure all the tiles which might be considered, have tiles created CreateAndAddEmptyTileIfNonExists(x, z); CreateAndAddEmptyTileIfNonExists(x + 1, z); CreateAndAddEmptyTileIfNonExists(x, z + 1); if (x < tileXCount - 1) { ConnectTiles(tiles[Convert2DArrayCoordTo1DArrayCoord(x, z, tileXCount)], tiles[Convert2DArrayCoordTo1DArrayCoord(x + 1, z, tileXCount)]); } if (z < tileZCount - 1) { ConnectTiles(tiles[Convert2DArrayCoordTo1DArrayCoord(x, z, tileXCount)], tiles[Convert2DArrayCoordTo1DArrayCoord(x, z + 1, tileXCount)]); } } } }