Dungeon Builder Placing Rooms[4]에 이어서 작성한 코드 내용이다.
/// <summary>
/// Generate random dungeon, returns true if dungeon built, flase is failed
/// </summary>
public bool GenerateDungeon(DungeonLevelSO currentDungeonLevel)
{
roomTemplateList = currentDungeonLevel.roomTemplateList;
// Load the scriptable object room templates into the dictionary
LoadRoomTemplatesIntoDictionary();
dungeonBuildSuccessful = false;
int dungeonBuildAttempts = 0;
while (!dungeonBuildSuccessful && dungeonBuildAttempts < Settings.maxDungeonBuildAttempts)
{
dungeonBuildAttempts++;
// Select a random room node graph from the list
RoomNodeGraphSO roomNodeGraph = SelectRandomRoomNodeGraph(currentDungeonLevel.roomNodeGraphList);
int dungeonRebuildAttemptsForNodeGraph = 0;
dungeonBuildSuccessful = false;
// Loop until dungeon successfully built or more than max attempts for node graph
while (!dungeonBuildSuccessful && dungeonRebuildAttemptsForNodeGraph <= Settings.maxDungeonRebuildAttemptsForRoomGraph)
{
// Clear dungeon room gameobjects and dungeon room dictionary
ClearDungeon();
dungeonRebuildAttemptsForNodeGraph++;
// Attempt To Build A Random Dungeon For The Selected room node graph
dungeonBuildSuccessful = AttemptToBuildRandomDungeon(roomNodeGraph);
}
if (dungeonBuildSuccessful)
{
// Instantiate Room Gameobjects
InstantiateRoomGameobjects();
}
}
return dungeonBuildSuccessful;
}
/// <summary>
/// Attempt to place the room node in the dungeon - if room can be placed return the room, else return null
/// </summary>
private bool CanPlaceRoomWithNoOverlaps(RoomNodeSO roomNode, Room parentRoom)
{
// initialise and assume overlap until proven otherwise.
bool roomOverlaps = true;
// Do while Room Overlaps - try to place against all available doorways of the parent until
// the room is successfully placed without overlap.
while (roomOverlaps)
{
// Select random unconnected available doorway for Parent
List<Doorway> unconnectedAbailableParentDoorways = GetUnconnectedAvailableDoorways(parentRoom.doorWayList).ToList();
if (unconnectedAbailableParentDoorways.Count == 0)
{
// If no more doorways to try then overlap failure.
return false; // room overlaps
}
Doorway doorwayParent = unconnectedAbailableParentDoorways[UnityEngine.Random.Range(0, unconnectedAbailableParentDoorways.Count)];
// Get a random room template for room node that is consistent with the parent door orientation
RoomTemplateSO roomtemplate = GetRandomTemplateForRoomConsistentWithParent(roomNode, doorwayParent);
// Create a room
Room room = CreateRoomFromRoomTemplate(roomtemplate, roomNode);
// Plcae the room - returns true if the room doesn't overlap
if (PlaceTheRoom(parentRoom, doorwayParent, room))
{
// If room doesn't overlap then set to false to exit while loop
roomOverlaps = false;
// Mark room as positioned
room.isPositioned = true;
// Add room to dictionary
dungeonBuilderRoomDictionary.Add(room.id, room);
}
else
{
roomOverlaps = true;
}
}
return true; // no room overlaps
}
/// <summary>
/// Place the room - returns true if the room doesn't overlap, false otherwise
/// </summary>
private bool PlaceTheRoom(Room parentRoom, Doorway doorwayParent, Room room)
{
// Get current room doorway position
Doorway doorway = GetOppositeDoorway(doorwayParent, room.doorWayList);
// Returns if no doorway in room opposite to parent doorway
if (doorway == null)
{
// Just mark the parnet doorway as unavailable so we don't try and connect it again
doorwayParent.isUnavailable = true;
return false;
}
// Calculate 'world' grid parent doorway position
Vector2Int parentDoorwayPosition = parentRoom.lowerBounds + doorwayParent.position - parentRoom.templateLowerBounds;
Vector2Int adjustment = Vector2Int.zero;
// Calculate adjustment position offset based on room doorway position that we are trying to connect
// (e.g. if this doorway is west then we need to add (1,0) to the east parent doorway)
switch(doorway.orientation)
{
case Orientation.north:
adjustment = new Vector2Int(0, -1);
break;
case Orientation.east:
adjustment = new Vector2Int(-1, 0);
break;
case Orientation.south:
adjustment = new Vector2Int(0, 1);
break;
case Orientation.west:
adjustment = new Vector2Int(1, 0);
break;
case Orientation.none:
break;
default:
break;
}
// Calculate room lower bounds and upper bounds based on positioning to aligh with parent doorway
room.lowerBounds = parentDoorwayPosition + adjustment + room.templateLowerBounds - doorway.position;
room.upperBounds = room.lowerBounds + room.templateUpperBounds - room.templateLowerBounds;
Room overlappingRoom = CheckForRoomOverlap(room);
if (overlappingRoom == null)
{
// mark doorway as connected & unavailable
doorwayParent.isConnected = true;
doorwayParent.isUnavailable = true;
doorway.isConnected = true;
doorway.isUnavailable = true;
// return true to show rooms have been connected with no overlap
return true;
}
else
{
// Just mark the parent doorway as unavailable so we don't try and connect it again
doorwayParent.isUnavailable = true;
return false;
}
}
/// <summary>
/// Get a room template by room tmeplate ID, returns null if ID doesn't exist
/// </summary>
public RoomTemplateSO GetRoomTemplate(string roomTemplateID)
{
if (roomTemplateDictionary.TryGetValue(roomTemplateID, out RoomTemplateSO roomTemplate))
{
return roomTemplate;
}
else
{
return null;
}
}
/// <summary>
/// Get room by roomID, if no room exists with that ID return null
/// </summary>
public Room GetRoomByRoomID(string roomID)
{
if (dungeonBuilderRoomDictionary.TryGetValue(roomID, out Room room))
{
return room;
}
else
{
return null;
}
}
이제 게임 매니저에서 던전 빌더를 사용해을 던전을 생성하는 코드를 추가해준다.
private void PlayDungeonLevel(int dungeonLevelListIndex)
{
// Build dungeon for level
bool dungeonBuiltSuccessfully = DungeonBuilder.Instance.GenerateDungeon(dungeonLevelList[dungeonLevelListIndex]);
if (!dungeonBuiltSuccessfully)
{
Debug.LogError("Couldn't build dungeon from specified rooms and node graphs");
}
}