public bool HasAdjacentCellInDirection(Vector2I location, Direction direction) { // Check that the location falls within the bounds of the map: if (!Bounds.Contains(location)) { return false; } // Check if there is an adjacent cell in the direction: if (direction.Equals(Direction.North)) { return location.Y > 0; } else if (direction.Equals(Direction.South)) { return location.Y < (Rows - 1); } else if (direction.Equals(Direction.West)) { return location.X > 0; } else if (direction.Equals(Direction.East)) { return location.X < (Columns - 1); } else { return false; } }
public void SetLocation(Vector2I location) { var bounds = Bounds; bounds.X = location.X; bounds.Y = location.Y; Bounds = bounds; }
/// <summary> /// Is this given point in one of the room's corners? /// </summary> /// <remarks> /// A corner cannot be walked to, so it is a bad place to put a door. /// </remarks> public bool IsPointInCorner(Vector2I point) { return (point == Bounds.TopLeft) || (point == Bounds.TopRight) || (point == Bounds.BottomLeft) || (point == Bounds.BottomRight); }
/// <summary> /// Is this given point on this room's boundary? /// </summary> /// <remarks> /// The room will generate walls on it's boundary, /// so if this returns true it may be a good place to put a door. /// </remarks> public bool IsPointOnBounds(Vector2I point) { return (point.X == Bounds.Left) || (point.X == Bounds.Right) || (point.Y == Bounds.Top) || (point.Y == Bounds.Bottom); }
public Cell this[Vector2I location] { get { return this[location.Row, location.Column]; } set { this[location.Row, location.Column] = value; } }
private void PlaceDoors(LabyrinthDungeon dungeon) { foreach (var room in dungeon.Rooms) { var hasNorthDoor = false; var hasSouthDoor = false; var hasWestDoor = false; var hasEastDoor = false; // TODO: Convert this into 4 loops on the sides of the room. for (var row = 0; row < room.Rows; row++) { for (var column = 0; column < room.Columns; column++) { var cellLocation = new Vector2I(column, row); // Translate the room cell location to its location in the dungeon: var dungeonLocation = new Vector2I(room.Bounds.X, room.Bounds.Y) + cellLocation; // Check if we are on the west boundary of our roomand if there is a corridor to the west: if (!hasWestDoor && (cellLocation.X == 0) && dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.West)) { dungeon.CreateDoor(dungeonLocation, Direction.West); hasWestDoor = true; } // Check if we are on the east boundary of our room and if there is a corridor to the east if (!hasEastDoor && (cellLocation.X == room.Columns - 1) && dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.East)) { dungeon.CreateDoor(dungeonLocation, Direction.East); hasEastDoor = true; } // Check if we are on the north boundary of our room and if there is a corridor to the north if (!hasNorthDoor && (cellLocation.Y == 0) && dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.North)) { dungeon.CreateDoor(dungeonLocation, Direction.North); hasNorthDoor = true; } // Check if we are on the south boundary of our room and if there is a corridor to the south if (!hasSouthDoor && (cellLocation.Y == room.Rows - 1) && dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.South)) { dungeon.CreateDoor(dungeonLocation, Direction.South); hasSouthDoor = true; } } } } }
private int CalculateRoomPlacementScore(Vector2I location, LabyrinthDungeon dungeon, Room room) { // Check if the room at the given location will fit inside the bounds of the map. if (Contains(dungeon.Bounds, location, room)) { var roomPlacementScore = 0; // Loop for each cell in the room. for (var column = 0; column < room.Columns; column++) { for (var row = 0; row < room.Rows; row++) { // Translate the room cell location to its location in the dungeon. var dungeonLocation = location + new Vector2I(column, row); // Add 1 point for each adjacent corridor to the cell. if (dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.North)) { roomPlacementScore++; } if (dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.South)) { roomPlacementScore++; } if (dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.West)) { roomPlacementScore++; } if (dungeon.AdjacentCellInDirectionIsCorridor(dungeonLocation, Direction.East)) { roomPlacementScore++; } // Add 3 points if the cell overlaps an existing corridor. if (dungeon[dungeonLocation].IsCorridor) { roomPlacementScore += 3; } // Add 100 points if the cell overlaps any existing room cells. foreach (var dungeonRoom in dungeon.Rooms) { if (dungeonRoom.Bounds.Contains(dungeonLocation)) { roomPlacementScore += 100; } } } } return roomPlacementScore; } else { return int.MaxValue; } }
private bool Contains(RectI bounds, Vector2I roomLocation, Room room) { return bounds.Contains(roomLocation.X, roomLocation.Y) && bounds.Contains(roomLocation.X + room.Columns - 1, roomLocation.Y) && bounds.Contains(roomLocation.X + room.Columns - 1, roomLocation.Y + room.Rows - 1) && bounds.Contains(roomLocation.X, roomLocation.Y + room.Rows - 1); }
public static Direction FromVector(Vector2I v) { v = v.Normalized; if (v.Equals(-Vector2I.UnitY)) { return North; } if (v.Equals(Vector2I.UnitY)) { return South; } if (v.Equals(Vector2I.UnitX)) { return East; } if (v.Equals(-Vector2I.UnitX)) { return West; } return North; }
private Chunk ExcavateRooms(Chunk chunk, LabyrinthDungeon dungeon, IProgress<string> progress) { progress.Report("Excavating room..."); progress.Report($"Room count: {dungeon.Rooms.Count}"); // Fill tiles with corridor values for each room in dungeon. foreach (var room in dungeon.Rooms) { // Get the room min and max location in tile coordinates. var right = room.Bounds.X + room.Bounds.Width - 1; var bottom = room.Bounds.Y + room.Bounds.Height - 1; var minPoint = new Vector2I(room.Bounds.X * 2 + 1, room.Bounds.Y * 2 + 1); var maxPoint = new Vector2I(right * 2, bottom * 2); // Fill the room in tile space with an empty value. for (var row = minPoint.Y; row <= maxPoint.Y; row++) { for (var column = minPoint.X; column <= maxPoint.X; column++) { ExcavateChunkPoint(chunk, new Vector2I(column, row)); } } } progress.Report("Room complete!"); return chunk; }
private void ExcavateChunkPoint(Chunk chunk, Vector2I chunkPoint) { chunk[ChunkLayer.Blocking, chunkPoint.X, chunkPoint.Y] = 0; }
protected Vector2I GetTargetLocation(Vector2I location, Direction direction) { if (!HasAdjacentCellInDirection(location, direction)) { throw new InvalidOperationException("No adjacent cell exists for the location and direction provided."); } if (direction.Equals(Direction.North)) { return location - Vector2I.UnitY; } else if (direction.Equals(Direction.South)) { return location + Vector2I.UnitY; } else if (direction.Equals(Direction.West)) { return location - Vector2I.UnitX; } else if (direction.Equals(Direction.East)) { return location + Vector2I.UnitX; } else { throw new InvalidOperationException("No adjacent cell exists for the location and direction provided."); } }
public Vector2I CreateWall(Vector2I location, Direction direction) { return CreateSide(location, direction, SideType.Wall); }
public Vector2I CreateCorridor(Vector2I location, Direction direction) { return CreateSide(location, direction, SideType.Empty); }
public Vector2I GetRandomVisitedCell(Vector2I location, Random random) { if (!_visitedCells.Any()) { throw new InvalidOperationException("There are no visited cells to return."); } var index = random.Next(_visitedCells.Count); // Loop while the current cell is the visited cell: while (_visitedCells[index] == location) { index = random.Next(_visitedCells.Count); } return _visitedCells[index]; }
private bool LocationIsOutsideBounds(Vector2I location) { return ((location.X < 0) || (location.X >= Columns) || (location.Y < 0) || (location.Y >= Rows)); }
public void FlagCellAsVisited(Vector2I location) { if (LocationIsOutsideBounds(location)) { throw new Exception("Location is outside of map bounds."); } if (this[location].Visited) { throw new Exception("Location is already visited."); } else { this[location].Visited = true; _visitedCells.Add(location); } }
public bool AdjacentCellInDirectionIsCorridor(Vector2I location, Direction direction) { if (!HasAdjacentCellInDirection(location, direction)) { return false; } var target = GetTargetLocation(location, direction); return this[target].IsCorridor; }
public bool AdjacentCellInDirectionIsVisited(Vector2I location, Direction direction) { if (!HasAdjacentCellInDirection(location, direction)) { throw new InvalidOperationException("No adjacent cell exists for the location and direction provided."); } return this[location + direction.ToVector2I()].Visited; }
private bool InBounds(Vector2I v) { return this.InBounds(v.X, v.Y); }
public Vector2I CreateDoor(Vector2I location, Direction direction) { return CreateSide(location, direction, SideType.Door); }
private Chunk ExcavateCorridors(Chunk chunk, LabyrinthDungeon dungeon) { // Loop for each corridor cell and expand it. foreach (var cellLocation in dungeon.CorridorCellLocations) { var tileLocation = new Vector2I(cellLocation.X * 2 + 1, cellLocation.Y * 2 + 1); ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X, tileLocation.Y)); if (dungeon[cellLocation].NorthSide == SideType.Empty) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X, tileLocation.Y - 1)); } else if (dungeon[cellLocation].NorthSide == SideType.Door) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X, tileLocation.Y - 1)); chunk[ChunkLayer.Blocking, tileLocation.X, tileLocation.Y - 1] = _doorId; } if (dungeon[cellLocation].SouthSide == SideType.Empty) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X, tileLocation.Y + 1)); } else if (dungeon[cellLocation].SouthSide == SideType.Door) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X, tileLocation.Y + 1)); chunk[ChunkLayer.Blocking, tileLocation.X, tileLocation.Y + 1] = _doorId; } if (dungeon[cellLocation].WestSide == SideType.Empty) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X - 1, tileLocation.Y)); } else if (dungeon[cellLocation].WestSide == SideType.Door) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X - 1, tileLocation.Y)); chunk[ChunkLayer.Blocking, tileLocation.X - 1, tileLocation.Y] = _doorId; } if (dungeon[cellLocation].EastSide == SideType.Empty) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X + 1, tileLocation.Y)); } else if (dungeon[cellLocation].EastSide == SideType.Door) { ExcavateChunkPoint(chunk, new Vector2I(tileLocation.X + 1, tileLocation.Y)); chunk[ChunkLayer.Blocking, tileLocation.X + 1, tileLocation.Y] = _doorId; } } return chunk; }
private IEnumerable<Tuple<Vector2I, Direction, Tile>> GetSurroundings(Vector2I v) { return this.GetSurroundingPoints(v) .Select(r => Tuple.Create(r.Item1, r.Item2, this.GetCellType(r.Item1.X, r.Item1.Y))); }
private bool IsDoorAdjacent(Chunk chunk, Vector2I chunkPoint) { var north = chunk[ChunkLayer.Blocking, chunkPoint.X, chunkPoint.Y - 1]; var south = chunk[ChunkLayer.Blocking, chunkPoint.X, chunkPoint.Y + 1]; var east = chunk[ChunkLayer.Blocking, chunkPoint.X + 1, chunkPoint.Y]; var west = chunk[ChunkLayer.Blocking, chunkPoint.X - 1, chunkPoint.Y]; return (north == _doorId) || (south == _doorId) || (east == _doorId) || (west == _doorId); }
private void PlaceRoom(Vector2I location, LabyrinthDungeon dungeon, Room room) { // Offset the room origin to the new location. room.SetLocation(location); // Loop for each cell in the room for (var row = 0; row < room.Rows; row++) { for (var column = 0; column < room.Columns; column++) { // Translate the room cell location to its location in the dungeon. var dungeonLocation = location + new Vector2I(column, row); dungeon[dungeonLocation].NorthSide = room[row, column].NorthSide; dungeon[dungeonLocation].SouthSide = room[row, column].SouthSide; dungeon[dungeonLocation].WestSide = room[row, column].WestSide; dungeon[dungeonLocation].EastSide = room[row, column].EastSide; // TODO: This part may be unnecessary. // Create room walls on map (either side of the wall) if ((column == 0) && (dungeon.HasAdjacentCellInDirection(dungeonLocation, Direction.West))) { dungeon.CreateWall(dungeonLocation, Direction.West); } if ((column == room.Columns - 1) && (dungeon.HasAdjacentCellInDirection(dungeonLocation, Direction.East))) { dungeon.CreateWall(dungeonLocation, Direction.East); } if ((row == 0) && (dungeon.HasAdjacentCellInDirection(dungeonLocation, Direction.North))) { dungeon.CreateWall(dungeonLocation, Direction.North); } if ((row == room.Rows - 1) && (dungeon.HasAdjacentCellInDirection(dungeonLocation, Direction.South))) { dungeon.CreateWall(dungeonLocation, Direction.South); } } } dungeon.Rooms.Add(room); }
private Vector2I CreateSide(Vector2I location, Direction direction, SideType sideType) { var target = GetTargetLocation(location, direction); if (direction.Equals(Direction.North)) { this[location].NorthSide = sideType; this[target].SouthSide = sideType; } else if (direction.Equals(Direction.South)) { this[location].SouthSide = sideType; this[target].NorthSide = sideType; } else if (direction.Equals(Direction.West)) { this[location].WestSide = sideType; this[target].EastSide = sideType; } else if (direction.Equals(Direction.East)) { this[location].EastSide = sideType; this[target].WestSide = sideType; } return target; }
private Direction(Vector2I v) { _vector = v.Normalized; }
public Vector2I PickRandomCellAndMarkItVisited(Random random) { var pnt = new Vector2I(random.Next(Columns), random.Next(Rows)); FlagCellAsVisited(pnt); return pnt; }
private IEnumerable<Tuple<Vector2I, Direction>> GetSurroundingPoints(Vector2I v) { var points = new[] { Tuple.Create(new Vector2I(v.X, v.Y + 1), Direction.North), Tuple.Create(new Vector2I(v.X - 1, v.Y), Direction.East), Tuple.Create(new Vector2I(v.X , v.Y-1), Direction.South), Tuple.Create(new Vector2I(v.X +1, v.Y), Direction.West), }; return points.Where(p => InBounds(p.Item1)); }