Morgemil Part 9 – BSP Dungeon Generation Part 2

I’ve started a list of tiles to be found

module Morgemil.Map.Tiles
 
let DungeonFloor = TileDefinition(1, "Floor", "Dungeon floors are often trapped", false, false, TileType.Land)
let DungeonWall = TileDefinition(2, "Wall", "Dungeon walls are built from the prisoner's bones", true, true, TileType.Land)

I’ve also changed the coloring slightly which is reflected in the header image.

      let tileColor =
        match tile with
        | _ when TileDefinition.IsDefault tile -> Color.Black
        | _ when Tiles.DungeonFloor.ID = tile.ID -> Color.White
        | _ when Tiles.DungeonWall.ID = tile.ID -> Color.Red
        | _ -> Color.Gray

So as you might notice, the header image is rectangles in a jumble. Each of the rectangles represent a room in the dungeon. I accomplished this pseudo-random scattering of rooms by feeding the list of rectangles returned by the Binary Space Partitioning algorithm into a room randomizer.

  let Generate rngSeed =
    let rng = RNG.SeedRNG rngSeed
    //Hardcoded dungeon size
    let dungeon_size = Rectangle(Vector2i(512, 512))
    //Empty map
    let dungeon_map = DungeonMap(dungeon_size)
    //BSP rooms with randomized size (Rectangle List). And feeds them to the map.
    BspGenerator.GenerateRoomDivides rng dungeon_size.Size
    |> List.map (RandomizeRoom rng)
    |> List.iter (GenerateRoom dungeon_map)
    //Return a chunk to feed to visualizer
    dungeon_map.CreateChunk()

I store the unfinished map in a mutable structure which goes against everything in functional programming. The existence of a mutable structure is necessary as a dungeon requires multiple passes to generate

type private DungeonMap(roomSize : Rectangle) =
  let internal_map = Array.create roomSize.Area (TileDefinition.Default)
  member this.SetValue pos tile = internal_map.[roomSize.FlatCoord pos] <- tile
  ///Return a single giant chunk to feed into the Visualizer
  member this.CreateChunk() = Chunk(roomSize, internal_map)

Each rectangle in the BSP tree which looks like something like map_test2 is randomized but still fits inside that distinct area.

  ///Randomizes a room's position and size within the defined area
  let private RandomizeRoom rng (maxArea : Rectangle) =
    //Randomize size before placing the room randomly
    let room_size =
      MinimumRoomArea.Size + RNG.RandomVector rng (maxArea.Size - MinimumRoomArea.Size)
    let room_position = maxArea.Position + RNG.RandomVector rng (maxArea.Size - room_size)
    Rectangle(room_position, room_size)

Then the room is drawn onto the DungeonMap

  ///Writes directly on the map (side-effects). returns nothing
  let private GenerateRoom (dungeonMap : DungeonMap) (area : Rectangle) =
    let ChooseTile pt =
      match pt with
      | _ when area.IsOnEdge(pt) -> Tiles.DungeonWall
      | _ -> Tiles.DungeonFloor
    area.Coordinates |> Seq.iter (fun coord -> dungeonMap.SetValue coord (ChooseTile coord))

The results could be slightly interpreted as a dungeon where each room was haphazardly excavated and added on. map_test2
The next step will be to make connecting corridors.