public virtual void Initialize() { // Remove all children game objects foreach (var child in transform.Cast <Transform>().ToList()) { PostProcessUtils.Destroy(child.gameObject); } // Add room template component if (gameObject.GetComponent <RoomTemplateSettings>() == null) { gameObject.AddComponent <RoomTemplateSettings>(); } // Create tilemaps root var tilemapsRoot = new GameObject(GeneratorConstants.TilemapsRootName); tilemapsRoot.transform.parent = gameObject.transform; // Init tilemaps InitializeTilemaps(tilemapsRoot); // Fix positions tilemapsRoot.transform.localPosition = Vector3.zero; transform.localPosition = Vector3.zero; // Add doors InitializeDoors(); }
public void RemoveOutlineOverride() { if (!HasOutlineOverride()) { return; } var tilemapsRoot = RoomTemplateUtils.GetTilemapsRoot(gameObject); var outlineOverride = tilemapsRoot.transform.Find(GeneratorConstants.OutlineOverrideLayerName).gameObject; PostProcessUtils.Destroy(outlineOverride); }
// TODO: where to put this? public static void Destroy(Object gameObject) { PostProcessUtils.Destroy(gameObject); }
public override IEnumerator Process() { var levelDescription = Payload.LevelDescription; if (config.Timeout <= 0) { throw new ArgumentException($"{nameof(config.Timeout)} must be greater than 0", nameof(config.Timeout)); } var rootGameObject = config.RootGameObject; // If the root game objects was not set in the config, we do the following: // 1. Check if there already exists a game objects with a name reserved for the generated level // 2. Otherwise, we create a new empty game object if (rootGameObject == null) { rootGameObject = GameObject.Find("Generated Level"); if (rootGameObject == null) { rootGameObject = new GameObject("Generated Level"); } } // We delete all the children from the root game object - we do not want to combine levels from different runs of the algorithm foreach (var child in rootGameObject.transform.Cast <Transform>().ToList()) { child.transform.parent = null; PostProcessUtils.Destroy(child.gameObject); } // The LevelDescription class must be converted to MapDescription var levelDescriptionGrid2D = levelDescription.GetLevelDescription(); levelDescriptionGrid2D.MinimumRoomDistance = 1; levelDescriptionGrid2D.RoomTemplateRepeatModeOverride = GeneratorUtils.GetRepeatMode(config.RepeatModeOverride); var configuration = new GraphBasedGeneratorConfiguration <RoomBase>() { EarlyStopIfTimeExceeded = TimeSpan.FromMilliseconds(config.Timeout), }; // We create the instance of the dungeon generator and inject the correct Random instance var generator = new GraphBasedGeneratorGrid2D <RoomBase>(levelDescriptionGrid2D, configuration); generator.InjectRandomGenerator(Payload.Random); // Run the generator in a different class so that the computation is not blocking LayoutGrid2D <RoomBase> layout = null; var task = Task.Run(() => layout = generator.GenerateLayout()); while (!task.IsCompleted) { yield return(null); } // Throw an exception when a timeout is reached // TODO: this should be our own exception and not a generic exception if (layout == null) { if (task.Exception != null) { if (task.Exception.InnerException != null) { throw task.Exception.InnerException; } throw task.Exception; } else { throw new TimeoutException(); } } // Transform the level to its Unity representation var generatedLevel = GeneratorUtils.TransformLayout(layout, levelDescription, rootGameObject); var stats = new GeneratorStats() { Iterations = generator.IterationsCount, TimeTotal = generator.TimeTotal, }; Debug.Log($"Layout generated in {stats.TimeTotal / 1000f:F} seconds"); Debug.Log($"{stats.Iterations} iterations needed, {stats.Iterations / (stats.TimeTotal / 1000d):0} iterations per second"); ((IGraphBasedGeneratorPayload)Payload).GeneratedLevel = generatedLevel; Payload.GeneratorStats = stats; yield return(null); }
public static GeneratedLevel TransformLayout(LayoutGrid2D <RoomBase> layout, LevelDescription levelDescription, GameObject rootGameObject) { // var layoutCenter = GetLayoutCenter(layout); var prefabToRoomTemplateMapping = levelDescription.GetPrefabToRoomTemplateMapping(); var corridorToConnectionMapping = levelDescription.GetCorridorToConnectionMapping(); // Prepare an object to hold instantiated room templates var roomTemplateInstancesRoot = new GameObject(GeneratorConstants.RoomsRootName); roomTemplateInstancesRoot.transform.parent = rootGameObject.transform; // Initialize rooms var layoutData = new Dictionary <RoomBase, RoomInstance>(); var layoutRooms = layout.Rooms.ToDictionary(x => x.Room, x => x); foreach (var layoutRoom in layoutRooms.Values) { var roomTemplatePrefab = prefabToRoomTemplateMapping.GetByValue(layoutRoom.RoomTemplate); // Instantiate room template var roomTemplateInstance = Object.Instantiate(roomTemplatePrefab); roomTemplateInstance.transform.SetParent(roomTemplateInstancesRoot.transform); roomTemplateInstance.name = $"{layoutRoom.Room.GetDisplayName()} - {roomTemplatePrefab.name}"; // Compute correct room position var position = layoutRoom.Position.ToUnityIntVector3(); roomTemplateInstance.transform.position = position; // Correct the position based on the grid // This is important when there is some cell spacing or when the level is isometric var tilemapsHolder = roomTemplateInstance.transform.Find(GeneratorConstants.TilemapsRootName).gameObject; if (tilemapsHolder != null) { var grid = tilemapsHolder.GetComponent <Grid>(); roomTemplateInstance.transform.position = grid.CellToLocal(position); } // Compute outline polygon var polygon = new Polygon2D(layoutRoom.Outline + layoutRoom.Position); var connection = layoutRoom.IsCorridor ? corridorToConnectionMapping[layoutRoom.Room] : null; var roomInstance = new RoomInstance(layoutRoom.Room, layoutRoom.IsCorridor, connection, roomTemplatePrefab, roomTemplateInstance, position, polygon); // Add room info to the GameObject var roomInfo = roomTemplateInstance.GetComponent <RoomInfo>(); if (roomInfo != null) { PostProcessUtils.Destroy(roomInfo); } roomInfo = roomTemplateInstance.AddComponent <RoomInfo>(); roomInfo.RoomInstance = roomInstance; layoutData.Add(layoutRoom.Room, roomInstance); } foreach (var roomInstance in layoutData.Values) { roomInstance.SetDoors(TransformDoorInfo(layoutRooms[roomInstance.Room].Doors, layoutData)); } // Add level info var levelInfo = rootGameObject.GetComponent <LevelInfo>(); if (levelInfo != null) { PostProcessUtils.Destroy(levelInfo); } levelInfo = rootGameObject.AddComponent <LevelInfo>(); levelInfo.RoomInstances = layoutData.Values.ToList(); return(new GeneratedLevel(layoutData, layout, rootGameObject)); }