private bool IsLineIntersectsRectangle(Line line, DelaunayMSTRoom room) { Vector2 intersection; Vector2 bottomLeft = new Vector3(room.x, room.y); Vector2 bottomRight = new Vector3(room.x + room.width, room.y); Vector2 topLeft = new Vector3(room.x, room.y + room.height); Vector2 topRight = new Vector3(room.x + room.width, room.y + room.height); if (UnityUtilities.Math.IsLineIntersects(line.start, line.end, bottomLeft, bottomRight, out intersection)) { return(true); } if (UnityUtilities.Math.IsLineIntersects(line.start, line.end, bottomLeft, topLeft, out intersection)) { return(true); } if (UnityUtilities.Math.IsLineIntersects(line.start, line.end, topRight, topLeft, out intersection)) { return(true); } if (UnityUtilities.Math.IsLineIntersects(line.start, line.end, topRight, bottomRight, out intersection)) { return(true); } return(false); }
// take all the midpoints of the selected rooms and feed that into the Delaunay procedure // generate a graph, also it's good to have ID for rooms // and generate minimum spanning tree private void TriangulateMainRoomsMidpointsAndGenerateMST() { List <Vector2> midpoints = new List <Vector2>(); List <uint> colors = new List <uint>(); // Colors are just necessary part for choosen delaunay library Vector2 min = Vector2.positiveInfinity; Vector2 max = Vector2.zero; for (int i = 0; i < rooms.Count; i++) { DelaunayMSTRoom room = rooms[i]; if (room.isMainRoom) { colors.Add(0); midpoints.Add(new Vector2(room.x + room.width / 2, room.y + room.height / 2)); // use division (not multiplication) because we need INT value (or use RoundToInt) min.x = Mathf.Min(min.x, room.x); min.y = Mathf.Min(min.y, room.y); max.x = Mathf.Max(max.x, room.x); max.y = Mathf.Max(max.y, room.y); } } Delaunay.Voronoi voronoi = new Delaunay.Voronoi(midpoints, colors, new Rect(min.x, min.y, max.x, max.y)); delaunayLines = voronoi.DelaunayTriangulation(); // Triangulate main rooms spanningTree = voronoi.SpanningTree(Delaunay.KruskalType.MINIMUM); //Find min. span. tree if (settings.isDebugLogEnabled) { Debug.Log("Main passages count: " + spanningTree.Count); } }
private DelaunayMSTRoom GetRoomByPoint(float x, float y) { DelaunayMSTRoom room = default(DelaunayMSTRoom); foreach (var r in rooms) { if (r.x < x && r.y < y && r.x + r.width > x && r.y + r.height > y) { return(r); } } return(room); }
//private void AddRoomsMidpointsToConnectionLines() //{ // foreach (Delaunay.Geo.LineSegment line in spanningTree) // { // DelaunayMSTRoom roomStart = GetRoomByPoint(line.p0.Value.x, line.p0.Value.y); // if (roomStart != null) // { // line.cellStart = roomStart; // } // else // { // Debug.LogError("Could not find cell start for " + line.p0.Value); // } // DelaunayMSTRoom roomEnd = GetRoomByPoint(line.p1.Value.x, line.p1.Value.y); // if (roomEnd != null) // { // line.cellEnd = roomEnd; // } // else // { // Debug.LogError("Could not find cell end for " + line.p1.Value); // } // } //} private void FindConnectedRoomsAndPathsBetweenThem() { foreach (var line in spanningTree) { DelaunayMSTRoom roomStart = GetRoomByPoint(line.p0.Value.x, line.p0.Value.y); if (roomStart == null) { Debug.LogError("Could not find cell start for " + line.p0.Value); } DelaunayMSTRoom roomEnd = GetRoomByPoint(line.p1.Value.x, line.p1.Value.y); if (roomEnd == null) { Debug.LogError("Could not find cell end for " + line.p1.Value); } Vector2Int start = new Vector2Int((int)line.p0.Value.x, (int)line.p0.Value.y); Vector2Int end = new Vector2Int((int)line.p1.Value.x, (int)line.p1.Value.y); //Vector2 start = line.p0.Value; //Vector2 end = line.p1.Value; Line firstHallway = new Line { start = start, //blockPath.end = new Vector2(end.x, start.y); end = new Vector2Int(end.x, start.y) }; Line secondHallway = new Line { start = firstHallway.end, end = end }; RoomsConnection path = new RoomsConnection { from = roomStart, to = roomEnd }; path.path.Add(firstHallway); path.path.Add(secondHallway); paths.Add(path); } spanningTree.Clear(); }
private void TranslateAllPointsCorrespondingToZeroOriginOfCoordinates() { // Find corners of map and remove unnecessary rooms for (int i = rooms.Count - 1; i >= 0; i--) { DelaunayMSTRoom room = rooms[i]; if (!room.isMainRoom && !room.isPathRoom) { rooms.Remove(room); } else { minX = Mathf.Min(room.x, minX); minY = Mathf.Min(room.y, minY); maxX = Mathf.Max(room.x + room.width - 1, maxX); maxY = Mathf.Max(room.y + room.height - 1, maxY); } } // translate rooms => make starting point == 0, 0 foreach (DelaunayMSTRoom room in rooms) { room.x -= minX; room.y -= minY; } // and connections between them foreach (RoomsConnection connection in paths) { foreach (Line hallway in connection.path) { hallway.start.x -= minX; hallway.start.y -= minY; hallway.end.x -= minX; hallway.end.y -= minY; } } maxX -= minX; maxY -= minY; minX = 0; minY = 0; }
//public void GenerateLevel() //{ // StartCoroutine(Generate()); //} //public IEnumerator Generate() //{ // // Random Generator // Random.State initialState = Random.state; // if (settings.useFixedSeed) // { // Random.InitState(settings.seed.GetHashCode()); // } // else // { // Random.InitState(Time.time.ToString().GetHashCode()); // } // SpawnOverlappingRooms(); // if (debug) // { // Debug.Log("Cells generated"); // yield return new WaitForSeconds(1.0f); // } // SettleOutRooms(); // if (debug) // { // Debug.Log("Cells Separated"); // yield return new WaitForSeconds(1.0f); // } // PickMainRooms(); // if (debug) // { // Debug.Log("Main rooms selected"); // yield return new WaitForSeconds(1.0f); // } // TriangulateMainRoomsMidpointsAndGenerateMST(); // if (debug) // { // Debug.Log("Delaunay proceeded"); // yield return new WaitForSeconds(1.0f); // } // CreateAdditionalConnectionsBetweenRooms(); // if (debug) // { // Debug.Log("Paths Selected"); // yield return new WaitForSeconds(1.0f); // } // //AddRoomsMidpointsToConnectionLines(); // //if (debug) // //{ // // Debug.Log("Cell Lines"); // // yield return new WaitForSeconds(1.0f); // //} // FindConnectedRoomsAndPathsBetweenThem(); // if (debug) // { // Debug.Log("RoomsConnection between blocks"); // yield return new WaitForSeconds(1.0f); // } // FindPathRoomsBetweenMainRooms(); // if (debug) // { // Debug.Log("RoomsConnection between main rooms"); // yield return new WaitForSeconds(1.0f); // } // if (OnLevelGenerationComplete != null) // { // OnLevelGenerationComplete(); // } // Random.state = initialState; // yield return null; //} #region GenerationMethods private void SpawnOverlappingRooms() { averageRoomWidth = 0; averageRoomHeight = 0; for (int i = 0; i < settings.numberOfRoomsToSpawn; i++) { // place rooms randomly inside a circle Vector2 pos = UnityUtilities.Math.GetRandomPointInCircle(settings.roomSpawnCircleRadius); // use the normal distribution for generating room sizes // Picking different ratios between width/height mean and standard deviation will generally result in different looking dungeons // Round to Int - because we use grid DelaunayMSTRoom room = new DelaunayMSTRoom { width = Mathf.RoundToInt(UnityUtilities.RandomNormalDistribution.RandomRangeGaussian(settings.roomMinWidth, settings.roomMaxWidth, UnityUtilities.RandomNormalDistribution.ConfidenceInterval._80)), height = Mathf.RoundToInt(UnityUtilities.RandomNormalDistribution.RandomRangeGaussian(settings.roomMinHeight, settings.roomMaxHeight, UnityUtilities.RandomNormalDistribution.ConfidenceInterval._80)), index = i, x = Mathf.RoundToInt(pos.x), y = Mathf.RoundToInt(pos.y) }; averageRoomWidth += room.width; averageRoomHeight += room.height; if (settings.isDebugLogEnabled) { Debug.Log("Room width = " + room.width + " room height = " + room.height + " posX = " + room.x + " posY = " + room.y); } rooms.Add(room); } averageRoomWidth /= rooms.Count; averageRoomHeight /= rooms.Count; if (settings.isDebugLogEnabled) { Debug.Log("Room Average width = " + averageRoomWidth + " average room height = " + averageRoomHeight); } }
//AABB inclusive public bool CollidesWith(DelaunayMSTRoom room) { return(!((room.x >= this.x + this.width) || (room.y >= this.y + this.height) || (room.x + room.width <= this.x) || (room.y + room.height <= this.y))); }
public void FillCellMap(ref Cell[,] map, CellType wallCell = CellType.Empty, CellType floorCell = CellType.Empty) { if (wallCell == CellType.Empty && floorCell == CellType.Empty) { Debug.LogError("Both cell types are CellType.Empty."); return; } // Spawn rooms for (int i = 0; i < rooms.Count; i++) { DelaunayMSTRoom room = rooms[i]; for (int x = room.x; x < room.x + room.width; x++) { map[x, room.y] = Cell.CreateCell(wallCell); map[x, room.y + room.height - 1] = Cell.CreateCell(wallCell); } for (int z = room.y; z < room.y + room.height; z++) { map[room.x, z] = Cell.CreateCell(wallCell); map[room.x + room.width - 1, z] = Cell.CreateCell(wallCell); } for (int z = room.y + 1; z < room.y + room.height - 1; z++) { for (int x = room.x + 1; x < room.x + room.width - 1; x++) { map[x, z] = Cell.CreateCell(floorCell); } } } // Spawn hallways for (int i = 0; i < paths.Count; i++) { RoomsConnection connection = paths[i]; for (int j = 0; j < connection.path.Count; j++) { Line hallway = connection.path[j]; int fromX = Mathf.Min(hallway.start.x, hallway.end.x); int toX = Mathf.Max(hallway.start.x, hallway.end.x); int fromZ = Mathf.Min(hallway.start.y, hallway.end.y); int toZ = Mathf.Max(hallway.start.y, hallway.end.y); for (int x = fromX; x <= toX; x++) { for (int z = fromZ; z <= toZ; z++) { map[x, z] = Cell.CreateCell(floorCell); AddPathWalls(x, z, ref map, wallCell, floorCell); } } } } }
//separation steering behavior private void SettleOutRooms() { bool cellCollision = true; int loop = 0; int count = 0; while (cellCollision) { loop++; cellCollision = false; if (settings.isDebugLogEnabled) { Debug.Log("Loop " + loop); } for (int i = 0; i < rooms.Count; i++) { DelaunayMSTRoom roomA = rooms[i]; for (int j = i + 1; j < rooms.Count; j++) { count++; DelaunayMSTRoom roomB = rooms[j]; if (roomA.CollidesWith(roomB)) { cellCollision = true; int roomB_x = Mathf.RoundToInt((roomA.x + roomA.width) - roomB.x); //between rightmost point of cellA and leftmost point of cellB int roomA_x = Mathf.RoundToInt((roomB.x + roomB.width) - roomA.x); //between leftmost point of cellA and rightmost point of cellB int roomB_y = Mathf.RoundToInt((roomA.y + roomA.height) - roomB.y); int roomA_y = Mathf.RoundToInt((roomB.y + roomB.height) - roomA.y); if (settings.isDebugLogEnabled) { Debug.Log("cb_x = " + roomB_x + " cell_x = " + roomA_x + " cb_y = " + roomB_y + " cell_y = " + roomA_y); } // cellB inside cellA, cellB intruded from left or cellB intuded from bottom //if (cellA_x < cellB_x) // stretched along x if (roomA_x < roomB_x || roomA_y < roomB_y) // both axis //if (cellA_y < cellB_y) // results: rooms expand along y axis { if (roomA_x < roomA_y) // horizontal or vertical movement { roomA.Shift(roomA_x, 0); } else { roomA.Shift(0, roomA_y); } } else { if (roomB_x < roomB_y) { roomB.Shift(roomB_x, 0); } else { roomB.Shift(0, roomB_y); } } } } } } if (settings.isDebugLogEnabled) { Debug.Log("Count " + count); } }