Skip to content

Instantly share code, notes, and snippets.

@nefigah
Created February 14, 2011 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nefigah/826649 to your computer and use it in GitHub Desktop.
Save nefigah/826649 to your computer and use it in GitHub Desktop.
class BspLevel
{
public Tile[] Tiles { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public ArraySegment<Tile>[] Rows { get; set; }
private const int minDimension = 4;
private const int maxRoomSize = 480;
private const int minRoomSize = 16;
public BspLevel LeftSublevel { get; set; }
public BspLevel RightSublevel { get; set; }
public BspLevel(int width, int height)
{
Width = width;
Height = height;
Tiles = new Tile[width * height];
Rows = new ArraySegment<Tile>[height];
InitializeTiles();
Split();
GenerateRooms();
}
public BspLevel(ArraySegment<Tile>[] tiles)
{
Rows = tiles;
Width = tiles.First().Count;
Height = tiles.Length;
Split();
}
public Tile this[int x, int y]
{
get { return GetTile(y, x); }
}
public bool HasSublevels
{
get
{
return !(LeftSublevel == null && RightSublevel == null);
}
}
private void GenerateRooms()
{
foreach (var subdungeon in this.CollectSublevels())
{
if (Util.SomeChanceInX(9, 10) && subdungeon.Width * subdungeon.Height > minRoomSize)
{
double widthPercent = WpfRogueGame.RNG.Next(50, 100) / 100.0;
double heightPercent = WpfRogueGame.RNG.Next(50, 100) / 100.0;
int width = (int)(subdungeon.Width * widthPercent);
int height = (int)(subdungeon.Height * heightPercent);
int x = (subdungeon.Width - width) / 2;
int y = (subdungeon.Height - height) / 2;
var room = new Rectangle(x, y, width, height);
SetRectangularArea(TileType.DiscoveredFloor, room);
}
}
}
private void SetRectangularArea(TileType tileType, Rectangle room)
{
for (int y = room.Y; y < room.Height; y++)
{
for (int x = room.X; x < room.Width; x++)
{
SetTile(tileType, y, x);
}
}
}
private IEnumerable<BspLevel> CollectSublevels()
{
if (!HasSublevels)
{
yield return this;
}
else
{
if (LeftSublevel != null)
foreach (var sublevel in LeftSublevel.CollectSublevels())
yield return sublevel;
if (RightSublevel != null)
foreach (var sublevel in RightSublevel.CollectSublevels())
yield return sublevel;
}
}
private void InitializeTiles()
{
for (int i = 0; i < Tiles.Length; i++)
{
Tiles[i] = Tile.Make(TileType.Rock);
}
for (int i = 0; i < Height; i++)
{
Rows[i] = new ArraySegment<Tile>(Tiles, i * Width, Width);
}
}
private void Split()
{
bool split = (Rows.Length * Rows.First().Count >= maxRoomSize) || (Rows.Length >= minDimension * 2 && Rows.First().Count >= minDimension * 2 && Util.SomeChanceInX(7, 10));
if (split)
{
Tuple<BspLevel, BspLevel> splitted;
if (Util.SomeChanceInX(50, 100))
{
splitted = SplitHorizontally();
}
else
{
splitted = SplitVertically();
}
LeftSublevel = splitted.Item1;
RightSublevel = splitted.Item2;
}
}
private Tuple<BspLevel, BspLevel> SplitVertically()
{
if (Rows.First().Count <= minDimension * 2)
return new Tuple<BspLevel, BspLevel>(null, null);
int splitAt = WpfRogueGame.RNG.Next(0, Rows.First().Count - minDimension);
var level1 = new ArraySegment<Tile>[Rows.Length];
var level2 = new ArraySegment<Tile>[Rows.Length];
for (int j = 0; j < Rows.Length; j++)
{
level1[j] = new ArraySegment<Tile>(Rows[j].Array, Rows[j].Offset, splitAt);
level2[j] = new ArraySegment<Tile>(Rows[j].Array, Rows[j].Offset + splitAt, Rows[j].Count - splitAt);
}
return new Tuple<BspLevel, BspLevel>(new BspLevel(level1), new BspLevel(level2));
}
private Tuple<BspLevel, BspLevel> SplitHorizontally()
{
if (Rows.Length <= minDimension * 2)
return new Tuple<BspLevel, BspLevel>(null, null);
int splitAt = WpfRogueGame.RNG.Next(0, Rows.Length - minDimension);
var level1 = new ArraySegment<Tile>[splitAt];
var level2 = new ArraySegment<Tile>[Rows.Length - splitAt];
for (int i = 0; i < splitAt; i++)
{
level1[i] = Rows[i];
}
for (int i = 0; i < Rows.Length - splitAt; i++)
{
level2[i] = Rows[i];
}
return new Tuple<BspLevel, BspLevel>(new BspLevel(level1), new BspLevel(level2));
}
private Tile GetTileFromRow(ArraySegment<Tile> row, int column)
{
return row.Array[row.Offset + column];
}
private Tile GetTile(int row, int column)
{
var segment = Rows[row];
return GetTileFromRow(segment, column);
}
private void SetTile(TileType type, int row, int column)
{
var segment = Rows[row];
segment.Array[segment.Offset + column] = Tile.Make(type);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment