[Unity] Dungeon Gunner (30) - Dungeon Builder Placing Rooms[5]

suhan0304·2024년 3월 8일
0

유니티 - Dungeon Gunner

목록 보기
30/30
post-thumbnail

Dungeon Builder Placing Rooms[4]에 이어서 작성한 코드 내용이다.

DungeonBuilder.cs

/// <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;
    }
}

이제 게임 매니저에서 던전 빌더를 사용해을 던전을 생성하는 코드를 추가해준다.

GameManager.cs

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");
    }
}
profile
Be Honest, Be Harder, Be Stronger

0개의 댓글

관련 채용 정보