Implemented multiple numbers on monster rooms

This commit is contained in:
Max 2025-02-20 17:44:46 +01:00
parent 5f0c0c5f26
commit 18908b2ae7
22 changed files with 157 additions and 85 deletions

View file

@ -17,6 +17,8 @@ class Program
int height = 20;
DungeonMap map = generator.GenerateDungeon(width, height, 5);
DungeonLockPopulator.PopulateLocksOfDungeon(map);
DungeonLockPopulator.AddExtraLocksToMonsterRooms(map.GetMonsterRooms());
DungeonLockPopulator.AddExtraLocksToBossRoom(map.GetBossRoom());
List<Room> potentialLootRooms = new List<Room>();
potentialLootRooms.AddRange(map.GetNormalRooms());
potentialLootRooms.AddRange(map.GetMonsterRooms());

View file

@ -0,0 +1,11 @@
namespace DungeonMapGenerator
{
public class BossRoom : MonsterRoom
{
public BossRoom(int width, int height, Point positionOfTopLeft)
: base(width, height, positionOfTopLeft) // Calls MonsterRoom's constructor
{
TypeOfRoom = RoomType.Boss;
}
}
}

View file

@ -35,7 +35,7 @@ namespace DungeonMapGenerator
dungeonMap.AddRoom(disperser.GenerateAndPlaceRoom(
SIDE_LENGTH_OF_MONSTER,
SIDE_LENGTH_OF_MONSTER,
RoomType.Monster));
typeof(MonsterRoom)));
}
AddNormalRoomsAroundMonsterRooms(dungeonMap);
@ -49,13 +49,13 @@ namespace DungeonMapGenerator
private void AddAdjacentRoomsToEntranceRooms(DungeonMap dungeon)
{
List<Room> entranceRooms = dungeon.GetEntranceRooms();
List<EntranceRoom> entranceRooms = dungeon.GetEntranceRooms();
List<Room> roomsToAddRoomsTowards = dungeon.GetNodeRooms();
List<Room> obstructions = dungeon.GetRootRooms();
foreach (Room entranceRoom in entranceRooms)
{
if (entranceRoom.GetAdjacentRooms().All(adjacent => adjacent.TypeOfRoom == RoomType.Entrance))
if (entranceRoom.GetAdjacentRooms().All(adjacent => adjacent is EntranceRoom))
{
Room closestRoom = null;
foreach (RoomSide side in Enum.GetValues(typeof(RoomSide)))
@ -73,7 +73,7 @@ namespace DungeonMapGenerator
dungeon.AddRooms(PlaceRoomsOrganicallyTowardRoom(
entranceRoom,
closestRoom,
RoomType.Normal,
typeof(Room),
dungeon.GetOccupiedPoints(),
dungeon.GetUnoccupiedPoints()));
}
@ -122,7 +122,7 @@ namespace DungeonMapGenerator
if (closestSeenRoom != null)
{
//Place rooms along the line until they are connected
dungeon.AddRooms(PlaceRoomsOrganicallyTowardRoom(room, closestSeenRoom, RoomType.Normal,
dungeon.AddRooms(PlaceRoomsOrganicallyTowardRoom(room, closestSeenRoom, typeof(Room),
dungeon.GetOccupiedPoints(), dungeon.GetUnoccupiedPoints()));
}
}
@ -185,7 +185,7 @@ namespace DungeonMapGenerator
}
// Create room and add it if valid
Room newRoom = CreateAdjacentRoom(RoomType.Normal, unoccupiedPointsOnSide, side, dungeon.GetOccupiedPoints());
Room newRoom = CreateAdjacentRoom(typeof(Room), unoccupiedPointsOnSide, side, dungeon.GetOccupiedPoints());
if (newRoom != null)
{
room.AddAdjacentRoomBySide(newRoom, side);
@ -254,9 +254,9 @@ namespace DungeonMapGenerator
}
}
private Room CreateAdjacentRoom(RoomType type, List<Point> unoccupiedPointsOnSide, RoomSide side, HashSet<Point> occupiedPoints)
private Room CreateAdjacentRoom(Type roomType, List<Point> unoccupiedPointsOnSide, RoomSide side, HashSet<Point> occupiedPoints)
{
int sizeOfNewRoom = GetRoomSizeByType(type);
int sizeOfNewRoom = GetRoomSizeByType(roomType);
Random random = new Random();
// Sort points by their coordinate based on the side of placement
@ -299,7 +299,7 @@ namespace DungeonMapGenerator
break;
}
Room testRoom = new Room(type, sizeOfNewRoom, sizeOfNewRoom, adjustedPoint);
Room testRoom = (Room)Activator.CreateInstance(roomType, sizeOfNewRoom, sizeOfNewRoom, adjustedPoint);
if (!testRoom.GetPointsInRoom().Any(occupiedPoints.Contains))
{
validRooms.Add(testRoom); // First point is the top-left point of the room
@ -343,20 +343,17 @@ namespace DungeonMapGenerator
return true;
}
private int GetRoomSizeByType(RoomType type)
private int GetRoomSizeByType(Type roomType)
{
switch (type)
if (roomType == typeof(EntranceRoom))
{
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;
return SIDE_LENGTH_OF_MONSTER;
}
if (roomType == typeof(MonsterRoom))
{
return SIDE_LENGTH_OF_MONSTER;
}
return SIDE_LENGTH_OF_NORMAL;
}
private Room GenerateOnlyBossRoom(int xLengthOfDungeon, int yLengthOfDungeon, int width, int heigth)
@ -367,7 +364,7 @@ namespace DungeonMapGenerator
Random random = new Random();
int bossX = middleAreaX + random.Next(0, middleAreaX - width);
int bossY = middleAreaY + random.Next(0, middleAreaY - heigth);
return new Room(RoomType.Boss, width, heigth, new Point(bossX, bossY));
return new BossRoom(width, heigth, new Point(bossX, bossY));
}
private enum Side
@ -421,20 +418,20 @@ namespace DungeonMapGenerator
// Add half of points for this entrance line to the top left side
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i,0)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i,0)));
}
// Add the rest of the points for this entrance line to the top right side.
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right - i,0)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right - i,0)));
}
break;
case 1:
int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL,new Point(startOfLine + i, 0)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL,new Point(startOfLine + i, 0)));
}
break;
}
@ -445,20 +442,20 @@ namespace DungeonMapGenerator
// Add points for this entrance line to the top right side
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, i + SIDE_LENGTH_OF_NORMAL)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, i + SIDE_LENGTH_OF_NORMAL)));
}
// Add the rest of the points for this entrance line to the bottom right side.
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, oneRoomFromBottom - i)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, oneRoomFromBottom - i)));
}
break;
case 1:
int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, startOfLine + i)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, startOfLine + i)));
}
break;
}
@ -469,20 +466,20 @@ namespace DungeonMapGenerator
// Add half of points for this entrance line to the bottom left side
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i, bottom)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i, bottom)));
}
// Add the rest of the points for this entrance line to the bottom right side.
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point((xLengthOfDungeon - 1) - i, bottom)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point((xLengthOfDungeon - 1) - i, bottom)));
}
break;
case 1:
int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(startOfLine + i, bottom)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(startOfLine + i, bottom)));
}
break;
}
@ -493,20 +490,20 @@ namespace DungeonMapGenerator
// Add half of points for this entrance line to the top left side
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, i + SIDE_LENGTH_OF_NORMAL)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, i + SIDE_LENGTH_OF_NORMAL)));
}
// Add the rest of the points for this entrance line to the bottom left side.
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, oneRoomFromBottom - i)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, oneRoomFromBottom - i)));
}
break;
case 1:
int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
{
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, startOfLine + i)));
entranceRooms.Add(new EntranceRoom(SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, startOfLine + i)));
}
break;
}
@ -613,7 +610,7 @@ namespace DungeonMapGenerator
return points;
}
private List<Room> PlaceRoomsOrganicallyTowardRoom(Room startingRoom, Room targetRoom, RoomType type,
private List<Room> PlaceRoomsOrganicallyTowardRoom(Room startingRoom, Room targetRoom, Type roomType,
HashSet<Point> occupiedPoints, HashSet<Point> unoccupiedPoints)
{
List<Room> placedRooms = new List<Room>();
@ -631,12 +628,12 @@ namespace DungeonMapGenerator
GetSidesTowardsEndPoint(currentRoom.GetCenterOfRoom(), targetRoom.GetCenterOfRoom());
List<Point> availablePointsOnSide = GetUnoccupiedPointsOnSide(currentRoom, primary, unoccupiedPoints);
newRoom = CreateAdjacentRoom(type, availablePointsOnSide, primary, occupiedPoints);
newRoom = CreateAdjacentRoom(roomType, availablePointsOnSide, primary, occupiedPoints);
// If the primary side doesn't have room for a new room the try secondary
if (newRoom == null)
{
availablePointsOnSide = GetUnoccupiedPointsOnSide(currentRoom, secondary, unoccupiedPoints);
newRoom = CreateAdjacentRoom(type, availablePointsOnSide, secondary, occupiedPoints);
newRoom = CreateAdjacentRoom(roomType, availablePointsOnSide, secondary, occupiedPoints);
}
if (newRoom != null)

View file

@ -13,8 +13,12 @@ namespace DungeonMapGenerator
{
Random random = new Random();
float desiredSuccessChance = .995f;
List<Room> currentRooms = dungeon.GetEntranceRooms();
List<Room> currentRooms = new List<Room>();
foreach (EntranceRoom entranceRoom in dungeon.GetEntranceRooms())
{
currentRooms.Add(entranceRoom);
}
HashSet<Room> seenRooms = new HashSet<Room>(currentRooms);
// Set entrance room locks to 2 - 12
@ -115,6 +119,43 @@ namespace DungeonMapGenerator
}
}
public static void AddExtraLocksToMonsterRooms(List<MonsterRoom> monsterRooms)
{
int maxExtraMonsterRoomLocks = 2;
foreach (MonsterRoom monsterRoom in monsterRooms)
{
int extraLockCounter = 0;
foreach (Room adjacentRoom in monsterRoom.GetAdjacentRooms())
{
if (Lock.VeryHardLocks.All(l => l.GetLock() != adjacentRoom.Lock.GetLock()))
{
if (extraLockCounter < maxExtraMonsterRoomLocks)
{
monsterRoom.ExtraLocks.Add(new Lock(adjacentRoom.Lock.GetLock()));
extraLockCounter++;
}
}
}
}
}
public static void AddExtraLocksToBossRoom(BossRoom bossRoom)
{
int maxExtraBossRooms = 5;
int extraLockCounter = 0;
foreach (Room adjacentRoom in bossRoom.GetAdjacentRooms())
{
if (Lock.VeryHardLocks.All(l => l.GetLock() != adjacentRoom.Lock.GetLock()))
{
if (extraLockCounter < maxExtraBossRooms)
{
bossRoom.ExtraLocks.Add(new Lock(adjacentRoom.Lock.GetLock()));
extraLockCounter++;
}
}
}
}
private static List<Lock> GenerateLocks(List<Lock> pregeneratedLocks, int numLocks, float successChance)
{
List<Lock> locks = new List<Lock>();

View file

@ -13,13 +13,13 @@ namespace DungeonMapGenerator
[JsonProperty("Height")]
public int Height;
[JsonProperty("MonsterRooms")]
private List<Room> _monsterRooms = new List<Room>();
private List<MonsterRoom> _monsterRooms = new List<MonsterRoom>();
[JsonProperty("EntranceRooms")]
private List<Room> _entranceRooms = new List<Room>();
private List<EntranceRoom> _entranceRooms = new List<EntranceRoom>();
[JsonProperty("NormalRooms")]
private List<Room> _normalRooms = new List<Room>();
[JsonProperty("BossRoom")]
private Room _bossRoom;
private BossRoom _bossRoom;
private HashSet<Point> _unoccupiedPoints = new HashSet<Point>();
private HashSet<Point> _occupiedPoints = new HashSet<Point>();
public DungeonMap(){ }
@ -60,22 +60,24 @@ namespace DungeonMapGenerator
public void AddRoom(Room room)
{
switch (room.TypeOfRoom)
if (room is MonsterRoom)
{
case RoomType.Monster:
_monsterRooms.Add(room);
break;
case RoomType.Entrance:
_entranceRooms.Add(room);
break;
case RoomType.Normal:
_normalRooms.Add(room);
break;
case RoomType.Boss:
_bossRoom = room;
break;
default:
return;
if (room is BossRoom)
{
_bossRoom = (BossRoom)room;
}
else
{
_monsterRooms.Add((MonsterRoom)room);
}
}
else if (room is EntranceRoom)
{
_entranceRooms.Add((EntranceRoom)room);
}
else
{
_normalRooms.Add(room);
}
AddPointsToOccupied(room.GetPointsInRoom());
@ -83,37 +85,23 @@ namespace DungeonMapGenerator
public void AddRooms(List<Room> rooms)
{
if (rooms.Count == 0) return;
switch (rooms[0].TypeOfRoom)
foreach (Room room in rooms)
{
case RoomType.Monster:
_monsterRooms.AddRange(rooms);
break;
case RoomType.Entrance:
_entranceRooms.AddRange(rooms);
break;
case RoomType.Normal:
_normalRooms.AddRange(rooms);
break;
default:
return;
AddRoom(room);
}
AddPointsToOccupied(rooms.SelectMany(room => room.GetPointsInRoom()).ToList());
}
public List<Room> GetMonsterRooms()
public List<MonsterRoom> GetMonsterRooms()
{
return _monsterRooms;
}
public Room GetBossRoom()
public BossRoom GetBossRoom()
{
return _bossRoom;
}
public List<Room> GetEntranceRooms()
public List<EntranceRoom> GetEntranceRooms()
{
return _entranceRooms;
}

View file

@ -0,0 +1,11 @@
namespace DungeonMapGenerator
{
public class EntranceRoom : Room
{
public EntranceRoom(int width, int height, Point positionOfTopLeft)
: base(width, height, positionOfTopLeft) // Calls Room's constructor
{
TypeOfRoom = RoomType.Entrance;
}
}
}

View file

@ -8,7 +8,6 @@ namespace DungeonMapGenerator
public class EvenDisperser
{
private List<Room> _samples = new List<Room>(){new Room(
RoomType.Normal,
1,
1,
new Point(1000, 1000))};
@ -36,16 +35,15 @@ namespace DungeonMapGenerator
return availablePoints;
}
public Room GenerateAndPlaceRoom(int xLength, int yLength, RoomType roomType)
public Room GenerateAndPlaceRoom(int xLength, int yLength, Type roomType)
{
int numCandidates = 100; // Increasing improves results but greatly effects performance.
Random rnd = new Random();
Room bestCandidate = new Room(roomType, xLength, yLength, new Point(Int32.MaxValue, Int32.MaxValue));
Room bestCandidate = new Room(xLength, yLength, new Point(Int32.MaxValue, Int32.MaxValue));
int bestDistance = 0;
for (var i = 0; i < numCandidates; i++)
{
var candidate = new Room(
roomType, xLength, yLength, _availablePoints.ToList()[rnd.Next(0, _availablePoints.Count)]);
var candidate = (Room)Activator.CreateInstance(roomType, xLength, yLength, _availablePoints.ToList()[rnd.Next(0, _availablePoints.Count)]);
var distance = candidate.GetDistanceToRoom(FindClosestRoom(_samples, candidate));
if (distance > bestDistance
&& candidate.GetPointsInRoom().All(room => _availablePoints.Contains(room)))

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace DungeonMapGenerator
{
public class MonsterRoom : Room
{
public MonsterRoom(int width, int height, Point positionOfTopLeft)
: base(width, height, positionOfTopLeft) // Calls Room's constructor
{
TypeOfRoom = RoomType.Monster;
}
public List<Lock> ExtraLocks = new List<Lock>();
}
}

View file

@ -32,8 +32,8 @@ namespace DungeonMapGenerator
public class Room
{
private static int _nextId = 1;
public RoomType TypeOfRoom { get; set; }
public RoomType TypeOfRoom { get; protected set; }
public Lock Lock { get; set; }
public int Height { get; set; }
public int Width { get; set; }
@ -51,15 +51,15 @@ namespace DungeonMapGenerator
}
public Room(RoomType roomType, int width, int height, Point positionOfTopLeft)
public Room(int width, int height, Point positionOfTopLeft)
{
TypeOfRoom = RoomType.Normal;
Id = _nextId++;
TypeOfRoom = roomType;
Width = width;
Height = height;
PositionOfTopLeft = positionOfTopLeft;
}
public void AddAdjacentRoom(Room room)
{
_adjacentRooms.Add(room);

View file

@ -29,6 +29,10 @@ namespace DungeonGenerator
GameObject bossRoomGO = PrefabUtility.InstantiatePrefab(bossRoomPrefab, gameObject.transform) as GameObject;
bossRoomGO.transform.position = ConvertToUnityPosition(map.GetBossRoom().GetCenterOfRoom(), map.Width, map.Height);
AddLockToRoomObject(bossRoomGO, map.GetBossRoom().Lock.GetLock());
foreach (DungeonMapGenerator.Lock extraLock in map.GetBossRoom().ExtraLocks)
{
AddLockToRoomObject(bossRoomGO, extraLock.GetLock());
}
_roomIdToGameObject[map.GetBossRoom().Id] = bossRoomGO;
foreach (var monsterRoom in map.GetMonsterRooms())
@ -36,6 +40,10 @@ namespace DungeonGenerator
GameObject monsterRoomGO = PrefabUtility.InstantiatePrefab(monsterRoomPrefab, gameObject.transform) as GameObject;
monsterRoomGO.transform.position = ConvertToUnityPosition(monsterRoom.GetCenterOfRoom(), map.Width, map.Height);
AddLockToRoomObject(monsterRoomGO, monsterRoom.Lock.GetLock());
foreach (DungeonMapGenerator.Lock extraLock in monsterRoom.ExtraLocks)
{
AddLockToRoomObject(monsterRoomGO, extraLock.GetLock());
}
_roomIdToGameObject[monsterRoom.Id] = monsterRoomGO;
}