/// <summary> /// Go through all of the generated rooms that match the parameter and add a small room to them so they don't lead to nowhere. /// </summary> /// <param name="typeToCloseOff">The room type to look for.</param> private void CloseOffPaths() { if (closeOffParent == null) { closeOffParent = new GameObject("Path closing rooms - "); closeOffParent.transform.parent = emptyGameObject.transform; } foreach (var roomType in RoomTypesToCloseOff) { foreach (GameObject go in GameObject.FindGameObjectsWithTag("RoomInstance")) { currRoom = go.GetComponent <Room>(); if (currRoom.GetRoomType().Equals(roomType)) { foreach (var exit in currRoom.GetRoomExits()) { if (exit.GetConnectionStatus().Equals(RoomExit.ExitStatus.Connected)) //if exit is connected, skip it { continue; } Room newRoom = (Room)Instantiate(rnd.GetRandom(RoomsToUseToClosePath)); newRoom.SetupCollider(); currExit = exit.GetExit(); var newRoomExits = newRoom.GetExits(); var exitToMatch = rnd.GetRandom(newRoomExits); newRoom.tag = "RoomInstance"; newRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances"); currExit.MatchExits(exitToMatch); if (collision.DetectCollision(newRoom)) { MarkRoomForDestruction(newRoom); currRoom.CloseCollidingExit(currExit); // cannot add room here so close the exit continue; } currRoom.ConnectExits(currExit, exitToMatch); newRoom.ConnectExits(exitToMatch, currExit); newRoom.transform.SetParent(closeOffParent.transform); } } } } closeOffParent.name += closeOffParent.GetComponentsInChildren <Room>().Count(); }
/// <summary> /// Try and add the specified 'ExitRoom' to one of the open exits. /// </summary> private void SetupExitRoom() { if (ExitRoom == null) //no exit room prefab was provided { hasExitRoomBeenSuccessfullyAdded = true; if (_DEBUG_MODE) { FileLogger.Log(">No Exit Room Specified. Terminating SetupExitRoom function.<"); } return; } if (_DEBUG_MODE) { FileLogger.Log(">Starting SetupExitRoom..."); } if ((supportFunctions.GetAllRoomsWithActiveExits().Count < 3 || supportFunctions.GetRoomsWithPossibleExits().Count < 5) && expandPathBy > 1) { //Make sure there are enough exits before spawning an exit room as it would certainly be a dead end if (_DEBUG_MODE) { FileLogger.Log("Postponing SetupExitRoom due to possibility of creating a dead-end."); } hasExitRoomBeenSuccessfullyAdded = false; return; } //Select a room to connect the exit to. int excludeRooms = 0; //counter to keep track of how many rooms we've backtracked so we do not check the same ones again currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(ExitRoom.GetRoomType()), ref excludeRooms);; //find a room to add the exit to(needs to meet one of the connection rules criteria) if (currRoom.Equals(InitialRoom)) { if (_DEBUG_MODE) { FileLogger.Log(">Attempted to connect exit room to initial room. Returning and awaiting more available rooms.<"); } hasExitRoomBeenSuccessfullyAdded = true; return; } if (currRoom == null) { //force stop the execution of the function if a suitable room wasn't found if (_DEBUG_MODE) { FileLogger.Log(">!< Could not add exit room to any of the rooms. Terminating SetupExitRoom function! >!<"); } hasExitRoomBeenSuccessfullyAdded = false; return; } Room exitRoom = (Room)Instantiate(ExitRoom); exitRoom.SetupCollider(); exitRoom.tag = "RoomInstance"; exitRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances"); var exitRoomExits = exitRoom.GetExits(); //get exits for the new room RoomConnector exitToMatch = null; bool collisionDetected = false; do { if (currRoom == null || currRoom.Equals(InitialRoom)) { //force stop the execution of the function if a suitable room wasn't found if (_DEBUG_MODE) { FileLogger.Log(">!< Could not add exit room to any of the rooms. Terminating SetupExitRoom function! >!<"); } MarkRoomForDestruction(exitRoom); hasExitRoomBeenSuccessfullyAdded = false; return; } currExit = rnd.GetRandom(currRoom.GetActiveExits()); if (collisionDetected) { currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(exitRoom.GetRoomType()), ref excludeRooms); //find a room to add the exit to excludeRooms++; //if this room cannot be connected to the one that was just found, then ignore it next time as we don't close the exit / prevent inf loop continue; } exitToMatch = rnd.GetRandom(exitRoomExits); //select default exit or choose one at random currExit.MatchExits(exitToMatch); //rotate the new room so it connects correctly }while (collisionDetected = collision.DetectCollision(exitRoom)); //deal with the collision currRoom.ConnectExits(currExit, exitToMatch); exitRoom.ConnectExits(exitToMatch, currExit); exitRoom.transform.parent = emptyGameObject.transform; exitRoom.name = "ExitRoom"; hasExitRoomBeenSuccessfullyAdded = true; if (markEndRoom) { exitRoom.GetComponent <Renderer>().material.color = Color.red; } if (_DEBUG_MODE) { FileLogger.Log("<SetupExitRoom was successful."); } }
/// <summary> /// Instantiates a room and adds it to the level. Based on the passed in argument it will either /// add a room to the main path of the level(true) or to a random room(false). /// Returns 1 if function was successful. 0 if collision occured. -1 if there are no more active exits. /// </summary> /// <param name="onMainPath">True: generate the main path. False: expand the level</param> /// <returns>-1 if dead end has been found; 0 if a collision has occured; 1 if room was generated successfully.</returns> private int GenerateRoom(bool onMainPath = true) { if (supportFunctions.GetTotalNumberOfActiveExits() == 0) { return(-1); } //try and add the exit room if the previous attempt was unsuccessful if (!onMainPath && supportFunctions.GetAllRoomsWithActiveExits().Count > 3 && !hasExitRoomBeenSuccessfullyAdded && CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0) {//dont generate during main path generation, but also make sure the function is not trying to add another room at this time if (_DEBUG_MODE) { FileLogger.Log(">!< Trying SetupExitRoom during Expansion >!<"); } SetupExitRoom(); } //if expanding level( NOT onMainPath) and not re-trying due to collision ( curr unsuccessful attempts is 0) if (!onMainPath && CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0) { currRoom = rnd.GetRandom(supportFunctions.GetAllRoomsWithActiveExits().ToArray()); //pick a random open exit from the list to use } //if we're not trying to replace a room due to collision, get a new random exit if (CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0) { currExit = rnd.GetRandom(currRoom.GetActiveExits()); //get the exit's room component } var possibleRoomConnections = GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(currExit.transform.parent.GetComponent <Room>().GetRoomType()); var pickRandomRoomType = rnd.GetRandom(possibleRoomConnections); //pick randomly a room type which can be connected to the current one's exit var newRoomPrefab = rnd.GetRandomByRoomType(Rooms, pickRandomRoomType); //find item with specific room type if (onMainPath) { //avoid dead end if the new room will have only 1 exit which will be closed upon conneciton with the current room, or if there are few exits left if (newRoomPrefab.GetExits().Length <= 1 || supportFunctions.GetTotalNumberOfActiveExits() <= 3) { supportFunctions.AvoidDeadEnd(ref newRoomPrefab, possibleRoomConnections); } } else { if (supportFunctions.GetTotalNumberOfActiveExits() <= 5) { supportFunctions.AvoidDeadEnd(ref newRoomPrefab, possibleRoomConnections); } } var newRoom = (Room)Instantiate(newRoomPrefab); if (onMainPath) { newRoom.name += "SP" + uniqueID; } else { newRoom.name += "EXP" + uniqueID; } newRoom.SetupCollider(); newRoom.tag = "RoomInstance"; newRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances"); var newRoomExits = newRoom.GetExits(); //get exits for the new room var exitToMatch = rnd.GetRandom(newRoomExits); //select default exit or choose one at random currExit.MatchExits(exitToMatch); //rotate the new room so it connects correctly if (collision.DetectCollision(newRoom)) //deal with the collision { MarkRoomForDestruction(newRoom); CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS++; if (CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS >= MAX_UNSUCCESSFUL_ROOM_REPLACEMENT_ATTEMPTS) //close off exit and backtrack { //close off exit only if there are other exits still open - otherwise it would lead to a complete dead end CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0; currRoom.CloseCollidingExit(currExit); //find a new room with active exits. if (onMainPath) { currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(); } //else case will be executed next time the function is called as currRoom will be randomly picked if not onMainPath } return(0); } //reset attempts and connect the rooms CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0; currRoom.ConnectExits(currExit, exitToMatch); newRoom.ConnectExits(exitToMatch, currExit); if (allowLoops) { newRoom.ConnectActiveExitsInProximity(); } if (onMainPath) { newRoom.transform.SetParent(spParent.transform); if (highlightMainPath) { // "highlight" the main path currRoom.GetComponent <Renderer>().material.color = Color.green; newRoom.GetComponent <Renderer>().material.color = Color.green; } //if the new room doesn't have an exit, don't move into it if (newRoom.GetActiveExits().Length >= 1) { currRoom = newRoom; } if (currRoom.GetActiveExits().Length == 0) { currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(); CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0; } } else { newRoom.transform.SetParent(expParent.transform); } uniqueID++; return(1); }