diff --git a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonGenerator.cs b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonGenerator.cs index 9a185c3..3da0ab8 100644 --- a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonGenerator.cs +++ b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonGenerator.cs @@ -11,7 +11,8 @@ namespace DungeonGenerator public class DungeonGenerator { private const int SIDE_LENGTH_OF_MONSTER = 4; - private const int SIDE_LENGTH_OF_NORMAL = 2; + private const int SIDE_LENGTH_OF_NORMAL = 2; + private const int SIDE_LENGTH_OF_ENTRANCE = 2; private const int WIDTH_OF_BOSS = 10; private const int HEIGHT_OF_BOSS = 6; @@ -40,10 +41,192 @@ namespace DungeonGenerator RoomType.Monster)); } - + AddNormalRoomsAroundMonsterRooms(dungeonMap); return dungeonMap; } + + enum RoomSide + { + Top, + Bottom, + Left, + Right + } + + private void AddNormalRoomsAroundMonsterRooms(DungeonMap dungeon) + { + HashSet unoccupiedPoints = dungeon.GetUnoccupiedPoints(); + Random random = new Random(); + foreach (Room monsterRoom in dungeon.GetMonsterRooms()) + { + var roomPoints = monsterRoom.GetPointsInRoom(); + int minX = roomPoints.Min(p => p.X); + int maxX = roomPoints.Max(p => p.X); + int minY = roomPoints.Min(p => p.Y); + int maxY = roomPoints.Max(p => p.Y); + + List topUnoccupiedPoints = new List(); + List bottomUnoccupiedPoints = new List(); + List leftUnoccupiedPoints = new List(); + List rightUnoccupiedPoints = new List(); + + for (int x = minX - SIDE_LENGTH_OF_NORMAL; x <= maxX + SIDE_LENGTH_OF_NORMAL; x++) + { + Point point = new Point(x, minY - SIDE_LENGTH_OF_NORMAL); + if (unoccupiedPoints.Contains(point)) + { + topUnoccupiedPoints.Add(point); + } + + point = new Point(x, maxY + SIDE_LENGTH_OF_NORMAL); + if (unoccupiedPoints.Contains(point)) + { + bottomUnoccupiedPoints.Add(point); + } + } + + for (int y = minY - SIDE_LENGTH_OF_NORMAL; y <= maxY + SIDE_LENGTH_OF_NORMAL; y++) + { + Point point = new Point(minX - SIDE_LENGTH_OF_NORMAL, y); + if (unoccupiedPoints.Contains(point)) + { + leftUnoccupiedPoints.Add(point); + } + + point = new Point(maxX + SIDE_LENGTH_OF_NORMAL, y); + if (unoccupiedPoints.Contains(point)) + { + rightUnoccupiedPoints.Add(point); + } + } + + int minNecessaryAvailablePoints = (SIDE_LENGTH_OF_MONSTER + SIDE_LENGTH_OF_NORMAL) / 2; + + List availableSides = new List(); + if (topUnoccupiedPoints.Count >= minNecessaryAvailablePoints){availableSides.Add(RoomSide.Top);} + if (bottomUnoccupiedPoints.Count >= minNecessaryAvailablePoints){availableSides.Add(RoomSide.Bottom);} + if (leftUnoccupiedPoints.Count >= minNecessaryAvailablePoints){availableSides.Add(RoomSide.Left);} + if (rightUnoccupiedPoints.Count >= minNecessaryAvailablePoints){availableSides.Add(RoomSide.Right);} + + // Ensure between 3 and 4 rooms are added + int numRoomsToAdd = Math.Min(availableSides.Count, random.Next(3, 5)); + + // Randomly shuffle and take the required number of sides + List newRooms = new List(); + foreach (RoomSide side in availableSides.OrderBy(_ => random.Next()).Take(numRoomsToAdd)) + { + // Select appropriate unoccupied points based on the side + List unoccupiedPointsOnSide = side switch + { + RoomSide.Top => topUnoccupiedPoints, + RoomSide.Bottom => bottomUnoccupiedPoints, + RoomSide.Left => leftUnoccupiedPoints, + RoomSide.Right => rightUnoccupiedPoints, + _ => new List() + }; + + // Create room and add it if valid + Room newRoom = CreateAdjacentRoom(RoomType.Normal, unoccupiedPointsOnSide, side); + if (newRoom != null) + { + newRooms.Add(newRoom); + } + } + dungeon.AddRooms(newRooms); + } + } + + private Room CreateAdjacentRoom(RoomType type, List unoccupiedPointsOnSide, RoomSide side) + { + int sizeOfNewRoom = GetRoomSizeByType(type); + Random random = new Random(); + + // Sort points by their coordinate based on the side of placement + var orderedPoints = side == RoomSide.Left || side == RoomSide.Right + ? unoccupiedPointsOnSide.OrderBy(p => p.Y).ToList() // Sort by Y for vertical placement + : unoccupiedPointsOnSide.OrderBy(p => p.X).ToList(); + + // List to store possible valid room placements (top-left points of the room) + List validPlacements = new List(); + + // Iterate over the ordered points to find potential placements + for (int i = 0; i < orderedPoints.Count - sizeOfNewRoom + 1; i++) + { + // Get a sequence of SIZE_OF_ROOM points starting from index i + var potentialPoints = orderedPoints.Skip(i).Take(sizeOfNewRoom).ToList(); + + // Check if all points are consecutive and fit within the range + if (IsRoomWideEnough(potentialPoints, side)) + { + Point firstPoint = potentialPoints.First(); + + // Adjust the first point for different sides + Point adjustedPoint = side switch + { + RoomSide.Top => new Point(firstPoint.X, firstPoint.Y), // Move up for top side + RoomSide.Bottom => new Point(firstPoint.X, firstPoint.Y - 1), // Move down for bottom side + RoomSide.Left => new Point(firstPoint.X, firstPoint.Y), // Move left for left side + RoomSide.Right => new Point(firstPoint.X - 1, firstPoint.Y), // Move right for right side + _ => firstPoint // Default case (shouldn't happen) + }; + + // If the points are wide enough, store the top-left point for the room + validPlacements.Add(adjustedPoint); // First point is the top-left point of the room + } + } + + // If there are valid placements, select a random one and create the room + if (validPlacements.Any()) + { + Point randomPlacement = validPlacements[random.Next(validPlacements.Count)]; + return new Room(type, sizeOfNewRoom, sizeOfNewRoom, randomPlacement); + } + + // If no valid placements are found, return null or handle it as necessary + return null; + } + + // Helper method to check if a sequence of points is wide enough (consecutive points) + private bool IsRoomWideEnough(List points, RoomSide side) + { + for (int i = 1; i < points.Count; i++) + { + if (side == RoomSide.Left || side == RoomSide.Right) + { + // Check if points are consecutive along the Y-axis for left/right side + if (points[i].Y != points[i - 1].Y + 1) + { + return false; + } + } + else + { + // Check if points are consecutive along the X-axis for top/bottom side + if (points[i].X != points[i - 1].X + 1) + { + return false; + } + } + } + return true; + } + + private int GetRoomSizeByType(RoomType type) + { + switch (type) + { + case RoomType.Entrance: + return SIDE_LENGTH_OF_ENTRANCE; + case RoomType.Monster: + return + SIDE_LENGTH_OF_MONSTER; + case RoomType.Normal: + return SIDE_LENGTH_OF_NORMAL; + default: + return SIDE_LENGTH_OF_NORMAL; + } + } private Room GenerateOnlyBossRoom(int xLengthOfDungeon, int yLengthOfDungeon, int width, int heigth) { diff --git a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonMap.cs b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonMap.cs index 8774671..6a9080f 100644 --- a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonMap.cs +++ b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/DungeonMap.cs @@ -13,6 +13,7 @@ namespace DungeonGenerator private int _height; private List _monsterRooms = new List(); private List _entranceRooms = new List(); + private List _normalRooms = new List(); private Room _bossRoom; private HashSet _unoccupiedPoints = new HashSet(); @@ -35,6 +36,9 @@ namespace DungeonGenerator case RoomType.Entrance: _entranceRooms.Add(room); break; + case RoomType.Normal: + _normalRooms.Add(room); + break; case RoomType.Boss: _bossRoom = room; break; @@ -47,6 +51,8 @@ namespace DungeonGenerator public void AddRooms(List rooms) { + if (rooms.Count == 0) return; + switch (rooms[0].TypeOfRoom) { case RoomType.Monster: @@ -55,6 +61,9 @@ namespace DungeonGenerator case RoomType.Entrance: _entranceRooms.AddRange(rooms); break; + case RoomType.Normal: + _normalRooms.AddRange(rooms); + break; default: return; } @@ -77,6 +86,11 @@ namespace DungeonGenerator return _entranceRooms; } + public List GetNormalRooms() + { + return _normalRooms; + } + public HashSet GetUnoccupiedPoints() { return new HashSet(_unoccupiedPoints); @@ -86,23 +100,29 @@ namespace DungeonGenerator { List monsterRoomPoints = _monsterRooms.SelectMany(room => room.GetPointsInRoom()).ToList(); List entranceRoomPoints = _entranceRooms.SelectMany(room => room.GetPointsInRoom()).ToList(); + List normalRoomPoints = _normalRooms.SelectMany(room => room.GetPointsInRoom()).ToList(); char[,] mapMatrix = new Char[_width, _height]; for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { - if (entranceRoomPoints.Contains(new Point(x, y))) + Point point = new Point(x, y); + if (entranceRoomPoints.Contains(point)) { mapMatrix[x, y] = '*'; } - else if (monsterRoomPoints.Contains(new Point(x,y))) + else if (monsterRoomPoints.Contains(point)) { mapMatrix[x, y] = 'X'; } - else if (_bossRoom.GetPointsInRoom().Contains(new Point(x, y))) + else if (_bossRoom.GetPointsInRoom().Contains(point)) { mapMatrix[x, y] = 'B'; } + else if (normalRoomPoints.Contains(point)) + { + mapMatrix[x, y] = 'N'; + } else { mapMatrix[x, y] = '-'; diff --git a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs index aeb67b4..18719a8 100644 --- a/PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs +++ b/PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using NUnit.Framework; +using Unity.VisualScripting; namespace DungeonGenerator { @@ -19,7 +21,12 @@ namespace DungeonGenerator Height = height; PositionOfTopLeft = positionOfTopLeft; } - + + private List _topAdjacentRooms = new List(); + private List _bottomAdjacentRooms = new List(); + private List _leftAdjacentRooms = new List(); + private List _rightAdjacentRooms = new List(); + public RoomType TypeOfRoom { get; set; } public int Height { get; set; } public int Width { get; set; } @@ -50,5 +57,45 @@ namespace DungeonGenerator { return new Point(PositionOfTopLeft.X + Width / 2, PositionOfTopLeft.Y + Height / 2); } + + public void AddTopAdjacentRoom(Room room) + { + _topAdjacentRooms.Add(room); + } + + public List GetTopAdjaceRooms() + { + return _topAdjacentRooms; + } + + public void AddBottomAdjacentRoom(Room room) + { + _bottomAdjacentRooms.Add(room); + } + + public List GetBottomAdjaceRooms() + { + return _bottomAdjacentRooms; + } + + public void AddLeftAdjacentRoom(Room room) + { + _leftAdjacentRooms.Add(room); + } + + public List GetLeftAdjaceRooms() + { + return _leftAdjacentRooms; + } + + public void AddRightAdjacentRoom(Room room) + { + _rightAdjacentRooms.Add(room); + } + + public List GetRightAdjaceRooms() + { + return _rightAdjacentRooms; + } } } \ No newline at end of file