/// <summary> /// Gets all continuous left/right Lines from the given level using all the walls in the given column. /// The Lines are indexed by all wall bounds that make up part of that indexed Line. /// </summary> public static void GetVerticalLines(FillData data, WallToLines associations, int col) { int startingY, currentY; Interval temp; ColType current; bool rightCol = (col == data.Map.GetLength(0) - 1); //Do the algorithm for both the left and the right of the column. int currentCol; for (int dir = -1; dir < 2; dir += 2) { currentCol = col + dir; current = (currentCol > col ? ColType.Right : ColType.Left); //Take care of the edge case where the whole row is a valid line. bool colFree = true; for (int j = 0; j < data.Map.GetLength(1); ++j) { if (data.GetMapAt(new Location(currentCol, j)) || !data.GetMapAt(new Location(col, j))) { colFree = false; break; } } //If the whole column is one line, just use that. if (colFree) { //If the level wraps around, use a large line. if (data.WrapY) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)), current, new Line(Orientation.Vertical, new Interval(-data.Map.GetLength(1), 2.0f * data.Map.GetLength(1), true, 2), (col + currentCol) * 0.5f)); } else { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)), current, new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)); } } //Otherwise, go through one wall at a time and build individual collections of Lines. else { //An edge is a whole Line if it spans an unbroken column of walls with no walls covering the edge. //Use a counter to run through the whole column in groups of unbroken walls. startingY = 0; currentY = 0; temp = null; while (startingY < data.Map.GetLength(1)) { //Get the next valid spot to start from. while ((!data.GetMapAt(new Location(col, startingY)) || data.GetMapAt(new Location(currentCol, startingY))) && startingY < data.Map.GetLength(1)) { currentY += 1; startingY = currentY; } if (startingY >= data.Map.GetLength(1)) { break; } //Keep the counter going as long as the next spot is valid (i.e. // there is a wall to the side but not in the way). while (data.GetMapAt(new Location(col, currentY + 1)) && !data.GetMapAt(new Location(currentCol, currentY + 1)) && currentY < data.Map.GetLength(1)) { currentY += 1; } //Now make the line. temp = new Interval(startingY, currentY, true, 2); associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp, col)), current, new Line(Orientation.Vertical, temp, (col + currentCol) * 0.5f)); //If this is near the top, wrap it around to the bottom. if (data.WrapY && temp.Start < 2.0f) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp + data.WorldSize.Y, col)), current, new Line(Orientation.Vertical, temp + data.WorldSize.Y, (col + currentCol) * 0.5f)); } //Move to the next spot in the column. startingY = currentY + 1; currentY = startingY; } //If the level wraps around in the Y, take the last Line and wrap it around. if (temp != null && data.WrapY) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp - data.WorldSize.Y, col)), current, new Line(Orientation.Vertical, temp - data.WorldSize.Y, (col + currentCol) * 0.5f)); } } } }
/// <summary> /// Gets all continuous top/bottom Lines from the given level using all the walls in the given row. /// The Lines are indexed by all wall bounds that make up part of that indexed Line. /// </summary> public static void GetHorizontalLines(FillData data, WallToLines associations, int row) { int startingX, currentX; Interval temp; ColType current; bool bottomRow = (row == data.Map.GetLength(1) - 1); //Do the algorithm for both above and below the row. int currentRow; for (int dir = -1; dir < 2; dir += 2) { currentRow = row + dir; current = (currentRow < row ? ColType.Bottom : ColType.Top); //There is one special case: the whole row is a valid line. bool rowFree = true; for (int i = 0; i < data.Map.GetLength(0); ++i) { if (data.GetMapAt(new Location(i, currentRow)) || !data.GetMapAt(new Location(i, row))) { rowFree = false; break; } } //If the whole row is one line, just use that. if (rowFree) { //If the level wraps around, use a large line. if (data.WrapX) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)), current, new Line(Orientation.Horizontal, new Interval(-data.Map.GetLength(0), 2.0f * data.Map.GetLength(0), true, 2), (row + currentRow) * 0.5f)); } else { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)), current, new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)); } } //Otherwise, go through one wall at a time and build individual collections of Lines. else { //An edge is a whole Line if it spans an unbroken row of walls with no walls covering the edge. //Use a counter to run through the whole row in groups of unbroken rows. startingX = 0; currentX = 0; temp = null; while (startingX < data.Map.GetLength(0)) { //Get the next valid spot to start from. while ((!data.GetMapAt(new Location(startingX, row)) || data.GetMapAt(new Location(startingX, currentRow))) && startingX < data.Map.GetLength(0)) { currentX += 1; startingX = currentX; } if (startingX >= data.Map.GetLength(0)) { break; } //Keep the counter going as long as the next spot is valid (i.e. // there is a wall in this row but not above/underneath). while (data.GetMapAt(new Location(currentX + 1, row)) && !data.GetMapAt(new Location(currentX + 1, currentRow)) && currentX < data.Map.GetLength(0)) { currentX += 1; } //Now make the line. temp = new Interval(startingX, currentX, true, 2); associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp, row)), current, new Line(Orientation.Horizontal, temp, (row + currentRow) * 0.5f)); //If this is near the left, wrap it around to the right. if (data.WrapX && temp.Start < 2.0f) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp + data.WorldSize.X, row)), current, new Line(Orientation.Horizontal, temp + data.WorldSize.X, (row + currentRow) * 0.5f)); } //Move to the next spot in the row. startingX = currentX + 1; currentX = startingX; } //If the level wraps around in the X, take the last Line and wrap it around. if (temp != null && data.WrapX) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp - data.WorldSize.X, row)), current, new Line(Orientation.Horizontal, temp - data.WorldSize.X, (row + currentRow) * 0.5f)); } } } }