Example #1
0
        public virtual void Initialize()
        {
            // Remove all children game objects
            foreach (var child in transform.Cast <Transform>().ToList())
            {
                PostProcessUtilsGrid2D.Destroy(child.gameObject);
            }

            // Add room template component
            if (gameObject.GetComponent <RoomTemplateSettingsGrid2D>() == null)
            {
                gameObject.AddComponent <RoomTemplateSettingsGrid2D>();
            }

            // Create tilemaps root
            var tilemapsRoot = new GameObject(GeneratorConstantsGrid2D.TilemapsRootName);

            tilemapsRoot.transform.parent = gameObject.transform;

            // Init tilemaps
            InitializeTilemaps(tilemapsRoot);

            // Fix positions
            tilemapsRoot.transform.localPosition = Vector3.zero;
            transform.localPosition = Vector3.zero;

            // Add doors
            InitializeDoors();
        }
 /// <summary>
 /// Disables colliders of individual room template tilemaps in the generated level.
 /// The goal is to try to keep triggers functioning.
 /// </summary>
 /// <param name="level"></param>
 public static void DisableRoomTemplatesColliders(GeneratedLevel level)
 {
     // Iterate through all the rooms
     foreach (var roomInstance in level.RoomInstances)
     {
         var roomTemplateInstance = roomInstance.RoomTemplateInstance;
         PostProcessUtilsGrid2D.DisableRoomTemplateColliders(roomTemplateInstance);
     }
 }
        public void RemoveOutlineOverride()
        {
            if (!HasOutlineOverride())
            {
                return;
            }

            var tilemapsRoot    = RoomTemplateUtilsGrid2D.GetTilemapsRoot(gameObject);
            var outlineOverride = tilemapsRoot.transform.Find(GeneratorConstantsGrid2D.OutlineOverrideLayerName).gameObject;

            PostProcessUtilsGrid2D.Destroy(outlineOverride);
        }
        private void RegisterCallbacks(PriorityCallbacks <DungeonGeneratorPostProcessCallback> callbacks)
        {
            if (config.InitializeSharedTilemaps)
            {
                callbacks.RegisterCallback(PostProcessPrioritiesGrid2D.InitializeSharedTilemaps, (level, _) =>
                {
                    PostProcessUtilsGrid2D.InitializeSharedTilemaps(level, config.TilemapLayersStructure, defaultTilemapLayersHandlerFactory(), config.TilemapLayersHandler, config.TilemapLayersExample);
                    PostProcessUtilsGrid2D.SetTilemapsMaterial(level, config.TilemapMaterial);
                });
            }

            if (config.CopyTilesToSharedTilemaps)
            {
                callbacks.RegisterCallback(PostProcessPrioritiesGrid2D.CopyTilesToSharedTilemaps, (level, _) =>
                {
                    PostProcessUtilsGrid2D.CopyTilesToSharedTilemaps(level);
                });
            }

            if (config.CenterGrid)
            {
                callbacks.RegisterCallback(PostProcessPrioritiesGrid2D.CenterGrid, (level, _) =>
                {
                    PostProcessUtilsGrid2D.CenterGrid(level);
                });
            }

            if (config.DisableRoomTemplatesRenderers)
            {
                callbacks.RegisterCallback(PostProcessPrioritiesGrid2D.DisableRoomTemplateRenderers, (level, _) =>
                {
                    PostProcessUtilsGrid2D.DisableRoomTemplateRenderers(level);
                });
            }

            if (config.DisableRoomTemplatesColliders)
            {
                callbacks.RegisterCallback(PostProcessPrioritiesGrid2D.DisableRoomTemplateColliders, (level, _) =>
                {
                    PostProcessUtilsGrid2D.DisableRoomTemplateColliders(level);
                });
            }
        }
        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;
                PostProcessUtilsGrid2D.Destroy(child.gameObject);
            }

            // The LevelDescription class must be converted to MapDescription
            var levelDescriptionGrid2D = levelDescription.GetLevelDescription();

            levelDescriptionGrid2D.MinimumRoomDistance            = config.MinimumRoomDistance;
            levelDescriptionGrid2D.RoomTemplateRepeatModeOverride = GeneratorUtilsGrid2D.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 = GeneratorUtilsGrid2D.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");

            Payload.GeneratedLevel = generatedLevel;
            Payload.GeneratorStats = stats;

            yield return(null);
        }
Example #6
0
        public static DungeonGeneratorLevelGrid2D TransformLayout(LayoutGrid2D <RoomBase> layout, LevelDescriptionGrid2D 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(GeneratorConstantsGrid2D.RoomsRootName);

            roomTemplateInstancesRoot.transform.parent = rootGameObject.transform;

            // Initialize rooms
            var layoutData  = new Dictionary <RoomBase, RoomInstanceGrid2D>();
            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(GeneratorConstantsGrid2D.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 RoomInstanceGrid2D(layoutRoom.Room, layoutRoom.IsCorridor, connection, roomTemplatePrefab, roomTemplateInstance, position, polygon);

                // Add room info to the GameObject
                var roomInfo = roomTemplateInstance.GetComponent <RoomInfoGrid2D>();

                if (roomInfo != null)
                {
                    PostProcessUtilsGrid2D.Destroy(roomInfo);
                }

                roomInfo = roomTemplateInstance.AddComponent <RoomInfoGrid2D>();
                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 <LevelInfoGrid2D>();

            if (levelInfo != null)
            {
                PostProcessUtilsGrid2D.Destroy(levelInfo);
            }

            levelInfo = rootGameObject.AddComponent <LevelInfoGrid2D>();
            levelInfo.RoomInstances = layoutData.Values.ToList();

            return(new DungeonGeneratorLevelGrid2D(layoutData, layout, rootGameObject, levelDescription));
        }