/// <summary> /// Creates an instance of the generator. /// </summary> /// <param name="levelDescription">Level description of the level that should be generated.</param> /// <param name="configuration">Configuration of the generator. Can be omitted for reasonable defaults.</param> public GraphBasedGeneratorGrid2D(LevelDescriptionGrid2D <TRoom> levelDescription, GraphBasedGeneratorConfiguration <TRoom> configuration = null) { this.levelDescription = levelDescription; this.levelDescriptionMapped = new LevelDescriptionMapping <TRoom>(levelDescription); this.configuration = configuration ?? new GraphBasedGeneratorConfiguration <TRoom>(); SetupGenerator(); }
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 GraphBasedGeneratorFactory(GraphBasedGeneratorConfiguration <TNode> configuration, bool benchmarkInitialization = false, string name = null) { this.configuration = configuration; this.benchmarkInitialization = benchmarkInitialization; Name = $"{name ?? "New generator"}" + (benchmarkInitialization ? " with init" : ""); }