public PrototypeDungeon BuildPrototype()
        {
            InitVirtualSpace();

            DungeonNode firstElement     = _loadedStructure.StartElement;
            var         firstRoom        = GetRandomRoom(firstElement);
            var         firstRoomWrapper = new RoomPrototype(
                firstElement,
                firstRoom,
                Vector3.zero,
                Quaternion.identity);

            firstRoomWrapper.ConnectToParent(null, null);

            if (!TryAddRoomToVirtualSpace(firstRoomWrapper, null))
            {
                throw new Exception("Could not place first element!");
            }

            TryCreateDungeonStructure(firstRoomWrapper);

            firstRoomWrapper.ActualGraphElement.MetaData.AddTag("ROOT");
            firstRoomWrapper.ActualGraphElement.TraverseDepthFirst().ForEach(n => n.MetaData.AddTag(MAIN_TAG));

            CreateBranches(firstRoomWrapper);

            CloseOpenConnections(firstRoomWrapper);

            return(new PrototypeDungeon(firstRoomWrapper, _loadedStructure));
        }
        private List <RoomPrototypeConnection> CollectOpenConnections(RoomPrototype roomPrototype)
        {
            List <RoomPrototypeConnection> result = new List <RoomPrototypeConnection>();

            CollectOpenConnectionsRecursively(roomPrototype, result);
            return(result);
        }
        private IEnumerable <RoomPrototype> GetPossibleRoomsForConnection(RoomPrototypeConnection baseConnection, DungeonNode nextStructureElement)
        {
            var baseRoom = baseConnection.ParentRoomPrototype;

            foreach (var newRoom in GetRandomOrderedRooms(nextStructureElement))
            {
                IEnumerable <RoomConnector> possibleNextConnections = newRoom
                                                                      .GetConnections()
                                                                      .Where(x => x.size.Equals(baseConnection.ParentConnection.size) && x.type == baseConnection.ParentConnection.type)
                                                                      .ToList().Shuffle(_random);

                foreach (var nextRoomConnection in possibleNextConnections)
                {
                    var nextRoomConnectionTransform = nextRoomConnection.transform;
                    var selectedConnectionTransform = baseConnection.ParentConnection.transform;

                    GetNewRoomPosAndRot(baseRoom.GlobalPosition, baseRoom.Rotation, selectedConnectionTransform, nextRoomConnectionTransform, out var newRoomPosition, out var rotationDiff);

                    var nextRoomWrapper = new RoomPrototype(nextStructureElement, newRoom, newRoomPosition, rotationDiff);

                    if (!TryAddRoomToVirtualSpace(nextRoomWrapper, baseRoom))
                    {
                        continue;
                    }

                    nextRoomWrapper.ConnectToParent(nextRoomConnection, baseConnection);

                    yield return(nextRoomWrapper);
                }
            }
        }
 void CloseOpenConnections(RoomPrototype roomPrototype)
 {
     foreach (var roomPrototypeConnection in CollectOpenConnections(roomPrototype))
     {
         roomPrototypeConnection.Close();
     }
 }
        private void RemoveRoomAndChildrenRecur(RoomPrototype roomToDelete)
        {
            _virtualSpace.Remove(roomToDelete);
            foreach (var childRoom in roomToDelete.ChildRoomConnections.Where(x => x.ChildRoomPrototype != null).Select(x => x.ChildRoomPrototype))
            {
                RemoveRoomAndChildrenRecur(childRoom);
            }
#if DEBUG_LOG
            Debug.LogWarning($"Removed room {roomToDelete.RoomResource.name}");
#endif
        }
 private static void CollectOpenConnectionsRecursively(RoomPrototype roomPrototype, List <RoomPrototypeConnection> resultCollector)
 {
     foreach (var childRoomConnection in roomPrototype.ChildRoomConnections)
     {
         if (childRoomConnection.State == PrototypeConnectionState.FREE)
         {
             resultCollector.Add(childRoomConnection);
         }
         else if (childRoomConnection.State == PrototypeConnectionState.CONNECTED)
         {
             CollectOpenConnectionsRecursively(childRoomConnection.ChildRoomPrototype, resultCollector);
         }
         else
         {
             throw new Exception("This should not happen");
         }
     }
 }
        private void TryCreateDungeonStructure(RoomPrototype firstRoomWrapper)
        {
            uint i = _retryNum;

            do
            {
                try
                {
                    if (BuildPrototypeRoomRecur(firstRoomWrapper))
                    {
                        return;
                    }

                    Debug.LogWarning($"Dungeon building failed with seed {_seed}!");
                }
                catch (MaxStepsReachedException e)
                {
                    Debug.LogWarning(e.Message);
                }

                if (i == 0)
                {
                    break;
                }

                firstRoomWrapper.ChildRoomConnections.Where(x => x.ChildRoomPrototype != null).ForEach(connectionToRemove =>
                {
                    RemoveRoomAndChildrenRecur(connectionToRemove.ChildRoomPrototype);
                    connectionToRemove.ClearChild();
                });
                _seed  += 37 * (1 + _seed);
                _random = new Random(_seed);
                _stepBackCounter.ResetMain();
                Debug.Log($"Retrying with seed {_seed}");

                i--;
            } while (i > 0);

            throw new Exception("Dungeon building failed!");
        }
        private bool TryAddRoomToVirtualSpace(RoomPrototype room, RoomPrototype parentRoom)
        {
            var bounds = room.GetRotatedBounds();

            bounds.extents += new Vector3(_marginHalf, _marginHalf, _marginHalf);

            List <RoomPrototype> collidingWith = new List <RoomPrototype>();

            _virtualSpace.GetColliding(collidingWith, bounds);
            if (_marginHalf <= 0.01)
            {
                if (collidingWith.Count > 1 || collidingWith.Count == 1 && collidingWith[0] != parentRoom)
                {
                    return(false);
                }
            }
            else
            {
                if (collidingWith.Count > 2)
                {
                    return(false);
                }

                //trying without margins
                bounds = room.GetRotatedBounds();
                collidingWith.Clear();
                _virtualSpace.GetColliding(collidingWith, bounds);
                if (collidingWith.Count > 1 || collidingWith.Count == 1 && collidingWith[0] != parentRoom)
                {
                    return(false);
                }
            }

            _virtualSpace.Add(room, bounds);

            return(true);
        }
示例#9
0
        private static Room BuildDungeonInUnitySpaceRecur(RoomPrototype actualElement, Transform parent)
        {
            var instantiatedRoom = Object.Instantiate(actualElement.RoomResource, actualElement.GlobalPosition, actualElement.Rotation, parent);

            actualElement.ActualGraphElement.Room = instantiatedRoom;
            instantiatedRoom.DungeonStructureNode = actualElement.ActualGraphElement;

            foreach (var prototypeConnection in actualElement.ChildRoomConnections)
            {
                var parentConn = instantiatedRoom.GetConnections().Single(c =>
                                                                          c.name == prototypeConnection.ParentConnection.name &&
                                                                          c.transform.localPosition == prototypeConnection.ParentConnection.transform.localPosition);

                if (prototypeConnection.State == PrototypeConnectionState.CONNECTED)
                {
                    var nextRoom  = BuildDungeonInUnitySpaceRecur(prototypeConnection.ChildRoomPrototype, parent);
                    var childConn = nextRoom.GetConnections().Single(c => c.name == prototypeConnection.ChildConnection.name &&
                                                                     c.transform.localPosition == prototypeConnection.ChildConnection.transform.localPosition);
                    RoomConnector.Connect(parentConn, childConn);

                    CreateOpenReplacement(parentConn);
                    CreateOpenReplacement(childConn);
                }
                else if (prototypeConnection.State == PrototypeConnectionState.CLOSED)
                {
                    parentConn.Close();
                    CreateClosedReplacement(parentConn);
                }
                else
                {
                    throw new Exception("No other state should be possible");
                }
            }

            return(instantiatedRoom);
        }
        private bool BuildPrototypeRoomRecur(RoomPrototype room)
        {
#if TAURUS_DEBUG_LOG
            Debug.Log($"Room {room.RoomResource} is built");
#endif
            DungeonNode actualGraphElement = room.ActualGraphElement;

            if (actualGraphElement.IsEndNode)
            {
                return(true);
            }

            var subElements = actualGraphElement.SubElements.Where(sub => GetGenMetaData(sub.MetaData).NodeRequired).ToList();

            if (room.ChildRoomConnections.Count < actualGraphElement.ChildNodes.Count())
            {
                throw new Exception($"Room {room.RoomResource.name} has {room.ChildRoomConnections.Count} connections, yet the graph element {actualGraphElement.Style} requires {actualGraphElement.ChildNodes.Count()}");
            }

            for (int connectionsToMake = subElements.Count; connectionsToMake > 0; connectionsToMake--)
            {
                IList <RoomPrototypeConnection> availableConnections = room.ChildRoomConnections
                                                                       .Where(x => x.State == PrototypeConnectionState.FREE)
                                                                       .ToList()
                                                                       .Shuffle(_random);

                DungeonNode nextStructureElement = subElements[connectionsToMake - 1];

                bool failed = availableConnections.Count < connectionsToMake;
                RoomPrototypeConnection successfulConnection = null;
                if (!failed)
                {
                    foreach (var selectedConnection in availableConnections)
                    {
                        if (GetPossibleRoomsForConnection(selectedConnection, nextStructureElement).Any(BuildPrototypeRoomRecur))
                        {
                            successfulConnection = selectedConnection;
                            break;
                        }
                    }

                    if (successfulConnection == null)
                    {
                        failed = true;
                    }
                }

                // building cannot be successful
                if (failed)
                {
#if TAURUS_DEBUG_LOG
                    Debug.LogWarning($"Failed to make room {room} of element {actualGraphElement.Style}");
#endif
                    RemoveRoomAndChildrenRecur(room);
                    room.ParentRoomConnection?.ClearChild();
                    _stepBackCounter.StepBack();
                    return(false);
                }
                else
                {
                    availableConnections.Remove(successfulConnection);
                }
            }

            return(true);
        }
        private void CreateBranches(RoomPrototype firstRoomWrapper)
        {
            var branchDataWrapper = _loadedStructure.NodeMetaData.BranchDataWrapper;

            if (branchDataWrapper == null)
            {
                return;
            }

            var branchPrototypeNames = branchDataWrapper.BranchPrototypeNames;
            var openConnections      = new Stack <RoomPrototypeConnection>(CollectOpenConnections(firstRoomWrapper).Shuffle(_random));

            uint remainingBranchNum;

            if (branchDataWrapper.BranchCount.HasValue)
            {
                remainingBranchNum = branchDataWrapper.BranchCount.Value;
            }
            else if (branchDataWrapper.BranchPercentage.HasValue)
            {
                remainingBranchNum = (uint)(branchDataWrapper.BranchPercentage.Value * openConnections.Count / 100);
            }
            else
            {
                return;
            }

            int extremeCntr      = 100;
            var embeddedDungeons = new ReadOnlyDictionary <string, AbstractDungeonStructure>(_loadedStructure.AbstractStructure.EmbeddedDungeons);

            while (openConnections.Count > 0 && remainingBranchNum > 0 && extremeCntr > 0)
            {
                var connection = openConnections.Pop();
                foreach (var selectedBranchType in branchPrototypeNames.Shuffle(_random))
                {
                    AbstractDungeonStructure embeddedBranchDungeon = _loadedStructure.AbstractStructure.EmbeddedDungeons[selectedBranchType];
                    DungeonNode concretizedDungeonBranch           = DungeonStructureConcretizer.ConcretizeDungeonTree(
                        embeddedBranchDungeon.StartElement,
                        _random,
                        embeddedDungeons);

                    _stepBackCounter.ResetBranch();

                    try
                    {
                        if (GetPossibleRoomsForConnection(connection, concretizedDungeonBranch).Any(BuildPrototypeRoomRecur))
                        {
                            remainingBranchNum--;
                            connection.ParentRoomPrototype.ActualGraphElement.AddSubElement(concretizedDungeonBranch);
                            concretizedDungeonBranch.TraverseDepthFirst().ForEach(n => n.MetaData.AddTag(BRANCH_TAG));
                            break;
                        }
                    }
                    catch (MaxStepsReachedException e)
                    {
                        Debug.LogWarning(e.Message);
                    }
                }

                extremeCntr--;
            }
        }
示例#12
0
 internal PrototypeDungeon(RoomPrototype firstRoom, DungeonStructure structure)
 {
     Structure  = structure;
     _firstRoom = firstRoom;
 }