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); }
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--; } }
internal PrototypeDungeon(RoomPrototype firstRoom, DungeonStructure structure) { Structure = structure; _firstRoom = firstRoom; }