private Rect CreateRectRoom(int width, int height, bool firstRoom = false) { int x, y; // Position the room if (firstRoom) { // Initial room, so start near center x = Rng.TriangleInt((_writer.Bounds.Width - width) / 2, (_writer.Bounds.Width - width) / 2 - 4); y = Rng.TriangleInt((_writer.Bounds.Height - height) / 2, (_writer.Bounds.Height - height) / 2 - 4); } else { // Place it wherever x = Rng.Int(_writer.Bounds.Width); y = Rng.Int(_writer.Bounds.Height); } Rect bounds = new Rect(x, y, width, height); // Check to see if the room can be positioned if (!_writer.IsOpen(bounds.Inflate(1), null)) { return(Rect.Empty); } return(bounds); }
/// <summary> /// Gets whether the given rectangle is empty (i.e. solid stone) and can have a feature placed in it. /// </summary> /// <param name="rect">The rectangle to test.</param> /// <param name="exception">An optional exception position. If this position is not stone, it is still possible /// to use the rect. Used for the connector to a new feature.</param> /// <remarks>It tests this by verifying each tile within the rect is a stone square. Originally only traced /// the perimeter, but that was allowing rooms to fully enclose other rooms.</remarks> public bool IsOpen(Rect rect, Vec2?exception) { // must be totally in bounds if (!_map.Bounds.Contains(rect)) { return(false); } // and not cover an existing feature foreach (Vec2 tile in rect) { // allow the exception if (exception != null && (exception == tile)) { continue; } if (_map.Tiles[tile].Type != Tiles.Stone) { return(false); } } return(true); }
public void TestEnumerateColumn() { TestEnumeration(Rect.Column(4, 5, 3), new Vec2(4, 5), new Vec2(4, 6), new Vec2(4, 7)); }
public void TestEnumerateRow() { TestEnumeration(Rect.Row(4, 5, 3), new Vec2(4, 5), new Vec2(5, 5), new Vec2(6, 5)); }
public void TestRow() { Rect r = Rect.Row(4); Assert.AreEqual(0, r.Position.x); Assert.AreEqual(0, r.Position.y); Assert.AreEqual(4, r.Size.x); Assert.AreEqual(1, r.Size.y); }
public void TestConstructorPositionIntSizeVec() { Rect r = new Rect(2, 4, new Vec2(3, 5)); Assert.AreEqual(2, r.Position.x); Assert.AreEqual(4, r.Position.y); Assert.AreEqual(3, r.Size.x); Assert.AreEqual(5, r.Size.y); }
public void TestColumn() { Rect r = Rect.Column(4); Assert.AreEqual(0, r.Position.x); Assert.AreEqual(0, r.Position.y); Assert.AreEqual(1, r.Size.x); Assert.AreEqual(4, r.Size.y); }
public void TestRowPos() { Rect r = Rect.Row(-2, 3, 4); Assert.AreEqual(-2, r.Position.x); Assert.AreEqual(3, r.Position.y); Assert.AreEqual(4, r.Size.x); Assert.AreEqual(1, r.Size.y); }
public void TestConstructorDefault() { Rect r = new Rect(); Assert.AreEqual(0, r.Position.x); Assert.AreEqual(0, r.Position.y); Assert.AreEqual(0, r.Size.x); Assert.AreEqual(0, r.Size.y); }
public void TestConstructorPositionVecSizeInt() { Rect r = new Rect(new Vec2(2, 4), 3, 5); Assert.AreEqual(2, r.Position.x); Assert.AreEqual(4, r.Position.y); Assert.AreEqual(3, r.Size.x); Assert.AreEqual(5, r.Size.y); }
public void TestColumnVecPos() { Rect r = Rect.Column(new Vec2(-2, 3), 4); Assert.AreEqual(-2, r.Position.x); Assert.AreEqual(3, r.Position.y); Assert.AreEqual(1, r.Size.x); Assert.AreEqual(4, r.Size.y); }
public void TestEmpty() { Rect r = Rect.Empty; Assert.AreEqual(0, r.Position.x); Assert.AreEqual(0, r.Position.y); Assert.AreEqual(0, r.Size.x); Assert.AreEqual(0, r.Size.x); }
public void TestConstructorSizeVec() { Rect r = new Rect(new Vec2(3, 5)); Assert.AreEqual(0, r.Position.x); Assert.AreEqual(0, r.Position.y); Assert.AreEqual(3, r.Size.x); Assert.AreEqual(5, r.Size.y); }
public bool CreateFeature(string name, out Rect bounds) { switch (name) { case "room": return(MakeRoom(out bounds)); default: throw new ArgumentException($"Unknown feature \"{name}\""); } }
private void Populate(Rect bounds, int monsterDensity, int itemDensity) { // TODO: For testing, place one NPC in each room. For real this should probably be more random! //foreach (Rect room in _rooms) { int xOffset = Rng.Int(bounds.Width); int yOffset = Rng.Int(bounds.Height); Vec2 location = bounds.Position + new Vec2(xOffset, yOffset); _writer.Populate(location); } }
private Rect CreateRoom(bool startingRoom = false) { int width = Rng.Int(_writer.Options.RoomSizeMin, _writer.Options.RoomSizeMax); int height = Rng.Int(_writer.Options.RoomSizeMin, _writer.Options.RoomSizeMax); Rect bounds = CreateRectRoom(width, height, startingRoom); // Bail if we failed if (bounds == Rect.Empty) { return(bounds); } // Place the room foreach (Vec2 position in bounds) { _writer.SetTile(position, Tiles.Floor); } // And the walls surrounding the room foreach (Vec2 position in bounds.Trace()) { _writer.SetTile(position, Tiles.Wall); } // === Room decoration code here === //TileType decoration = ChooseInnerWall(); //RoomDecoration.Decorate(bounds, new RoomDecorator(this, position => _writer.Populate(position, 60, 200))); //_writer.LightRect(bounds); // place the connectors //AddRoomConnectors(bounds); Populate(bounds, 20, 20); // === End room decoration code === _rooms.Add(bounds); return(bounds); }
public void TestCoordinates() { Rect rect = new Rect(1, 2, 3, 4); // x, y Assert.AreEqual(1, rect.x); Assert.AreEqual(2, rect.y); // size Assert.AreEqual(3, rect.Width); Assert.AreEqual(4, rect.Height); // ltrb Assert.AreEqual(1, rect.Left); Assert.AreEqual(2, rect.Top); Assert.AreEqual(1 + 3, rect.Right); Assert.AreEqual(2 + 4, rect.Bottom); // ltrb vecs Assert.AreEqual(new Vec2(1, 2), rect.TopLeft); Assert.AreEqual(new Vec2(1 + 3, 2), rect.TopRight); Assert.AreEqual(new Vec2(1, 2 + 4), rect.BottomLeft); Assert.AreEqual(new Vec2(1 + 3, 2 + 4), rect.BottomRight); }
private bool MakeRoom(out Rect bounds) { bounds = CreateRoom(); return(bounds != Rect.Empty); }
public bool MakeHalls() { List <Vertex> vertices = new List <Vertex>(); // add a vertex at the center of each room foreach (Rect room in _rooms) { vertices.Add(new Vertex <Rect>(new Vector2(room.Center.x, room.Center.y), room)); } // Create a Delaunay triangulation of the rooms _delaunay = Delaunay2D.Triangulate(vertices); // Convert the Delaunay edges to Prim edges List <Prim.Edge> edges = new List <Prim.Edge>(); foreach (Delaunay2D.Edge edge in _delaunay.Edges) { edges.Add(new Prim.Edge(edge.U, edge.V)); } // Create a minimum spanning tree of the triangulation List <Prim.Edge> mst = Prim.MinimumSpanningTree(edges, edges[0].U); // Get the edges not part of the MST HashSet <Prim.Edge> selectedEdges = new HashSet <Prim.Edge>(mst); HashSet <Prim.Edge> remainingEdges = new HashSet <Prim.Edge>(edges); remainingEdges.ExceptWith(selectedEdges); // Create some loops, since MSTs make for boring maps foreach (Prim.Edge edge in remainingEdges) { if (Rng.Int(100) < _writer.Options.ChanceOfExtraHallway) { selectedEdges.Add(edge); } } // Drive a pathfinder to carve out the halls Motility motility = Motility.FourWayNeighbors | Motility.Unconstrained; foreach (Prim.Edge edge in selectedEdges) { Rect startRoom = (edge.U as Vertex <Rect>).Item; Rect endRoom = (edge.V as Vertex <Rect>).Item; GridNode start = _writer.GetTile(new Vec2(startRoom.Center.x, startRoom.Center.y)); GridNode goal = _writer.GetTile(new Vec2(endRoom.Center.x, endRoom.Center.y)); // Heuristic is Manhattan distance on a square grid IList <GridNode> path = _writer.Graph.FindPath <AStarSearchAlgorithm>(start, goal, motility, (a, b) => Math.Abs((float)(a.Position.x - b.Position.x)) + Math.Abs((float)(a.Position.y - b.Position.y))); // Bail if the pathfinder failed to find a path (NOTE: if it does, it seems like it should be a problem) if (path == null) { continue; } foreach (GridNode step in path) { _writer.SetTile(step.Position, Tiles.Floor); foreach (GridNode neighbor in step.Neighbors) { if ((_writer.GetTile(neighbor.Position)).Type == Tiles.Stone) { _writer.SetTile(neighbor.Position, Tiles.Wall); } } } } return(true); }