/// <summary> /// Generate a new randomised level. This is an expensive method and /// should be called infrequently. /// </summary> /// <param name="startingRoomPrefab"> /// A room prefab to use as the starting room. /// </param> /// <param name="parent"> /// The transform of the parent gameobject, the instantiated rooms /// comprising the level will be a child of the given transform. /// </param> /// <param name="depth"> /// The depth of the level to be generated. Depth should be a value /// larger than zero. A larger depth value will result in a larger /// level being generated. /// </param> /// <param name="disableChildRooms"> /// Whether or not child-rooms (any room that is not the starting room) /// should be initially disabled. Normally rooms should only be enabled /// when the player enters them however it is sometimes useful for /// debugging to have all rooms enabled. /// </param> /// <returns> /// Returns the fully instantiated and initialized starting room. All /// rooms in the level are accessible via the starting room through the /// connected doors in each room which form a "level graph" of /// interconnected rooms. /// </returns> public static GameObject GenerateLevel(GameObject startingRoomPrefab, Transform parent, int depth, int?seed = null, bool disableChildRooms = true) { // NOTE: Due to how level generation is implemented, there is // always the small possibility that despite best efforts a // guaranteed room wont be able to find a viable position to spawn // while upholding all of the required constraints. // // To ensure the guaranteed rooms are included in the level, the // level will re-generate itself if it detects that not all the // guaranteed rooms were spawned. // set level generation seed if (!seed.HasValue) { seed = (int)DateTime.Now.Ticks; } UnityEngine.Random.InitState(seed.Value); Log.Info($"Generating level with depth {Log.Cyan(depth)} and seed {Log.Cyan(seed.Value)}", LogCategory.LevelGeneration); const int attempts = 25; for (int i = 0; i < attempts; i++) { RoomGrid grid = new RoomGrid(depth); Vector2Int centre = new Vector2Int(0, 0); GameObject startingRoomInstance = InstanceFactory.InstantiateRoom(startingRoomPrefab, parent, centre); RoomConnectionBehaviour startingRoom = startingRoomInstance.GetComponent <RoomConnectionBehaviour>(); grid.Add(startingRoom); SpawnChildRooms(startingRoom, parent, grid, depth, disableChildRooms); bool levelVerfied = grid.Verify(); if (!levelVerfied) { Log.Warning($"Generated level did not pass verification check. Regenerating... (attempt #{i+1})", LogCategory.LevelGeneration); foreach (Transform childTransform in parent.transform) { GameObject.Destroy(childTransform.gameObject); } continue; } return(startingRoomInstance); } throw new Exception("GenerateLevel failed. This is likely due to an invalid SpawnProbability configuration."); }