public static ConnectionInfo FindConnection(TileRegion regionA, TileRegion regionB) { Assert.IsNotNull(regionA); Assert.IsNotNull(regionB); Assert.AreNotEqual(regionA, regionB); var bestConnection = new TempConnection(Coord.zero, Coord.zero, float.MaxValue); int indexA = 0; while (indexA < regionA.Count) { int indexB = 0; var bestThisLoop = new TempConnection(regionA[indexA], Coord.zero, float.MaxValue); while (indexB < regionB.Count) { Coord tileB = regionB[indexB]; float distance = bestThisLoop.tileA.Distance(tileB); if (distance < bestThisLoop.distance) { bestThisLoop = new TempConnection(bestThisLoop.tileA, tileB, distance); } indexB += (int)distance; // distance is never < 1, as minimum occurs with diagonally adjacent tiles } if (bestThisLoop.distance < bestConnection.distance) { bestConnection = bestThisLoop; } indexA += (int)bestThisLoop.distance; } return(new ConnectionInfo(bestConnection.tileA, bestConnection.tileB, regionA.Index, regionB.Index, bestConnection.distance)); }
/* The following method has some subtleties to it that need to be explained. The purpose of it is to trace out the * floor tiles in the room that are adjacent to a wall tile. The tricky part is ensuring that this is done * in an orderly fashion, i.e. that it traces out a more or less continuous path (some error is fine, but a random * ordering is not, as the ordering of the edge tiles is needed for an enormous optimization in the connectivity * algorithm used elsewhere). * * The basic idea is to start on an edge tile, and then perform a depth-first search along edge tiles. The difficulty * comes from two situations. First, consider this example: * * x x o * x x o * 1 2 o * o o o * * x represents wall, o represents floor, numbers represent the path travelled (and the order). If we only * look at horizontal neighbors, the search will terminate at 2, because no adjacent floor is adjacent to a wall. * So we need to look at diagonal neighbors. That leads to the following problem: * * x x x x * x x o x * x 3 x x * 1 2 x x * * The remaining o is not connected to the path so far, but it's diagonally adjacent to the 3. This is handled * by explicitly checking for this situation: in order to take a diagonal jump, one of the * two adjacent tiles must be a floor. i.e. one of these situations: * * x x x x x x x x x x x x * x x o x x o o x x o o x * x 3 o x x 3 x x x 3 o x * 1 2 x x 1 2 x x 1 2 x x * * The final complexity is the possibility of the path jumping, leading to irregularities in the edges. * Example: * * x x o o o 8 x * x x 4 5 6 7 x * 1 2 3 x x o x * o o o x x o x * * Ultimately this level of error is accepted as is. */ /// <summary> /// Extract the edge tiles from this region. /// </summary> /// <param name="region">Must not be empty.</param> public TileRegion Extract(TileRegion region) { Assert.AreNotEqual(region.Count, 0, "Room is empty!"); var boundary = new Boundary(map.Length, map.Width); var edgeTiles = new List <Coord>(region.Count); var stack = new Stack <Coord>(); Coord firstTile = GetStartingEdgeTile(map, region); stack.Push(firstTile); edgeTiles.Add(firstTile); visited[firstTile.x, firstTile.y] = true; while (stack.Count > 0) { Coord tile = stack.Pop(); foreach (Coord adj in GetAdjacentCoords(tile, pooledAdjacentTiles)) { if (boundary.IsInBounds(adj) && !visited[adj.x, adj.y] && FoundEdgeTile(tile, adj, map)) { visited[adj.x, adj.y] = true; stack.Push(adj); edgeTiles.Add(adj); } } } return(new TileRegion(edgeTiles, region.Index)); }
static TileRegion[] ExtractEdges(Map map, List <TileRegion> regions) { var extractor = new EdgeExtractor(map); var rooms = new TileRegion[regions.Count]; for (int i = 0; i < rooms.Length; i++) { rooms[i] = extractor.Extract(regions[i]); } return(rooms); }
static Coord GetStartingEdgeTile(Map map, TileRegion region) { // Note that in practice, this should return the very first item in alltiles. return(region.First(tile => map.IsAdjacentToWall(tile.x, tile.y))); }