# Table of Contents - [DunGen](#dungen) - [Changelog - DunGen](#changelog-dungen) - [1. Creating Tiles - DunGen](#1-creating-tiles-dungen) - [Overview - DunGen](#overview-dungen) - [4. Scene Setup & First Generation - DunGen](#4-scene-setup-first-generation-dungen) - [2. Doorways - DunGen](#2-doorways-dungen) - [Overview - DunGen](#overview-dungen) - [3. Dungeon Flow Basics - DunGen](#3-dungeon-flow-basics-dungen) - [Weighting - DunGen](#weighting-dungen) - [Tile Sets - DunGen](#tile-sets-dungen) - [Archetypes - DunGen](#archetypes-dungen) - [Overview - DunGen](#overview-dungen) - [Dungeon Flow Asset - DunGen](#dungeon-flow-asset-dungen) - [Flow Editor - DunGen](#flow-editor-dungen) - [Doorways - DunGen](#doorways-dungen) - [Dungeon Generator - DunGen](#dungeon-generator-dungen) - [Tiles & Tile Component - DunGen](#tiles-tile-component-dungen) - [Doors - DunGen](#doors-dungen) - [Props for Variety - DunGen](#props-for-variety-dungen) - [Multiple Floors - DunGen](#multiple-floors-dungen) - [Injecting Special Tiles - DunGen](#injecting-special-tiles-dungen) - [Lock & Key System - DunGen](#lock-key-system-dungen) - [Generating Attached Dungeons - DunGen](#generating-attached-dungeons-dungen) - [Tile Connection Rules - DunGen](#tile-connection-rules-dungen) - [Overview - DunGen](#overview-dungen) - [Overview - DunGen](#overview-dungen) - [Built-in Culling - DunGen](#built-in-culling-dungen) - [DunGen Character Component - DunGen](#dungen-character-component-dungen) - [Custom Post-Processing - DunGen](#custom-post-processing-dungen) - [Runtime Events & Code Execution - DunGen](#runtime-events-code-execution-dungen) - [Tile Pooling - DunGen](#tile-pooling-dungen) - [A* Pathfinding Project Pro - DunGen](#a-pathfinding-project-pro-dungen) - [Avoid Collisions With the Scene - DunGen](#avoid-collisions-with-the-scene-dungen) - [Overview - DunGen](#overview-dungen) - [Unity NavMesh Components - DunGen](#unity-navmesh-components-dungen) - [SECTR Portal Culling - DunGen](#sectr-portal-culling-dungen) - [PlayMaker Actions - DunGen](#playmaker-actions-dungen) - [Custom Adapters - DunGen](#custom-adapters-dungen) - [Limitations & Considerations - DunGen](#limitations-considerations-dungen) - [Overview - DunGen](#overview-dungen) - [FAQ - DunGen](#faq-dungen) - [Analysis - DunGen](#analysis-dungen) - [Cookbook - DunGen](#cookbook-dungen) - [Spawning the Player - DunGen](#spawning-the-player-dungen) - [Line Segment Injection - DunGen](#line-segment-injection-dungen) - [Use a Specific Socket for the Main Path - DunGen](#use-a-specific-socket-for-the-main-path-dungen) - [Programmatically Modify the DungeonFlow - DunGen](#programmatically-modify-the-dungeonflow-dungen) --- # DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/#dungen) DunGen ====== [![Header](https://www.aegongames.com/dungen-documentation/assets/images/header.png)](https://www.aegongames.com/dungen-documentation/assets/images/header.png) DunGen is a Unity editor extension designed to make procedural dungeon generation quick and easy—both in-editor and at runtime. It follows a room-based approach: you create prefab "rooms" (called `Tiles`), define doorway positions, and DunGen intelligently connects them to form complete dungeon layouts. Using an intuitive graph-based interface, you control the dungeon’s structure—defining the main path and optional branches, inserting special rooms like shops or boss arenas, and varying the visual style or theme throughout. Back to top --- # Changelog - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/changelog/#2185-20250713) Changelog ========= 2.18.5 - \[2025/07/13\] ----------------------- ### Fixed * The analyser should now correctly handle generation failure, displaying a success rate upon completion 2.18.4 - \[2025/07/10\] ----------------------- ### Changed * Built-in culling and SECTR VIS integration now support dungeons generated attached to other dungeons * SECTR VIS integration now caches portal meshes and disposes of them in OnDestroy() ### Fixed * Fixed an issue causing changes to not be saved when adding objects to a list by dragging and dropping them in the inspector 2.18.3 - \[2025/07/05\] ----------------------- ### Fixed * Fixed an issue causing tiles to spawn in the wrong position when the dungeon root object is not at the origin * Fixed an issue causing debug tile visualisation GameObjects to stick around after the dungeon has been generated when 'Pause Between Rooms' is greater than zero 2.18.2 - \[2025/07/02\] ----------------------- ### Added * The `Dungeon` class now has a reference to the `TileInstanceSource` used for tile pooling. There's now a parameterless `Clear()` function that will return all tiles to the pool and clear the dungeon ### Fixed * The generation failure report window should now correctly display an error when a required tile could not be injected, causing the dungeon generation as a whole to fail * Fixed an issue where multiple copies of the same door prefab would be added to the `Dungeon` component's list of doors * Fixed a build error caused by `DunGenSettings` validation using editor-only methods * Fixed some build-only warnings 2.18.1 - \[2025/06/17\] ----------------------- ### Added * Added support for 2D tile trigger placement ### Changed * Tile injection rules can now be re-ordered and collapsed in the inspector. This has no effect on the generation process and is purely visual 2.18 - \[2025/06/10\] --------------------- ### Added * Doorway connector and blocker prefabs can now optionally use position & rotation offsets to correctly align the prefabs * Added a new option for pooling tiles, improving performance when generating dungeons multiple times * Added a `TilePoolPreloader` component that can be added into the scene to spawn instances of tiles that can be saved with the level and will be used to pre-warm the tile pool * Added a `ITileSpawnEventReceiver` interface that can be implemented on any script to receive a callback when the parent tile is spawned or de-spawned. Useful for resetting state when using tile pooling * Added `OnDungeonGenerationStarted` and `OnAnyDungeonGenerationStarted` events to the `DungeonGenerator` class * Added a new window for displaying the stats of a generated dungeon (Window > DunGen > Generation Stats) * Added functions for finding tiles by their tags to the `Dungeon` class: `FindTilesWithTag`, `FindTilesWithAnyTag`, `FindTilesWithAllTags` * The `Dungeon` class now lists all branches via the `Branches` property * DunGen settings can now be accessed from the project settings window (Edit > Project Settings...) * Added a validation rule that warns when a tile prefab is missing a `Tile` component * Enhanced path straightening options: * Settings on `Archetypes` now include an option to straighten **branches** in addition to or instead of the **main path** * Path straightening can now also be applied to **nodes** in the dungeon flow graph * There are now global settings for path straightening on the `DungeonFlow` asset. These can be optionally overridden in `Archetypes` and on **Nodes** in the flow graph * When the dungeon generation fails after reaching the maximum number of retries, a failure report window will now be displayed, showing all the reasons why the generation failed, and which tiles were involved. This can be turned off in the project settings * Line segments in the dungeon flow graph can now be resized by clicking and dragging the boundary between two line segments ### Changed * **\[BREAKING CHANGE\]:** `IKeySpawnable` has been deprecated. Please update your code to use the new `IKeySpawner` interface instead * Tile instantiation is now also asynchronous if 'Generate Asynchronously' is enabled in the generator settings * PauseBetweenRooms is now automatically disabled outside of the editor so it won't affect the performance of builds * Improvements to generation performance: * Tile bounds are now pre-calculated in the editor to avoid performance overhead at runtime. By default, bounds are automatically recalculated each time the tile prefab is saved, but this can be turned off in the project settings. Bounds can be recalculated at any time using a new button in the Tile inspector * Performance improvement will scale up with the number and complexity of tile prefabs * Tiles are no longer deactivated before being destroyed * Bounds from additional tiles that should contribute to collision avoidance are now cached at the beginning of the generation process * Implemented a choice of broad phase for collision detection: None, Quadtree, or Spatial Hashing. NOTE: Quadtree is not recommended and currently only supports dungeons where the up vector is +Y * Affects the MainPath and Branching phases. Performance improvement will scale up with the number of tiles in the dungeon * Prospective doorway pairs are now sorted in a single pass, and custom connection rules are sorted once at the beginning of the generation process * TileProxy objects are now pooled * Various small performance improvements * The option to include sprite renderers in the bounds calculations has been moved to the global DunGen settings asset * Collision functionality and settings have been refactored into their own classes. Settings now belong in the `DungeonCollisionSettings` class * The Dungeon class now has a `TileInstantiated` event that is fired when a new tile is instantiated * Updated all samples to support tile pooling * `DungeonGenerator`'s `GenerationStats` now contains information about how many of each type of tile were spawned, including how many were newly instantiated vs pulled from the pool * Added assembly definitions for 'DunGen' and 'DunGen.Editor' * Integrations for Unity's NavMesh Components and A\* Pathfinding Project Pro no longer need to be manually extracted. They will be automatically enabled if the appropriate packages are present * Added collapsible foldout categories to the dungeon generator inspector * Selected node/line is now highlighted in the dungeon flow graph editor window ### Fixed * Custom connection rules should now be properly reset if domain reload is disabled in the project * Fixed an issue in the Basic Sample causing many materials to be created when generating a dungeon * Fixed an issue where the project would lose a reference to the default doorway socket * The Doorway component should now always correctly revert to the default socket when no other is selected * Labels on nodes in the dungeon flow graph editor should now correctly appear black in newer versions of Unity * Removed remaining instances of deprecated `FindObjectOfType` and `FindObjectsOfType` * Generating a dungeon attached to a manually placed tile (not spawned by DunGen) should now work as intended * Fixed `NullReferenceException` when placing Doorways in a hierarchy with no `Tile` component * The path straightening chance in the `DungeonArchetype` should now work as intended * Fixed `NullReferenceException` when using empty entries in `LocalPropSet` component ### Removed * Removed support for versions of A\* Pathfinding Project Pro before 5.0 * Removed RAIN AI integration 2.17.5 - \[2025/05/03\] ----------------------- ### Fixed * Path straightening should now work as intended 2.17.4 - \[2024/10/15\] ----------------------- ### Fixed * Fixed an issue that broke nesting for random prefab props 2.17.3 ------ ### Fixed * All generation steps now call the `OnGenerationStatusChanged` callback. Previously the callback was incorrectly not triggering for TileInjection, BranchPruning, and InstantiatingTiles 2.17.2 ------ ### Fixed * AStarPathfindingProjectPro adapter now correctly supports version 5.0 2.17.1 ------ ### Fixed * Fixed a null reference exception caused by trying to process a prop that had been deleted by another prop script 2.17 - \[2024/08/29\] --------------------- ### Added * Dungeons can now be generated attached to other dungeons or even manually placed tiles in the scene using the new AttachmentSettings property on the DungeonGenerator class * Added a new branch mode that allows users to specify the number of branches that should appear on a given section in the dungeon flow (see 'Branch Mode' in the dungeon flow settings) * Added a new option in the archetype settings to optionally specify which tiles can be used at the beginning of branches (similar to the branch cap settings) * DunGen can now avoid colliding with objects not placed by the dungeon generator in one of two ways: * Adding custom Bounds to the `AdditionalCollisionBounds` property on the DungeonGenerator class * Providing a custom function to the `AdditionalCollisionsPredicate` property on the DungeonGenerator class * Multiple doorways can now be marked as designated potential entrances and exits, instead of just one of each ### Changed * The `TilePlacementData` class now contains a new 'BranchId' property to allow custom code to know which branch a tile belongs to * Added events for `OnGenerationComplete` and `OnAnyDungeonGenerationComplete` to the dungeon generator that can be used instead of the original `OnGenerationStatusChanged` if you're only interested in completion * By default, the dungeon generator will now check for collisions against every other dungeon in the scene. This can be disabled by unchecking 'Collide All Dungeons' in the generator settings * Replaced instances of obsolete methods (as a result, DunGen now requires Unity 2020.3 as the minimum version) * `FindObjectOfType` -> `FindFirstObjectByType` * `FindObjectsOfType` -> `FindObjectsByType` ### Fixed * Fixed an issue causing the 'DunGen Settings' asset to not be created properly in newer versions of Unity * Fixed a crash that could happen in the DungeonCrawler sample project when going from one scene to another * Fixed an exception that could happen in the editor when using the culling camera when no scene cameras are present * Fixed an issue that could sometimes cause a key to be placed inside the room being locked (or on any of the attached branches) * Fixed an issue causing door prefabs to be removed when trying and failing to replace it with a locked door * Fixed an issue where keys would exist inside a dungeon even if the corresponding locked doorway could not be placed * `Dungeon.Bounds` is now correctly calculated in world-space when using a dungeon root object not at the origin 2.16 - \[2023/08/15\] --------------------- ### Changed * Most lists now support dragging and dropping to add new elements (including archetypes, tile sets, props, and doorway connectors/blockers) * All lists now support undo/redo when adding or deleting elements * Prop processing is now significantly faster on complex dungeons with many GameObjects * Empty GameObject entries in the LocalPropSet or RandomPrefab components will no longer be ignored and can now be used to signal that no prop should be spawned * Added a validation rule that warns when a terrain is being used in a tile that allows rotation (Unity terrains cannot be rotated) * Selected doorways are now checked for valid placement in the editor: * The doorway will be colour-coded (green = valid, orange = not placed on the edge of the tile, red = not axis-aligned) * A red line will be drawn from the doorway to the nearest valid location * For doorways that are incorrectly placed, there will be a button in the inspector to attempt to fix the placement issues * The dungeon validator will now warn when a doorway is not placed on the edge of the tile bounding box * Unity NavMesh Adapter improvements * Added a new option to automatically calculate the start and end points of navigation links per-doorway instead of just using a pre-determined distance on either side of the doorway * When using the "Full Dungeon Bake" mode, any existing NavMesh surfaces in the dungeons will now be disabled to avoid overlapping navigation meshes * `TileConnectionRule` supports a new 'ConnectionDelegate' which contains more information for more complex custom connection rules. The old delegate has been marked as obsolete but will continue to function for now * Tags are now available on tile and doorway proxy objects for easier access when writing custom connection rules in code * Tiles now have a branch ID that can be accessed via the tile's 'Placement' property. All tiles on the same branch will share a branch ID. Tiles not on a branch will have a branch ID of -1 ### Fixed * Fixed an issue where too much time was being attributed to the branch generation step. New steps for branch pruning and instantiating tile prefabs have been added for more accurate analysis * Fixed and issue causing the 'Cull Each Child' option to not work properly with newer versions of SECTR (requires re-exporting SECTR\_VIS integration package) * Fixed a NullReferenceException when using an empty entry in the RandomPrefab component * Fixed an issue causing the dungeon validator to incorrectly warn about doorways facing the wrong way in a tile containing a terrain * Fixed an issue causing keys to sometimes not be able to spawn in the same room as the lock * Key spawn points will now correctly only be used once * Fixed an issue causing a doorway's 'LockID' to not be assigned * Fixed a NullReferenceException caused when no valid locks could be found * Fixed a NullReferenceException when trying to copy tags from a tile that has none assigned * Fixed a bug causing DunGen to generate too few branches when the branch mode is set to 'Global' 2.15.1 - \[2021/11/01\] ----------------------- ### Changed * The built-in Unity NavMesh adapter now supports providing a layer mask for any surfaces that need to be added at runtime. Existing surfaces are unaffected by this setting * The `DungeonGenerator` class now contains a static event `OnAnyDungeonGenerationStatusChanged` which can be used without a direct reference to a given generator instance ### Fixed * Fixed an issue causing injected tiles to sometimes have their locks not spawn on the entrance doorway * Fixed an issue resulting in an uneven distribution of branches when using the 'Global' branch mode * Fixed an issue causing the 'Global' branch mode to sometimes result in more than the maximum number of branches being created * Fixed an issue causing the DungenCharacter component to not correctly track the current tile if the player only partially stepped into a new tile before returning to the original * Fixed an error caused by the DungenCharacter component re-checking tiles when a dungeon is generated in the editor * Dungeon information (tiles, connections, tile bounds, etc) should now be properly saved when generating a dungeon in the editor 2.15 - \[2021/10/16\] --------------------- ### Added * Injected tiles can now optionally have a locked door using the standard Lock & Key system * The dungeon flow now has an option for pruning branches based on tile tags * A tile at the end of a branch will be deleted based on whether it has one of the tags in the "Branch Prune Tags" list in the dungeon flow settings * This setting ignores any injected tiles marked as required * Added a new `IDungeonCompleteReceiver` interface which can be implemented on any script inside a dungeon to receive a callback when the dungeon generation is complete ### Changed * Doorways now have a set of tags that can be used for custom connection logic in code using `DoorwayPairFinder.CustomConnectionRules` ### Fixed * Doorways connected by the dungeon flow's random connection chance setting should now properly respect custom connection rules * It should now once again be possible to select a different 'Count Mode' in the local prop set inspector * Fixed an issue causing changes to sometimes not be saved when modifying the tags on a Tile component 2.14 - \[2021/06/19\] --------------------- ### Added * Added user-defined tags that can be applied to individual tiles * The dungeon flow now has a "Tile Connection Rules" section that can be used to customise which tiles are allowed to connect based on their tags * Tags can be accessed through code to apply more complex logic * Added a new method for applying custom logic through code to allow/disallow connections between tiles (see `DoorwayPairFinder.CustomConnectionRules`) * Supports making decisions based on doorways and tiles instead of just two doorway sockets * Can be assigned priorities and chained together * Added a new NavMesh adapter for 2D dungeons * Can be found in 'DunGen/Integration/Unity NavMesh.unitypackage' * Requires 2017.2 or higher * Currently supports SpriteRenderer meshes (not colliders) and Tilemaps sprite meshes (also not colliders) ### Changed * AdjacentRoomCulling component Improvements * Added IsTileVisible method and TileVisibilityChanged event * Can now optionally ignore components that are disabled from the start * Many methods are now marked as virtual for easier extension * Now also culls reflection probes 2.13.4 ------ ### Fixed * Fixed a compilation error in the Playmaker integration package * Fixed an issue that allowed designated exits to be used as an entrance to the tile 2.13.3 ------ ### Changed * **\[Breaking Change\]:** All references to `System.Random` have been replaced with a new type `DunGen.RandomStream`. Any user code that references the random number generator will need to be updated. * The dungeon generator should now produce identical results when using the same seed even across different .NET versions 2.13.2 - \[2020/08/13\] ----------------------- ### Fixed * Fixed an error when trying to process child props that have been removed by a prop script * When doing a full dungeon bake using Unity's NavMesh system, the old NavMesh is now correctly cleared first 2.13.1 - \[2020/07/01\] ----------------------- ### Fixed * Removed deprecated components from sample scenes to avoid warnings in Unity 2020.1 * The 'Adjacent Room Culling (Multi-Camera)' component should now work when using scriptable render pipelines, provided the project is Unity 2019.1 or higher * The 'Adjacent Room Culling' component (non-multi-camera) now also has a 'Target Override' property to match its multi-camera counterpart, allowing it to be used in games where you want to cull around the character, not the camera (e.g. third-person or 2D) * Fixed an issue in the Dungeon Crawler Sample that caused the NavMesh to persist between scenes * Fixed an issue with SECTR portal culling integration that caused rooms to not be culled initially when 'Multi Camera Culling' was turned off * Fixed an issue causing 'Doorway Connection Chance' to do nothing 2.13 - \[2020/05/05\] --------------------- ### Added * Archetypes can now be be marked as unique. DunGen will try to ensure that unique archetypes are only used once throughout the dungeon. * The Door component now contains a `DontCullBehind` property to allow doors to be closed without culling rooms behind it. This works for the built-in culling and the SECTR VIS integration. * Doorway connector & blocker prefabs can now all be assigned weights for more control over how frequently certain objects spawn. ### Changed * Tile prefabs are now only instantiated after the entire dungeon layout is generated, resulting in much faster generation times. Tiles will still be spawned individually when generating asynchronously with a 'Pause Between Rooms' greater than zero to allow for visual debugging. * Local Prop Set and Random Prefab props can now be nested properly. Global props should still not have other props nested inside them, but can be nested inside others. * When using the 'Full Dungeon Bake' mode with the built-in Unity NavMesh adapter, it's now possible to use your own surfaces for more control over settings by unchecking the 'Auto-Generate Surfaces' checkbox. ### Fixed * Local prop sets now correctly work with objects attached to door connectors & blockers * The SECTR VIS integration will no longer throw an error if a door already has a SECTR\_MEMBER component 2.12.1 - \[2019/12/12\] ----------------------- ### Fixed * Dungeon generator settings should now properly work with the new prefab workflow in Unity * Fixed an issue causing the phase of a post-process step to be ignored * Connector prefab instances now correctly have their local position reset after being parented to the doorway 2.12 - \[2019/11/20\] --------------------- ### Added * Dungeon Crawler Sample (Extract from "DunGen/Samples/DungeonCrawler.unitypackage"). Requires Unity 2019.1 or higher * Doorway sockets are no longer hard-coded and are instead assets that can be added without modifying DunGen's source code * Doorway size is now part of the new DoorwaySocket asset instead of being applied to each doorway instance * Doorway socket connection logic can be overridden by providing your own function to `DoorwaySocket.CustomSocketConnectionDelegate` * Added a new constraint in generator settings to enforce a minimum padding distance between unconnected tiles * Added a new constraint in generator settings to disallow overhangs (so rooms cannot spawn above other rooms) * Added a new icon for doorways ### Changed * **\[Breaking Change\]:** Upgrading from older versions requires deleting the old version first. Doorways must have their sockets re-assigned using the new system. Up-direction must be re-assigned in dungeon generator settings. * Door prefabs are now parented to their doorway objects, rather than the dungeon root * The maximum overlap between two connected tiles can be tweaked in the dungeon generator settings * Simplified up-vector selection * If no socket is specified for an entry in a TileSet's locked door prefab list, the locked door can be assigned to any socket * Assigning a prefab to a key is now optional * Disabled doorways are no longer considered when connecting tiles together or when calculating tile bounds 2.11.9 - \[2019/10/28\] ----------------------- ### Added * Added a new built-in culling component "AdjacentRoomCulling" * Added "Full Dungeon Bake" mode to Unity NavMesh integration which allows the entire dungeon to be baked as a single surface when generated ### Changed * Improvements to built-in basic culling camera * Improved performance by ~60% (3.19ms -> 1.29ms in test case) * Now optionally supports culling light sources * Now supports culling doors * Some improved inspector tooltips 2.11.8 - \[2019/08/05\] ----------------------- ### Added * Added an option to override the global "Doorway Connection Chance" on a per-tile basis * Added an option to restrict connecting overlapping doorways to only tiles that occupy the same segment of the dungeon flow graph. This should help to prevent unintended shortcuts from appearing when this feature is used ### Changed * The documentation has been updated to include some recent features which had mistakenly been omitted. The documentation also includes a previously missing step when setting up the Lock & Key system * An error is now logged whenever a tiles automatically calculated bounds are invalid (have a negative or zero size) ### Fixed * Automatic bounds calculation will now work properly with newer versions of ProBuilder 2.11.7 - \[2019/04/23\] ----------------------- ### Added * A more comprehensive validation tool has been added to help find any errors when setting up a dungeon. This can be accessed using the "Validate" button in the DungeonFlow asset inspector * Added a 'Branch Mode' option to the dungeon flow allowing users to optionally specify the number of branches that should appear globally across the entire dungeon, rather than locally per-tile ### Changed * BasicRoomCullingCamera now has an option to also cull in the editor scene view * Improved performance of BasicRoomCullingCamera in scenes with a lot of renderers * Foldout labels can now be clicked to expand the foldout * The old dungeon validation is now only run inside the editor for a minor performance improvement in packaged builds * Doorways now also draw their expected up-vector to make it clearer which way they should be facing * Adapters (such as integration for SECTR VIS and Unity's NavMesh) will no longer fail silently if attached to a GameObject without a RuntimeDungeon component * Creating a new DunGen asset will now allow the user to specify a file name * Some improvements for the DungeonFlow inspector 2.11.6 - \[2019/02/19\] ----------------------- ### Changed * Most DunGen components now support editing multiple selected objects * All inspector lists are now re-orderable * Added some in-editor tooltips to properties that didn't already have them * The Tile and RuntimeDungeon components now also allow for editing bounds in the scene view * There is now the option to disallow any tile repetition. This can be done on a per-tile basis or overridden globally in the dungeon generator ### Fixed * Fixed an issue preventing the dungeon generating from working until the scene/editor is restarted after finding an issue with the dungeon layout * SECTR VIS integration will now correctly use the already calculated tile bounds instead of its own. This should prevent any gaps from forming between sectors (resulting in incorrect culling) * Fixed an issue causing some DunGen components to not save correctly when edited in the new prefab editor in Unity 2018.3 * Undo/redo should now work consistently 2.11.5 - \[2018/11/26\] ----------------------- ### Changed * **\[Breaking Change\]:** A\* Pathfinding Project Pro integration updated to version 4.0+. If you're using an older version, you'll need to add `ASTAR_PATHFINDING_VERSION_3` to your "Scripting Define Symbols" in the Unity project settings * Updated to work with the new prefab system in Unity 2018.3 * Moved demo scripts to their own namespace to avoid naming conflicts * Small update to the 2D demo scene to include a controllable player character ### Fixed * Fixed an issue preventing the basic culling camera from culling rooms behind a closed door * The Basic Culling Camera will now no longer incorrectly refresh the visible set of tiles every frame - this could increase performance greatly * Fixed an issue causing the integrated basic culling to not work if the camera was spawned through code 2.11.4 - \[2018/08/28\] ----------------------- ### Fixed * The start tile should now correctly respect the transform of its root game object * The integration for A\* Pathfinding Project Pro should work correctly in Unity 5 or higher * Off-mesh links produced for Unity's NavMesh system will now take the agent's radius into account 2.11.3 - \[2018/01/08\] ----------------------- ### Changed * Auto-calculated bounds should now ignore particle systems * DunGen now supports setting `Physics.autoSyncTransforms` (new in Unity 2017.2) to false ### Fixed * Large tiles should no longer overlap a small amount * The per-tile "Allow Rotation" and "Allow Immediate Repeats" options should work correctly again * Lock & key placement should now correctly be done after props are processed 2.11.2 - \[2017/07/24\] ----------------------- ### Changed * The "Basic Room Culling Camera" component can now optionally be provided with a TargetOverride transform for third-person games * The ArchetypeValidator will now report a warning when a TileSet contains an entry with an unassigned tile and will no longer throw an unhandled exception ### Fixed * Tiles will now correctly never appear in the dungeon layout when they have a tile weight of zero 2.11.1 - \[2017/05/23\] ----------------------- ### Added * Tiles can now optionally designate entrance and exit doorways (available by manually adding a Tile component to your tile) ### Changed * Door prefabs will now always take on the transform of the Doorway that spawned it * "Allow Immediate Repeats" now defaults to true to avoid confusion when testing DunGen with a setup that has only one tile. It's still possible to override this behaviour both globally and on a per-tile basis * The DungeonGenerator class has a new "Retrying" event that is fired whenever DunGen has to retry the entire dungeon layout ### Fixed * JIT errors should no longer be thrown on platforms that require AoT compilation (such as Xbox One & iOS) * Fixed an error preventing use of the PlayMaker integration * Fixed a rare issue that caused rooms with vertical doorways to sometimes be flipped upside-down * Fixed an issue that caused the dungeon generator to incorrectly revisit certain statuses (Branching, PostProcessing, Complete), thus making multiple calls to the `OnGenerationStatusChanged` event * Fixed multiple errors with the dungeon flow editor window * Fixed an OutOfMemoryException that could occur when a tile had a weight of zero 2.11 - \[2017/04/14\] --------------------- ### Added * Added API to DungeonGenerator for registering post-process callbacks: `RegisterPostProcessStep()` & `UnregisterPostProcessStep()` * Callbacks are invoked during DunGen's Post-Process step in order of phase (before or after built-in post-processing), then priority (highest to lowest) * The base NavMeshAdapter class has been changed to use this method to ensure that the NavMesh is build before DunGen reports that the generation is complete when using the `OnGenerationStatusChanged` event * Added an adapter for Unity's new NavMesh system (5.6 beta) * Added an adapter for built-in simple culling for use in interior first-person games; works best with auto-closing doors on each doorway * Dungeon generation can now be performed asynchronously so as to avoid blocking Unity's main thread, allowing for things like animated loading screens to play while the dungeon is being generated * There are some new settings for runtime dungeons to control this behaviour * The new "Pause Between Rooms" settings allows you to pause the generation for a number of seconds after a room is placed to visualise the generation process * Added tooltips to all dungeon generator settings ### Changed * **\[Breaking Change\]:** Drastic changes from previous versions. Back up your project before upgrading. Unity 5.0+ targeted (minimum Unity 4.5+ recommended). * Drastically changed the way DunGen appends tiles internally - it should now generate faster most of the time and practically never fail * Culling adapters now use the same method as NavMesh adapters, they are added as components to the GameObject containing the RuntimeDungeon; moved culling code out of DungeonGenerator class * Documentation has been completely re-written to be more modular, easier to follow, and to include features that may have been skipped over in previous versions. The documentation is now front-loaded with information to get started quickly, more advanced topics come later * Improved the inspector for the Doorway component & changed some of the terminology; it should be much easier to understand now ### Removed * The option to use the legacy weighting system has been removed, there was no reason to use it and it's no longer possible with the new generation method anyway * Code Cleanup: * Removed experimental `GenerateAppended()` method. It was never fully supported and never would have been * Removed orphaned code for dungeon analysis window. RuntimeAnalyzer has always been the way to analyse dungeon generation * Removed code used to generate a main path without allowing backtracking - it wasn't even exposed as an option and allowing backtracking is objectively better * Removed visibility code from the base Tile class; visibility should be handled by culling adapters * Removed TypeUtil & AnalysisWindow ### Fixed * Fixed an issue with the generation failing due to not finding matching doorways in a tile when using a custom `IsMatchingSocket()` method * Disallowing repeated tiles should now work as intended and will now also consider branches * Fixed a collision issue when using manually overridden tile bounds * Fixed an issue with injected tiles on the main path marked as "required" not appearing occasionally * Unused tiles deleted during the generation process should no longer contribute to the NavMesh when generating synchronously 2.10.1 - \[2016/12/11\] ----------------------- ### Added * It's now possible to override DunGen's automatically generated tile bounds by attaching a Tile component to the room prefab and checking the "Override Automatic Tile Bounds" box ### Changed * All Renderer component bounds will be taken into account when calculating tile bounds now, not just MeshRenderers and (optionally) SpriteRenderers ### Fixed * Tiles created with ProBuilder should now have their bounds calculated properly and should no longer overlap * Tile prefab's scale is now correctly handled 2.10 - \[2016/11/15\] --------------------- ### Added * Doorways now have a priority for deciding which doorway's "Door Prefab" should be chosen * Added an option to specify which layer the tile trigger volume is placed on (Defaults to "Ignore Raycasts", only effective if "Place Tile Triggers" is checked) * Added a DungeonFlowBuilder helper class to assist with creating a dungeon flow graph through code * Added a new "count mode" to the local prop set script which allows the number of props to change based on the tile's position in the dungeon layout ### Changed * "Ignore Sprite Bounds" in the dungeon generation settings is now unchecked by default ### Fixed * Fixed an issue with the 2D demo scene which caused tiles to overlap * "Avoid Door Prefab Rotation?" for doorways should now be set properly * Door prefabs should now always be cleaned up correctly * Auto-placed trigger volumes for tiles no longer sometimes have negative sizes * Fixed an issue with the SECTR VIS integration that was causing door states to not correctly update * Fixed an error that occurred when trying to place a lock on a doorway that was already locked * Fixed an issue that was incorrectly allowing assets to be selected in the LocalPropSet component 2.9.1 - \[2016/04/18\] ---------------------- ### Added * There are now options to avoid rotating Door and Blocker prefabs placed by the Doorway component ### Changed * Dungeon generation will fail much less frequently, especially when imposing constraints such as fixed tile rotations * In the event DunGen does fail (editor only; at runtime, DunGen will keep trying indefinitely), points-of-failure will be listed to give a better idea of the cause ### Fixed * Fixed an error causing the "Allow Tile Rotation" override to not work properly * Fixed an issue causing nodes in the Dungeon Flow to be un-selectable if placed over the top of the Start or Goal nodes * Fixed an issue causing doorways from a previous dungeon to be considered when trying to connect overlapping doorways * Fixed an ambiguous reference to `TooltipAttribute` when using PlayMaker integration with newer versions of Unity 2.9 - \[2016/04/03\] -------------------- ### Added * The `Dungeon` class now has a `Bounds` variable which gives the bounding box of the entire dungeon layout * A root GameObject can now be chosen when using the RuntimeDungeon component. If none is specified, it will default to the old behaviour of creating a new root named "Dungeon" * RandomPrefab props now have options for keeping the spawned prefab's position or rotation as an offset. Previously, spawned prefabs always snapped into position and ignored the prefab's transform (this is still the default behaviour) * Added integration for generating navigation meshes with both RAIN and A\* Pathfinding Project Pro * Added an option to disable the trigger volumes DunGen places around each tile. If disabled, the DungenCharacter component won't receive events when moving between rooms ### Changed * Reverted the ProBuilder support changes made in 2.8.0 - these are no longer necessary * The utility function `UnityUtil.CalculateObjectBounds()` now ignores trigger colliders by default. Room bounds should no longer encompass any trigger colliders * Moved `TypeUtil` class to the editor folder as it was causing issues when trying to build for Windows Store (and possibly other platforms) ### Fixed * Fixed an error in the runtime analyser * Fixed errors when using custom doorway socket connection logic 2.8 - \[2016/01/11\] -------------------- ### Added * DunGen now supports tiles made with ProBuilder ### Changed * Tiles will now maintain their proper weights across multiple TileSets. The old behaviour can be reactivated using the "Use Legacy Weighting" option in the dungeon generator settings ### Fixed * DunGen will no longer throw an ArgumentOutOfRangeException if a GameObject containing a Doorway component is disabled * Fixed an error when trying to build a project with SECTR integration * Fixed a stack overflow exception that occurred when no Tile matched the requirements for the next room in the layout * The scale of Tile prefabs will no longer be reset before being placed by the generator 2.7 - \[2015/10/24\] -------------------- ### Added * Injected tiles can now be marked as required. If a required tile is not present at the end of the branch path stage, the generation will fail (and retry until the layout is successfully generated or until the maximum number of failed attempts is reached) * Added a new "Length Multiplier" option to the dungeon generator. The main path length of the output dungeon will be multiplied by this number. Allows for dungeon length to be altered dynamically at runtime * Added support for PlayMaker actions for generating and clearing dungeon layouts ### Changed * The dungeon generator will now wait one frame before changing its status to "Complete" to ensure all unused GameObjects are properly destroyed first * SECTR VIS culling is now easier to enable. Just unpack "DunGen/Integration/SECTR\_VIS.unitypackage" and select "SECTR VIS" from the list of portal culling solutions in the dungeon generator settings. It's now also much easier to integrate your own portal culling solution; just derive a new type from PortalCullingAdapter and implement its abstract methods. * Portal culling will now also automatically handle doors placed by DunGen so that rooms are culled when the connecting door is closed - as a result, door objects are now parented to the dungeon root rather than their doorway. There is now a Door component which will automatically be added to door prefabs placed by DunGen. This component includes information about which doorways and tiles it is connected to and has a IsOpen property which is used to turn portals on or off when used with portal culling * As a result of the new culling changes, door objects are now parented to the dungeon root, rather than their doorway * Doors placed by the Lock & Key system are now considered the same as a door prefab and so will also benefit from the above ### Fixed * Fixed an issue that was causing dungeons to not generate properly when `Generate()` was called from a physics trigger/contact * Fixed an error that caused DunGen to try to place locks & keys using a DungeonFlow without a KeyManager assigned * Tiled placed using the tile injection system should now correctly make use of their full range of possible spawn locations * Injected tiles should no longer occasionally overwrite tiles placed by a node in the DungeonFlow 2.6 - \[2015/07/15\] -------------------- ### Added * Tiles can now be "injected" into DunGen before randomization occurs. Injection delegates can be added to the generator's `TileInjectionMethods` property * Tile injection for simple cases can be done through the DungeonFlow inspector. No code required. * There's now a "Overwrite Existing?" option when generating dungeons in the editor * Doorways now have a "Hide Conditional Objects?" option which hides all GameObjects in the "Add when in use" and "Add when NOT in use" lists. For the purpose of reducing clutter at design-time - has no effect on the runtime results * Doorways now have a "Blocker Prefabs" list which works similarly to the existing "Door Prefabs" list, except with doorways that are not in use. Allows you to define blocking objects without placing them in the tile first, if that's your preferred workflow ### Changed * All object lists now report how many objects they contain ### Fixed * Fixed an issue that sometimes caused tiles to not be cleaned up correctly in editor-built dungeons, resulting in what looked like overlapping tiles 2.5.5 - \[2015/06/13\] ---------------------- ### Added * Both "Allow Immediate Repeats" and "Allow Tile Rotation" now have optional global overrides that can be set in the dungeon generator ### Changed * "Allow Immediate Repeats" can now be specified per-tile and is now set to false by default ### Fixed * Fixed an issue causing Tile trigger volumes to sometimes be incorrectly oriented * Fixed a bug which lead to SECTR portals not being removed when calling the `Generate()` function multiple times (like when using the analyser) * Fixed some camera related bugs in the demo scene 2.5.4 - \[2015/04/11\] ---------------------- ### Added * The `DungeonGenerator` class now has a `DetachDungeon` method allowing you to "tear-off" the dungeon from the generator so that it is not overwritten next time `Generate()` is called * **\[EXPERIMENTAL\]** The `DungeonGenerator` class now has a `GenerateAppended` method which will generate a new dungeon appended to a previous dungeon that you specify. **NOTE:** This is entirely experimental and NOT supported functionality; dungeons generated in this manner will likely overlap or fail depending on whether allowIntersection is set. You'll have to decide how/if this is handled when it occurs. This is mostly in place as a starting point for those of you who want to implement infinite dungeons - but it needs additional logic (likely game-specific) to work as a complete solution. * Doorway components now have a `ConnectedDoorway` variable * Tiles now have some methods of getting/checking adjacent Tiles * Tiles now contain a BoxCollider trigger component. There's a new DungenCharacter component which handles information about which Tile it's currently in (with events fired when switching tiles) ### Changed * DunGen is using a new method for socketing doorways together which is more robust. Doorways can now be aligned vertically (for stairwells, for example) ### Fixed * The Lock & Key system will correctly also place locks on doorways that don't have a prefab applied to them 2.5.3 - \[2015/02/10\] ---------------------- ### Changed * The `Doorway` class is now properly defined under the namespace "DunGen" which should help with any naming conflicts * Minor changes to make the demo scene compatible with Unity 5.0 ### Fixed * DunGen should no longer try to apply a lock to the same door twice, causing an exception to be thrown * Doorways with no possible "locked door prefab" will no longer be considered when adding locks * In-editor dungeons will once again generate correctly * Dungeons should now be generated in the local coordinate space of its root GameObject, rather than at the world-space origin * Fixed an issue causing a branch tile's `NormalizedPathDepth` to be calculated incorrectly, resulting in errors in Unity 5 2.5.2 - \[2014/12/29\] ---------------------- ### Added * Added a Straighten slider to the DungeonArchetype that controls the likelihood that the main path generated will be a straight line (thanks to Binary42) * Multiple keys can now be spawned for a single lock. In the KeyManager asset, each key has a "Keys per Lock" value ### Changed * Users should notice a large improvement in success rate when generating dungeons * DunGen will keep trying until it succeeds when the project is built (can still fail in the editor as a safety net to prevent infinite loops for invalid dungeons) * Users should notice a further large improvement in success rate when generating dungeons; in addition to shorter generation times (thanks to ashwinFEC) ### Fixed * Fixed an issue causing bounding boxes to sometimes be calculated incorrectly * Doorways should no longer have multiple door prefabs assigned to them if the doorways were connected by overlapping * Doorways with different sockets will no longer be connected when overlapping * DunGen should now retry to place a Tile when none of those in the TileSet have a socket of the correct type * DunGen should now correctly try to add the specified number of locked doors to a dungeon segment. **NOTE:** This still rarely produces desired results 2.5.1 - \[2014/12/19\] ---------------------- ### Fixed * Fixed an issue causing RandomPrefabs to not inherit their parent's rotation * RandomPrefabs will now correctly be added when nested inside another RandomPrefab * Door prefabs will now correctly be added to open doorways 2.5 - \[2014/10/04\] -------------------- ### Added * Added an option to reduce the frequency that duplicate rooms are being placed right next to each other. Un-checking "Allow Immediate Repeats" in the dungeon generator settings will enable this behaviour. * Added a button to the Local Prop Set inspector that allows for all currently selected GameObjects to be added to the list at once. ### Fixed * Fixed a bug causing the bounding box of some rooms to be incorrect once rotated by DunGen. * Fixed a bug causing the ChosenSeed variable to be set incorrectly after a failed generation attempt. 2.4.2 ----- ### Changed * Doorways no longer have to be on the very edge of a room's bounds. DunGen will calculate the bounds as usual, then collapse them to fit the doorways where necessary. 2.4.1 ----- ### Fixed * Fixed a bug preventing the seed from being set manually * Fixed a bug causing branching depth to not behave as expected 2.4 - \[2014/07/06\] -------------------- ### Added * Added preliminary support for 2D dungeons. It's now possible to change the up-axis for dungeon generation inside the dungeon generator settings. 2D support hasn't been thoroughly tested yet but it is feature-complete. 2.3.1 - \[2014/05/29\] ---------------------- ### Added * DunGen now supports SECTR portal culling. If you have the SECTR VIS extension, you will have automatic portal culling applied to your runtime and in-editor dungeons with minimal setup. * Added door prefabs 2.2 - \[2014/05/17\] -------------------- ### Added * Added a new analysis tool that generates a set number of copies of a dungeon and presents detailed results such as success rate, average generation time, etc ### Changed * It's no longer a requirement to make sure the prefab's position is set to (0,0,0) - not doing so will no longer cause the tile's position to be offset in the dungeon ### Fixed * Fixed an issue that caused the timings returned by the generation stats to be inaccurate when the dungeon fails to generate the first time 2.1 - \[2014/05/02\] -------------------- ### Added * Lock Key system * You can tell DunGen to connect doorways that overlap but were otherwise not connected during the generation process 2.0 - \[2014/04/23\] -------------------- ### Added * Implemented the dungeon flow editor. You can now control the flow of your procedural dungeons including the ability to add specific rooms at points on the main path * Introduced two new types of asset: Dungeon Archetype and Tile Set which should allow for far more control when building a dungeon ### Changed * **\[Breaking Change\]:** Complete rewrite from v1.x. Significant code and workflow changes. * Homogenised object weights. Weights for all objects (tiles/rooms and all prop types) now contain a main path weight, a branch path weight, and a depth scale curve * A lot of terminology and naming was changed, there's less ambiguity now when it comes to identifying key components of DunGen * Cleaned up the UI a lot 1.0.1 - \[2014/03/13\] ---------------------- ### Added * Added some height-varying rooms to the demo project to demonstrate multi-floor dungeons * Added the option to generate a dungeon in the editor instead of at runtime 1.0 - \[2014/03/07\] -------------------- Initial Version Back to top --- # 1. Creating Tiles - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/getting-started/1-creating-tiles/#getting-started-creating-a-tile) Getting Started: Creating a Tile ================================ Room Geometry ------------- First, we'll create a very simple tile. In DunGen, a Tile is a segment of your dungeon, usually a room or corridor, that the dungeon generator will piece together to create the final layout. Start by creating an empty GameObject and give it a descriptive name (e.g. "Basic Room). This GameObject will act as the container for our room's geometry and doorways, and we'll later turn it into a prefab. Set up up the basic geometry of the room but leave gaps where you want doorways to be in the future. Not all of them will necessarily be used, so feel free to add more than you need. > ⚠️ **Important:** > Doorways must be positioned on the edge of the Tile's Axis-Aligned Bounding Box (AABB). > See the [Limitations](https://www.aegongames.com/dungen-documentation/troubleshooting/limitations/#doorway-placement) > section for more details. [![Basic Room Geometry](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/basic-room-geo.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/basic-room-geo.png) Basic room geometry with gaps for doors We have the shell of a room tile, now we need to tell DunGen how it should connect to other tiles. In the next step, we'll create doorways for our room. Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/getting-started/#getting-started) Getting Started =============== Welcome to the Quick Start guide. Here, you'll learn how to create your first procedural dungeon layout using DunGen—with minimal setup and fast results. We'll walk you through the core steps of DunGen's room-based system: * **Design Your Building Blocks:** Create a simple room prefabs (Tile) * **Define Connection Points:** Specify where doorways can appear * **Control the Structure:** Build a basic `Dungeon Flow` graph to guide the generator * **Generate on Demand:** Use the `Runtime Dungeon` component to bring it all together To keep things simple, we'll gloss over most settings for now and focus on the essentials. Once you've seen your first dungeon come to life, you'll be ready to dive deeper in later sections. Ready? [Let's create your first tile →](https://www.aegongames.com/dungen-documentation/getting-started/1-creating-tiles/) Back to top --- # 4. Scene Setup & First Generation - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#getting-started-scene-setup-first-generation) Getting Started: Scene Setup & First Generation =============================================== Now that we have our dungeon flow set up, it's time to generate it. * * * Setting Up the Generator ------------------------ Start with a clean scene or an empty GameObject in your existing one. 1. Create a new `GameObject` and name it **Dungeon Generator** 2. Add the `Runtime Dungeon` component: `Add Component > DunGen > Runtime Dungeon` [![Runtime Dungeon Settings](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/runtime-dungeon-settings.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/runtime-dungeon-settings.png) In the Inspector: * Assign your **Dungeon Flow** asset to the appropriate field * Make sure **Generate On Start** is checked Now when you enter Play Mode, DunGen will automatically generate a dungeon based on your setup. > 🎥 **Tip:** > Switch to the Scene view during Play Mode to fly around and inspect the layout. [![Generated Dungeon Layout](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/final-generated-dungeon.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/final-generated-dungeon.png) Generating in Code We can generate a new dungeon in code as follows. Add this new component to any GameObject in your scene and be sure to assign your `Runtime Dungeon` to the field. Now, pressing R will generate a new random dungeon. GenerateDungeonOnKeyPress.cs `[](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-2) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-4) public class GenerateDungeonOnKeyPress : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-5) { [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-6) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-7) [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-8) void Update() [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-9) { [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-10) if(Input.GetKeyDown(KeyCode.R)) [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-11) { [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-12) var generator = RuntimeDungeon.Generator; [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-13) generator.Generate(); [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-14) } [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-15) } [](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/#__codelineno-0-16) }` Back to top --- # 2. Doorways - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/#getting-started-doorways) Getting Started: Doorways ========================= Creating a Doorway ------------------ Now we need a way to tell DunGen where we want our doorways to be. To do this, we'll create another empty GameObject and call it “Doorway”. Be sure to parent it to your tile GameObject. Now we'll add a `Doorway` component to our new doorway: `Add Component > DunGen > Doorway` [![Doorway Placement](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/doorway-placement.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/doorway-placement.png) The doorway should be placed on the very edge of the tile with its local Z-axis (shown by the light blue line in the editor) pointing outwards. Working in 2D? Make sure the door is correctly oriented to match your up-direction. The **green line** should point upwards. Can't see the doorway? If the doorway outline isn't visible, check that **Gizmos** are enabled in the Scene view. Look for this button: ![Gizmos Button](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/gizmos-button.png). You may also need to expand the dropdown next to it and make sure the 'Doorway' checkbox is checked Don't worry if the outline doesn't match the shape or size of your doorway. For the purpose of this tutorial, all that matters is that the doorway is centered correctly. * * * Doorway Blockers ---------------- Right now, DunGen can connect Tiles using your doorway—but unused doorways would leave visible gaps in the dungeon walls. To prevent this, we’ll use **Blockers** to automatically fill in any unused doorways. A blocker can be anything that visually closes off a doorway: a wall, debris, furniture, or even a sealed door. [![Doorway Blocker](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/doorway-blocker.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/doorway-blocker.png) 1. Create a new GameObject with a wall mesh (or whatever fits your aesthetic). 2. Position it to block the doorway. 3. Parent this blocker to the Doorway object. 4. In the Doorway component, expand the **Blockers** section. 5. Drag your blocker GameObject into the **Scene Objects** list. Now, when a doorway isn’t used during generation, the blocker will be shown. If the doorway is connected to another room, DunGen will automatically hide the blocker. * * * Reusing Doorways ---------------- For easy reuse of our doorway, we can make it a prefab by dragging the GameObject into our project window. Now, any changes made will be reflected wherever we use our doorway prefab. Once that's done, you can easily duplicate and reuse it for each of the remaining door gaps in your room: * Drag the prefab into the scene, or * Select an instance and press Ctrl+D to duplicate it Place a doorway at each of the gaps you left earlier. * * * Recap ----- At this stage, you should have: * A simple room Tile * A doorway placed at each entrance * Each doorway containing a Blocker to fill in unused paths Here's what your setup should look like: [![First Doorway - End Result](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/first-doorway-end-result.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/first-doorway-end-result.png) Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/#core-concepts-overview) Core Concepts: Overview ======================= Asset Types ----------- * ![Tile Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/tile.png) **Tile** * * * The building blocks of your dungeon. Usually a single room or corridor [Read More →](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/) * ![Tile Set Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/tile-set.png) **Tile Set** * * * A collection of Tiles to choose from at random [Read More →](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) * ![Archetype Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/archetype.png) **Archetype** * * * A type or “biome” for a dungeon section. Also describes how branching occurs [Read More →](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) * ![Dungeon Flow Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/dungeon-flow.png) **Dungeon Flow** * * * The master graph that controls structure and progression [Read More →](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) * * * Paths ----- There are two types of path in DunGen: ### Main Path The primary route or “hot path” through your dungeon that goes from the **Start** tile to the **Goal** tile. DunGen first creates the **Main Path** by running through the `Dungeon Flow` from start to finish. Each step adds a new **Tile** adjacent to the one created in the previous step, constructing the dungeon one tile at a time. Since the **Main Path** is considered critical to gameplay, if DunGen fails to generate it following the constraints set, it will backtrack or restart until it succeeds Note In the editor, DunGen will give up if it fails to generate the dungeon a certain number of times to avoid running into an infinite loop. In a packaged build, it will continue until it succeeds * * * ### Branch Paths One of any number of optional branches coming off the **Main Path**. These are not meant to be critical to gameplay. Once the **Main Path** has been generated, DunGen loops back through the dungeon adding **Branch Paths** to line segments in the graph. If DunGen fails at any point when generating a branch, it will consider the last Tile placed to be the end of that branch and move on. Back to top --- # 3. Dungeon Flow Basics - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/getting-started/3-dungeon-flow/#getting-started-dungeon-flow-basics) Getting Started: Dungeon Flow Basics ==================================== Now that we've created a basic room Tile and added Doorways, it’s time to give DunGen instructions on how to assemble those Tiles into a full dungeon. This is where the **Dungeon Flow** system comes in. * * * Marking the Tile ---------------- We need to add a `Tile` component to the root of our room (_Add Component > DunGen > Tile_). This component provides information about how DunGen should handle the tile. For now, the defaults are exactly what we need. Our tile GameObject now needs to be turned into a prefab. Drag the GameObject into a folder in the project window just like we did with the doorway. Before DunGen can use our room, we need to mark it as a Tile. 1. Select the root of your room GameObject (e.g. "BasicRoom"). 2. Add the `Tile` component: `Add Component > DunGen > Tile` The default settings will work just fine for now. Now turn your room into a prefab by dragging it into a folder in the Project window—just like we did with the Doorway earlier. * * * Setting Up Assets ----------------- DunGen uses a few asset types to define how dungeons are generated: * ![Tile Set Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/tile-set.png) **Tile Set** * * * A collection of Tiles to choose from at random * ![Archetype Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/archetype.png) **Archetype** * * * A type or “biome” for a dungeon section * ![Dungeon Flow Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/dungeon-flow.png) **Dungeon Flow** * * * The master graph that controls structure and progression Let’s create each of these now. * * * ### ![Tile Set Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/tile-set.png) Tile Set Right-click in your Project window and choose: `Create > DunGen > Tile Set` This asset holds the list of prefab Tiles DunGen can randomly choose from. [![Simple Tile Set Setup](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/simple-tile-set.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/simple-tile-set.png) We just need to assign our tile prefab to the newly created tile set. With the Tile Set selected: * Click **Add New Tile**, or * Drag your Tile prefab directly onto the button * * * ### ![Archetype Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/archetype.png) Archetype An `Archetype` represents a segment of the dungeon path that allows us to have distinct sections. We could use these to create biomes (e.g. castle, graveyard), but we'll only need the one for this tutorial. [![Simple Tile Set Setup](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/simple-archetype.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/simple-archetype.png) With the Archetype asset selected: * Click **Add New** under the **Tile Sets** section, or * Drag your Tile Set onto the button * * * ![Archetype Icon](https://www.aegongames.com/dungen-documentation/assets/images/asset-icons/dungeon-flow.png) Dungeon Flow -------------------------------------------------------------------------------------------------------------------------- We have one final asset to create: the Dungeon Flow that ties everything together. Right-click in the project window once again and select: `Create > DunGen > Dungeon Flow` This asset has a lot of options, but for now we're only concerned with the flow graph. With the dungeon flow asset selected, click on the **Open Flow Editor** button in the inspector and you will be greeted with the basic default graph containing just a **Start** and a **Goal** node, with a single line connecting them. [![Default Dungeon Flow Graph](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/default-flow-graph.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/default-flow-graph.png) The default dungeon flow graph * * * Understanding the Flow Graph ---------------------------- ### Nodes Nodes (such as **Start** and **Goal**) on the graph represent a **single tile**. Click on one of the nodes to edit it in the inspector. For now, we'll just add our only tile set to the list for both the **Start** and **Goal** nodes. Later, we might decide we want a specific tile at the beginning and/or end of the dungeon. This would be the place to do that. In future tutorials, we'll also look into adding additional nodes, allowing us to place specific rooms such as boss rooms that need to appear at certain points along the main path. * * * ### Lines Between the nodes is a single line and clicking on it reveals a simple list of archetypes in the inspector. As before, we'll assign our single archetype asset to this list. DunGen will make a path of random tiles between the two nodes connected by this line. In future tutorials, we'll split this line segment into multiple biomes. * * * ### Dungeon Length [![Dungeon Length](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/dungeon-length.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/dungeon-length.png) The overall length of the dungeon is not determined by the graph, and is instead set inside the `Dungeon Flow` asset as a range of values. Based on these numbers (and taking into account any nodes in the graph), DunGen will automatically calculate how long the line segments in the flow graph should be. * * * Recap ----- You should now have three new assets in your project: * A **Tile Set** with your room prefab * An **Archetype** using that Tile Set * A **Dungeon Flow** with a basic two-node graph [![All Assets Created](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/all-assets-created.png)](https://www.aegongames.com/dungen-documentation/assets/images/getting-started/all-assets-created.png) All the assets we've created Dungeon Validation To ensure we didn't make any mistakes along the way, we can validate the dungeon by selecting our `Dungeon Flow` asset and pressing the 'Validate Dungeon' button in the inspector. A message will appear in the console letting us know if any issues were detected. If you don't see the console window, go to `Window > Panels > Console` to open it. All that remains is to generate the dungeon layout, which we'll be doing in the [next section →](https://www.aegongames.com/dungen-documentation/getting-started/4-scene-setup/) Back to top --- # Weighting - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/#core-concepts-weighting) Core Concepts: Weighting ======================== What is Weighting? ------------------ Throughout DunGen, you'll encounter settings related to **Weight**. Simply put, **weight controls likelihood.** When DunGen has to choose one item from a list (like picking which Tile to place next, or which Prop variant to keep), items with a higher weight are more likely to be chosen. **Key Principle:** Weights are **relative**. * If Tile A has a weight of 1 and Tile B has a weight of 1, they have an **equal chance** of being chosen. * If Tile A has a weight of 2 and Tile B has a weight of 1, Tile A is **twice as likely** to be chosen as Tile B. * If Tile A has a weight of 0.5 and Tile B has a weight of 0.5, they _still_ have an **equal chance** (same as 1 vs 1). * If an item has a weight of 0, it will **never** be chosen under those conditions. You'll find weight settings primarily in: * [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) : Controlling the chance of each Tile prefab being selected. * Prop Components (`Local Prop Set`, `Random Prefab`, `Global Prop`): Controlling the chance of props spawning or specific prefabs being chosen. * Doorway Component (`Connectors`/`Blockers`): Controlling the chance of specific connector/blocker prefabs being chosen. * * * Components of a DunGen Weight ----------------------------- [![Tile Weights](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/tile-weights.png)](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/tile-weights.png) Weight used by a `Tile Set` A full weight configuration in DunGen (like those found on Tiles within a Tile Set) has three main parts: 1. **Main Path Weight:** The base likelihood of this item being chosen when DunGen is building the **main path** (the critical route from the start to the goal). 2. **Branch Path Weight:** The base likelihood of this item being chosen when DunGen is building an optional **branch path**. * _Why two base weights?_ This lets you make certain tiles or props common on the main path but rare in branches, or vice-versa. For example, maybe key quest rooms only appear on the main path (`Main Path Weight > 0`, `Branch Path Weight = 0`). 3. **Depth Scale (Curve):** This is a powerful modifier that allows the item's likelihood to **change based on how deep into the path** it's being placed. * **How it works:** The curve graph adjusts the _effective_ weight. * The **X-axis** represents the normalized depth (0 = start of the path, 1 = end of the path). * The **Y-axis** represents a **multiplier** (0 = zero chance, 1 = use the base weight exactly, 2 = double the base weight, etc.). * DunGen calculates the current depth (0-1), finds the corresponding multiplier value on the Y-axis of the curve, and multiplies the appropriate base weight (Main or Branch) by this value. * **Example:** * Imagine a curve that starts low (Y=0.1) at the beginning (X=0) and ramps up high (Y=2.0) at the end (X=1). * An item with this curve would be _unlikely_ to appear near the start of the dungeon path (base weight \* 0.1) but _very likely_ (base weight \* 2.0) to appear near the end. * * * Putting it Together ------------------- The final chance of an item being chosen at any given point is calculated roughly like this: `Effective Weight = Base Weight (for current path type) * Depth Scale Multiplier (at current depth)` DunGen then compares the `Effective Weight` of all possible choices at that moment to determine the probabilities. * * * Practical Examples ------------------ * **Common Room:** `Main Path Weight = 1`, `Branch Path Weight = 1`, `Depth Scale = Flat line at Y=1`. (Equal chance everywhere) * **Early Game Room:** `Main Path Weight = 1`, `Branch Path Weight = 1`, `Depth Scale = Starts high (Y=1), drops low (Y=0.1) near the end`. (Common early, rare late) * **Boss Room Ante-chamber:** `Main Path Weight = 1`, `Branch Path Weight = 0`, `Depth Scale = Starts very low (Y=0), sharply rises only near the end (X=0.9 to 1.0)`. (Only appears on the main path, right before the goal) * **Secret Room (Branches Only):** `Main Path Weight = 0`, `Branch Path Weight = 1`, `Depth Scale = Flat line at Y=1`. (Only appears in branches, equal chance throughout branch length) By combining these three components, you can precisely control the frequency and placement context of your tiles and props within the generated dungeons. Back to top --- # Tile Sets - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/#core-concepts-tile-sets) Core Concepts: Tile Sets ======================== What is a Tile Set? ------------------- Tile Sets are essentially named groupings or **collections of your Tile prefabs**. Think of them as palettes or inventories of rooms and corridors that DunGen can draw from during generation. Their main purpose is to help you **organize your tiles** and **control which specific sets of tiles can be used** in different parts of your dungeon or for different structural roles. Tile Sets vs. Archetypes It's important to understand the difference: * **Tile Set:** A _collection_ of Tile prefabs * **Archetype:** A set of _rules_ defining a section of the dungeon (branching behaviour, length, etc.) which _uses_ one or more Tile Sets You can create as many Tile Sets as you need to categorize your content effectively. * * * How are Tile Sets Used? ----------------------- Tile Sets act as the source for Tile selection in several key areas of DunGen: 1. **Dungeon Flow Nodes:** You assign Tile Sets directly to the Start, Goal, and any intermediate Nodes in your [Dungeon Flow graph](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) . This dictates which specific tiles can be used for those critical single-tile placements. 2. **Archetypes:** [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) define which Tile Set(s) should be used when generating the segments of the dungeon they control (both main path lines and branches). 3. **Tile Injection:** When using the [Tile Injection](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/) feature, you specify a Tile Set from which the injected tile should be randomly chosen. 4. **Branch Caps:** [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) allow assigning specific Tile Sets to use for the final tile at the end of a branch path. * * * Creating a Tile Set ------------------- You create Tile Set assets directly in your project: 1. Right-click in the Project view. 2. Navigate to `Create > DunGen > Tile Set`. 3. Give your new Tile Set asset a descriptive name (e.g., "Crypt\_Corridors", "Castle\_LargeRooms", "StartTiles"). * * * Inspector Settings ------------------ Selecting a Tile Set asset reveals its configuration options in the Inspector: ### Tile Weights This is the main part of the Tile Set, where you list the Tile prefabs included in this collection and configure their selection likelihood. * **Adding Tiles:** Tiles can be added in one of two ways: 1. Click the "Add New Tile" button. Drag a Tile prefab from your Project view into the "None (GameObject)" slot that appears. 2. Drag a Tile prefab from your Project view directly onto the "Add New Tile" button. * **Weights per Tile:** Each Tile entry has its own weight settings: * **Main Path:** The base chance of this tile being chosen when this Tile Set is used for the dungeon's main path. * **Branch Path:** The base chance of this tile being chosen when this Tile Set is used for an optional branch path. * **Depth Scale:** A curve that modifies the Main/Branch path weight based on the tile's normalized depth (0=start, 1=end) along the current path. * _(For a full explanation of how these weights interact, see the [Weighting](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) page)._ Tile Reusability A single Tile prefab can be included in _multiple_ different Tile Sets, potentially with different weights in each set. This is great for organization (e.g., a standard corridor might be in both "Crypt\_Corridors" and "Castle\_Corridors" Tile Sets). * * * ### Locked Door Prefabs This section allows you to define which prefabs DunGen should use when it needs to place a **locked door** involving a Tile from _this_ Tile Set. This is part of the [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) . * **Adding Entries:** Click "Add" to create a new entry for a specific [Doorway Socket type](https://www.aegongames.com/dungen-documentation/core-concepts/doorways/#doorway-sockets) . * **Socket Type:** Select the Doorway Socket asset this entry applies to from the dropdown. * **Prefab Weights:** Click "Add New Prefab" within the socket entry. Drag your locked door prefab(s) here. * If you add multiple prefabs for the _same socket type_, their individual weights determine the chance of each one being chosen when a locked door of that socket type is needed. * * * Common Use Cases ---------------- * **Start/Goal Rooms:** Create Tile Sets like "StartRooms" and "GoalRooms" containing only the specific prefabs suitable for the dungeon's entrance and exit, then assign these to the Start/Goal nodes in the Dungeon Flow. * **Thematic Sections:** Organize tiles by visual theme (e.g., "CryptTiles", "CaveTiles", "CastleTiles") and assign them to different Archetypes used along the Dungeon Flow graph. * **Structural Roles:** Separate corridors from rooms (e.g., "CorridorSet", "RoomSet") to potentially use different Archetype rules or weights for each. * **Difficulty Tiers:** Create Tile Sets for different challenge levels (e.g., "EasyRooms", "HardRooms") and use weights or the Dungeon Flow to introduce harder rooms later in the dungeon. By effectively using Tile Sets, you gain precise control over which pieces DunGen uses where, enabling better organization and more structured procedural generation. Back to top --- # Archetypes - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/#core-concepts-archetypes) Core Concepts: Archetypes ========================= What is an Archetype? --------------------- Think of an Archetype as a **set of rules or a "style guide" for a specific section** of your dungeon layout. While [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) define _which_ tiles are available (the palette), Archetypes define _how_ DunGen should behave when building a segment using those tiles. Specifically, an Archetype controls: * Which [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) to use for placing tiles in this section. * How optional branches should behave (how many, how long). * How much DunGen should try to keep the path straight. * * * How are Archetypes Used? ------------------------ Archetypes are primarily assigned to the **line segments** connecting nodes within the [Dungeon Flow graph](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) . When DunGen generates the tiles corresponding to that line segment (either on the main path or branches originating from it), it uses the rules defined in the assigned Archetype. This allows you to easily create distinct sections within your dungeon – perhaps a crypt section that branches frequently using "Crypt" tiles, followed by a straighter castle corridor section using "Castle" tiles. * * * Creating an Archetype --------------------- You create Archetype assets directly in your project: 1. Right-click in the Project view. 2. Navigate to `Create > DunGen > Dungeon Archetype`. 3. Give your new Archetype asset a descriptive name. * * * Inspector Settings ------------------ Selecting an Archetype asset reveals its configuration options in the Inspector: ### General * **Branching Depth (Min/Max):** Defines the minimum and maximum length (number of tiles) for any _individual branch path_ that originates from a tile within this Archetype's section. Guideline, Not Strict Limit The minimum value is a target, not a guarantee. If DunGen cannot place a branch of the minimum length due to collisions or other constraints, it may create a shorter branch or no branch at all. The maximum value _is_ respected. * **Branch Count (Min/Max):** Defines the minimum and maximum number of branch paths that can _originate_ from any single tile on the main path while DunGen is processing this Archetype's section. Per-Tile vs Global This setting is used when the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) 's `Branch Mode` is set to `Local`. If set to `Global`, the branch count is managed across the entire dungeon by the Dungeon Flow asset itself. Guideline, Not Strict Limit Similar to Branching Depth, the minimum value is a target. DunGen might not be able to place the minimum number of branches from every tile if space is constrained. ### Path Straightening All settings in this section can be optionally overridden from the `Dungeon Flow` asset by checking the checkbox next to each field. If the box is unchecked, the default values from the `Dungeon Flow` will be used instead. * **Straighten Chance:** A value indicating how strongly DunGen should prioritize placing the next tile directly forward, avoiding turns. Higher values result in straighter, less winding paths. A value of 0 applies no directional preference. * **Straighten Main Path:** Should the path straightening be applied to tiles on the main path? * **Straighten Branch Paths:** Should the path straightening be applied to tiles on branch paths? ### Tile Sets * **List of Tile Sets:** This is where you specify which [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) DunGen should use when selecting tiles for this section of the dungeon (both main path and branches). * **Adding Sets:** Click "Add New" and drag a Tile Set asset from your Project view into the slot. * **Selection:** DunGen will consider _all_ tiles within _all_ the listed Tile Sets, respecting their individual [weights](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) , when choosing the next tile for this section. ### Branch Cap Tiles This section allows you to define specific tiles that should be used as "dead ends" or caps for branch paths generated within this Archetype. * **Branch Cap Type:** Controls how the Branch-Cap Tile Sets (below) are used: * `Instead Of`: Only tiles from the "Branch-Cap Tile Sets" list below will be considered for the final tile of a branch. The main "Tile Sets" list (above) is ignored for this last tile. * `As Well As`: Tiles from _both_ the main "Tile Sets" list and the "Branch-Cap Tile Sets" list are considered for the final tile of a branch. * **Branch-Cap Tile Sets:** A list of [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) specifically designated for use as branch caps. Click "Add New" and assign Tile Set assets here. Length Dependent DunGen tries to use these caps, but if a branch path ends up being shorter than the configured `Branching Depth` (due to collisions, etc.), the final tile might not necessarily come from this specific list. * * * Purpose and Use Cases --------------------- Archetypes are powerful tools for: * **Defining Thematic Sections:** Assign different Archetypes with different Tile Sets to consecutive lines in your Dungeon Flow to transition between visual styles (e.g., cave entrance -> crypt -> lava caverns). * **Controlling Complexity:** Create Archetypes with high branching settings for maze-like areas, and others with low/zero branching for straightforward corridors. * **Pacing:** Use Archetypes with simpler tiles and fewer branches early in the dungeon flow, and introduce more complex ones later. * **Defining Branch Content:** Ensure branches use specific types of tiles (e.g., only "SecretRoom" tilesets for branches in a certain section). By combining Archetypes with Tile Sets and arranging them in the Dungeon Flow graph, you gain significant control over the structure, style, and complexity of your generated dungeons. Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/#advanced-features-overview) Advanced Features: Overview =========================== Once you're comfortable with the [Core Concepts](https://www.aegongames.com/dungen-documentation/core-concepts/) of Tiles, Tile Sets, Archetypes, and the basic Dungeon Flow, you can begin exploring DunGen's more advanced capabilities. This section covers features that allow for greater control, deeper integration with your game systems, and more complex procedural outcomes. These features build upon the foundation established earlier, enabling you to: * Add significant visual variety without necessarily creating more unique Tile prefabs. * Implement gameplay mechanics like locked doors and keys. * Exercise fine-grained control over tile placement and connectivity. * Hook into the generation process with your own custom code. * Attach new dungeons dynamically to existing ones. Build Upon Core Concepts While powerful, these features generally assume a working knowledge of the basic DunGen workflow. If you haven't already, make sure you're familiar with the topics covered in the [Getting Started](https://www.aegongames.com/dungen-documentation/getting-started/) and [Core Concepts](https://www.aegongames.com/dungen-documentation/core-concepts/) sections. **Explore the Advanced Features:** * **[Props for Variety](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/) :** Learn how to use Local Prop Sets, Random Prefabs, and Global Props to dynamically add or remove objects within your tiles, increasing visual interest and randomness. * **[Doors](https://www.aegongames.com/dungen-documentation/advanced-features/doors/) :** Go beyond simple blockers/connectors. Understand the `Door` component placed on spawned door prefabs and how it interacts with other systems like culling and pathfinding. * **[Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) :** Implement locked doors and corresponding keys within your dungeon layouts using DunGen's integrated system and its C# interfaces. * **[Injecting Special Tiles](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/) :** Force specific tiles or tile types to appear at certain points or under certain conditions within the dungeon layout, using either the Inspector or custom code. * **[Tile Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/) :** Define explicit rules, using Tags or code, to control precisely which types of tiles are allowed (or forbidden) to connect to each other. * **[Generating Attached Dungeons](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/) :** Learn how to procedurally generate a new dungeon layout that connects seamlessly to a specific doorway in an already existing tile (either manually placed or part of a previous generation). * **[Runtime Events & Code Execution](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/) :** Execute your own custom C# logic at specific points during or after the dungeon generation process. * **[Custom Post-Processing](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) :** Add your own major steps to DunGen's generation pipeline, useful for integrating complex third-party systems or custom analysis. * **[DunGen Character Component](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/) :** Use this simple helper component to easily track when a player (or any object) moves between different Tiles in the generated dungeon. Dive into these topics to leverage the full potential of DunGen and create truly unique and dynamic procedural environments. Back to top --- # Dungeon Flow Asset - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/#core-concepts-dungeon-flow-asset) Core Concepts: Dungeon Flow Asset ================================= What is a Dungeon Flow? ----------------------- The **Dungeon Flow** asset is the **master blueprint** for your entire dungeon layout. It orchestrates the high-level structure, defining the sequence of different sections, the overall length, branching behaviour, and connections to other systems like [Locks & Keys](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) or [Tile Injection](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/) . Think of it as the top-level director telling DunGen _how_ to assemble the dungeon using the [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) and [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) you've defined. It uses a visual graph interface, the [Flow Editor](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/) , to represent this structure. Every DunGen generation process starts with a Dungeon Flow asset. * * * Creating a Dungeon Flow Asset ----------------------------- You create Dungeon Flow assets directly in your project: 1. Right-click in the Project view. 2. Navigate to `Create > DunGen > Dungeon Flow`. 3. Give your new Dungeon Flow asset a descriptive name. * * * Inspector Settings ------------------ Selecting a Dungeon Flow asset reveals its configuration options in the Inspector: * **Validate Dungeon:** (Button) Runs a series of checks on the Dungeon Flow and its referenced assets (Tile Sets, Archetypes, Nodes) to help identify potential configuration issues that might prevent successful dungeon generation. * **Key Manager:** Assigns a [Key Manager](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) asset to enable the Lock & Key system for this dungeon flow. _(See Advanced Features for details)._ * **Length (Min/Max):** Defines the minimum and maximum number of tiles that should make up the **main path** of the dungeon (from the start node to the goal node). DunGen will attempt to generate a main path within this length range. ### Doorway Connection * **Connection Chance:** A percentage (0-1) determining the likelihood that two _unconnected_ but spatially overlapping doorways will be connected by DunGen. This can create potential shortcuts or loops if set above 0. * **Restrict to Same Section:** If checked, connections created by the `Connection Chance` can only occur between doorways on tiles belonging to the _same line segment_ in the Flow Editor graph. This prevents accidental shortcuts bypassing major sections defined in the flow. ### Path Straightening Global settings for defining how straight paths should be. These can be overridden on individual [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/#path-straightening) and on nodes in the [Flow Graph Editor](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/) . * **Straighten Chance:** A value indicating how strongly DunGen should prioritize placing the next tile directly forward, avoiding turns. Higher values result in straighter, less winding paths. A value of 0 applies no directional preference. * **Straighten Main Path:** Should the path straightening be applied to tiles on the main path? * **Straighten Branch Paths:** Should the path straightening be applied to tiles on branch paths? ### Branching * **Branch Mode:** Determines how the total number of branches in the dungeon is calculated: * `Local`: The number of branches is calculated _per-tile_ using the `Branch Count` settings from the owning [Archetype](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) . * `Global`: The `Branch Count (Min/Max)` setting defined here (directly below the Branch Mode setting) controls the _total_ number of branches across the entire dungeon. Archetype `Branch Count` settings are ignored. * `Section`: Each line segment in the flow graph will have the desired number of branches specified in the `Branch Count` property of the segment's [Archetype](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) . * **Branch Count (Min/Max) (Visible if Global):** Defines the target minimum and maximum number of branches across the entire dungeon. * **Branch Prune Mode:** The method by which tiles at the end of a branch are removed based on the tags below. * `Any Tags Present`: Tiles at the end of a branch will be removed if any of the following tags are present. Useful for tagging tiles with a `Corridor` tag to avoid branches terminating in a corridor. * `All Tags Missing`: Tiles at the end of a branch will be removed if it doesn't have any of the following tags. E.g. For if you want only tiles tagged as `End Cap`, `Shop`, or `Secret Room` to terminate branches. * **Branch Prune Tags:** Allows you to specify [Tile Tags](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/#tags) that should cause a tile to be deleted if it appears at the very end (dead end) of a branch path. Useful for preventing inappropriate tiles (like simple corridor pieces) from being branch terminators. Tiles are removed based on the `Branch Prune Mode` above. * **Special Tile Injection:** Configure rules to inject specific tiles from designated [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) at certain points in the dungeon layout. _(See [Injecting Special Tiles](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/) for details)._ * **Global Props:** Define the minimum and maximum number of specific [Global Props](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#global-props) that should appear across the entire dungeon. _(See Advanced Features for details)._ * **Tile Connection Rules:** Define rules based on [Tile Tags](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/#tags) to explicitly allow or deny connections between certain types of tiles (e.g., prevent corridors from connecting only to other corridors). _(See [Tile Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/) for details)._ * **Open Flow Editor:** (Button) Opens the visual graph editor associated with this Dungeon Flow asset. * * * The Dungeon Flow asset ties all these pieces together, making it the central configuration point referenced by the [Dungeon Generator](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-generator/) component at runtime. Back to top --- # Flow Editor - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/#core-concepts-flow-editor) Core Concepts: Flow Editor ========================== What is the Flow Editor? ------------------------ The **Flow Editor** is the visual graph interface associated with a [Dungeon Flow Asset](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) . It provides a graphical way to define the high-level structure and sequence of the dungeon's **main path**. You access it by selecting a Dungeon Flow asset in your Project view and clicking the **"Open Flow Editor"** button in the Inspector. [![Default Dungeon Flow](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/dungeon-flow-default.png)](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/dungeon-flow-default.png) Default dungeon flow * * * Understanding the Graph ----------------------- The graph represents the intended progression through your dungeon's critical path: * **Nodes (Boxes):** Represent specific, single tile placements along the main path. * **Start Node (Red):** The fixed starting point of the dungeon. The first tile generated. * **Goal Node (Green):** The fixed endpoint of the main path. The last tile generated. * **Intermediate Nodes (White):** Optional nodes you can add to create distinct milestones within the dungeon flow. * **Line Segments (Lines):** Represent the sequence of tiles generated _between_ two connected nodes. The actual number of tiles in a segment depends on the overall dungeon `Length` (set in the Dungeon Flow asset) and the relative visual length of the segments in the editor. * * * Interacting with the Flow Editor -------------------------------- * **Selecting Elements:** Click on a Node or a Line Segment in the graph. The Unity Inspector window will update to show the configuration options specific to that selected element. * **Adding Nodes:** Right-click anywhere along a Line Segment. This will insert a new **Intermediate Node** at that point. * **Splitting Lines:** Right-click anywhere along a Line Segment. This will **split the segment** at that point. This is how you create more complex flows with multiple distinct sections. [![Adding a Node](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/flow-graph-add-node.png)](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/flow-graph-add-node.png) Right-clicking to add a new node or split a line * * * Configuring Nodes and Lines --------------------------- The real power comes from configuring what happens at each stage: ### Selecting a Node (Start, Goal, or Intermediate) When a Node is selected, the Inspector allows you to configure: * **Label:** A cosmetic name for the node in the editor (doesn't affect generation). * **Tile Sets:** Assign one or more [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) here. DunGen will randomly select a single tile from _one_ of these assigned sets to place at this specific node location. * **Straighten Chance:** An optional override to determine how much the path should be straightened. If the checkbox is unchecked, the default setting is used from the [Dungeon Flow Asset](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/#path-straightening) * **Keys / Locks:** Assign specific Keys or Locks to be placed _within_ this single node tile. (Requires [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) setup). * **Lock Placement:** (Nodes only) Specify _where_ on the node's tile a lock should be placed (e.g., only on its entrance doorway). ### Selecting a Line Segment When a Line Segment is selected, the Inspector allows you to configure: * **Archetypes:** Assign one or more [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) here. DunGen will use the rules (branching, Tile Sets specified _within_ the Archetype) defined in one of the assigned Archetypes to generate the sequence of tiles along this segment. If multiple Archetypes are listed, one is chosen randomly _per segment_. * **Keys / Locks:** Assign Keys or Locks to be placed _randomly_ somewhere along the tiles generated for this line segment. (Requires [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) setup). * **Count:** (Locks on Lines only) Specify how many instances of the listed lock type should be placed along this segment. * * * Example: Multi-Stage Dungeon ---------------------------- By adding intermediate nodes, you can create flows like this: [![Adding a Node](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/dungeon-flow-basic-sample.png)](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/dungeon-flow-basic-sample.png) Multi-Stage dungeon flow This graph tells DunGen: 1. Start with a tile from the "Start" Node's Tile Set(s). 2. Generate a sequence of tiles using the rules from the first Line Segment's Archetype(s). 3. Place a specific tile from the "MiniBoss" Node's Tile Set(s). 4. Generate the next sequence using the second Line Segment's Archetype(s). 5. Place a specific tile from the "Boss" Node's Tile Set(s). 6. Place the final tile from the "Goal" Node's Tile Set(s). * * * Why Use the Flow Editor? ------------------------ The Flow Editor provides a clear, visual way to: * Define the overall progression of your dungeon's main path. * Break the dungeon into distinct sections with different themes or rules (using different Archetypes on lines). * Place specific "milestone" rooms or tiles at key points (using Nodes). * Integrate systems like Locks & Keys at specific structural points. It translates your high-level design intent into concrete instructions for the DunGen generator. Back to top --- # Doorways - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/doorways/#core-concepts-doorways) Core Concepts: Doorways ======================= What is a Doorway? ------------------ Doorways are the fundamental mechanism DunGen uses to **connect your Tiles together**. They act as designated attachment points on your Tile prefabs. When generating a dungeon, DunGen attempts to align Doorways from adjacent Tiles to form connections and build the layout. You define potential connection points by adding Doorway components to your Tile prefabs, as initially covered in the [Getting Started](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) guide. * * * Creating a Doorway ------------------ 1. Inside your Tile prefab, create an **empty GameObject** where you want a potential connection to form. 2. Add the **Doorway component** (`Add Component > DunGen > Doorway`) to this empty GameObject. 3. Position this empty GameObject precisely (see Placement Rules below). 4. Ensure this Doorway GameObject is a child of your main Tile prefab's root object. * * * Placement Rules --------------- Correct Doorway placement is **crucial** for DunGen to function properly. * **Edge of Bounds:** The Doorway's position _must_ lie on the **edge** of the Tile's calculated Axis-Aligned Bounding Box (AABB). If a doorway lies inside the bounds, the bounding box will be shrunk to match its position (potentially causing some geometry to protrude outside the bounding box). Concave Shapes Doorways cannot be placed on concave sections of a Tile's boundary. They must be accessible from outside the Tile's AABB. See the [Limitations](https://www.aegongames.com/dungen-documentation/troubleshooting/limitations/) page for more details. * **Orientation (Z-Axis):** The Doorway GameObject's **local forward (Z) axis** (the blue arrow in the Scene view gizmo) **must point directly outwards**, away from the Tile's interior. This defines the connection direction. * **Orientation (Y-Axis):** By default, the doorway's up axis will point towards positive Y. This is the usual up-vector for 3D scenes, but if you're working in 2D, ensure the Doorway's orientation matches your project's "up" direction so connections form correctly in the 2D plane. * * * The Doorway Component --------------------- The Doorway component holds all the information DunGen needs about this specific connection point: * **Socket:** This is perhaps the most important setting for controlling connections. It assigns a **Doorway Socket** asset to this doorway. See the dedicated [Doorway Sockets](https://www.aegongames.com/dungen-documentation/core-concepts/doorways/#doorway-sockets) section below for details. * **Hide Conditional Objects?:** If checked, connector and blocker scene objects will be hidden to reduce clutter in-editor. This setting has no effect at runtime * * * ### Connectors & Blockers These sections control what appears at the Doorway's location depending on whether it gets used in the final layout: * **Connectors:** Objects placed here are **enabled or spawned** when this Doorway successfully **connects** to another Doorway on an adjacent Tile. * **Use Case:** Door frames, open doorways, dynamic [Door](https://www.aegongames.com/dungen-documentation/advanced-features/doors/) objects, visual connection flourishes. * **Priority:** If both connecting doorways try to spawn a Connector prefab, the one with the **higher priority value** wins and its prefab is spawned. If priorities are equal, one is chosen randomly. * **Blockers:** Objects placed here are **enabled or spawned** when this Doorway remains **unused** (is not connected to another Tile). * **Use Case:** Walls, closed doors, rubble piles, bookcases - anything to block the unused opening. Both Connectors and Blockers share these configuration options: * **Random Prefab:** A list where you can assign prefabs to be potentially spawned at the Doorway's position and orientation. The prefab instance will be attached to the Doorway GameObject. * **Weights:** Each prefab has a [Weight](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) controlling its relative chance of being chosen if multiple prefabs are listed. Only _one_ prefab is chosen per connected doorway pair. * **Avoid Rotation?:** If checked, the spawned prefab will retain its own prefab rotation instead of inheriting the Doorway's rotation. Useful for props that shouldn't rotate with the doorway. Note For Connectors, one prefab per connected doorway pair will be spawned. For Blockers, one prefab per Doorway component will be spawned. * **Scene Objects:** A list of GameObjects already present _within the Tile prefab itself_ (as children somewhere) that should be enabled/disabled based on the Doorway's connection state. * Unlike prefabs, _all_ GameObjects listed here are affected (enabled if the condition is met, disabled otherwise). * * * #### Ensuring Correct Placement of Doorway Prefabs If you're using Connector or Blocker Prefabs (as opposed to Scene Objects), getting the position and rotation right is critical. Since the instantiated prefab will be parented to the Doorway GameObject, it will inherit its position and rotation. While there are options for `Position Offset` and `Rotation Offset`, it's better to just create the prefab with the appropriate offsets built-in. Here's a solid process for doing this: 1. Find an existing Doorway in one of your Tiles. 2. Create a new GameObject and name it appropriately (e.g., "Standard Doorway Blocker"). 3. Parent the empty GameObject to your Doorway and reset its transform (in the inspector, right-click on `Transform` and choose `Reset`). 4. Add the geometry you want to the new GameObject. Move and rotate **only the child objects**, not the root GameObject. This will ensure that all the geometry will be in the correct place when the prefab is instantiated later. 5. When done, drag the root GameObject into the project view to turn it into a prefab. We don't need it in the scene hierarchy any more so feel free to delete it. 6. Assign the new prefab to one of the lists as described earlier. * * * #### Tags * **Functionality:** Allows you to assign one or more custom tags to this Doorway. * **Purpose:** These tags are used by custom [Tile Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/) to allow or deny connections between specific tiles based on the type of doorways DunGen is trying to connect. Tags are extremely versatile and can be used for any number of purposes in your own code. * * * Doorway Sockets --------------- ### Purpose Doorway Sockets are **identifier assets** used to **filter potential connections**. By default, DunGen will only connect two Doorways if they **both share the exact same Socket asset**. This is essential for: * **Different Sizes:** Preventing a small doorway from connecting to a large one. Create separate Socket assets like "Small Archway Socket" and "Large Archway Socket" and assign them accordingly. * **Different Styles:** Ensuring a "Cave Mouth" doorway only connects to another "Cave Mouth", not a "Castle Door". * **Special Connections:** Defining unique sockets for specific connection types, like ladders or teleporters, that shouldn't connect to standard doorways. ### Default Socket DunGen includes a "Default" socket. If all your doorways are identical in size and type, you can simply use this default socket for all of them. ### Creating Custom Sockets If you need different types of connections: 1. Right-click in the Project view. 2. Navigate to `Create > DunGen > Doorway Socket`. 3. Give the new Socket asset a descriptive name. 4. Assign this new Socket asset to the `Socket Group` field on the relevant Doorway components in your Tile prefabs. * * * ### Overriding Matching Behaviour While default behaviour requires sockets to match exactly, you can implement more complex logic using [Code-Based Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#method-2-code-based-rules-advanced) . * * * Doorways, combined with Sockets and their Connector/Blocker configurations, are the core elements that allow DunGen to intelligently piece together your pre-designed Tiles into coherent and varied dungeon layouts. Back to top --- # Dungeon Generator - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-generator/#core-concepts-dungeon-generator) Core Concepts: Dungeon Generator ================================ Overview -------- The **Dungeon Generator** is the engine responsible for taking all your configuration (from the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) , [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) , [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) , etc.) and actually building the dungeon layout in your scene. While you can trigger generation manually through code or via an editor window (`Window > DunGen > Generate Dungeon`), the most common way to handle generation at runtime is by using the **Runtime Dungeon** component. You add this component to a GameObject in your scene (`Add Component > DunGen > Runtime Dungeon`). This GameObject then becomes the central point for controlling and triggering the dungeon generation process for that specific dungeon instance. * * * Runtime Dungeon Component Settings ---------------------------------- Here are the settings available in the `Runtime Dungeon` component's Inspector: * **Generate on Start:** * If checked, the dungeon generation process will automatically begin as soon as the scene starts (in the `Start()` method). If unchecked, you'll need to trigger generation manually via code or another system (like PlayMaker). * **Root:** * An optional GameObject reference. If assigned, the generated dungeon's root GameObject (containing all the placed Tiles) will be parented under this object in the scene hierarchy. If left as `None`, DunGen will create a new root GameObject named "Dungeon". * **Dungeon Flow:** * **Required.** Assign the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) asset that defines the structure and rules for the dungeon you want to generate. This is the master blueprint the generator follows. * **Max Failed Attempts:** * Specifies the maximum number of times DunGen is allowed to completely fail and restart the generation process _in the editor_ before giving up. This prevents infinite loops during design if constraints are too strict. Runtime Behaviour In a standalone build (not the Unity Editor), DunGen will keep retrying indefinitely until it succeeds, ignoring this setting to ensure a dungeon is always generated eventually. * **Length Multiplier:** * A multiplier applied to the `Length` range defined in the assigned `Dungeon Flow` asset. * `1` = Use the length as defined in the Dungeon Flow. * `2` = Double the target length range. * `0.5` = Halves the target length range. * This allows you to easily scale the dungeon size without modifying the Dungeon Flow asset itself. * **Up Direction:** * Defines the primary "up" axis for the dungeon layout (usually `+Y` for 3D, and `-Z` for top-down 2D). This primarily affects the placement logic for vertically oriented doorways, ensuring they connect correctly relative to the dungeon's intended orientation. It does _not_ rotate the entire generated dungeon. * **Debug Render:** * If checked, coloured bounding boxes will be rendered around each Tile in the Scene view _after_ generation is complete. * **Main Path:** Tiles are coloured from **Red** (near Start) to **Green** (near Goal). * **Branch Paths:** Tiles are coloured from **Blue** (near branch start) to **Purple** (near branch end). * Useful for visualizing the generated layout structure and debugging path generation. * * * ### Asynchronous Generation Settings related to generating the dungeon over multiple frames to avoid freezing the game. * **Generate Asynchronously:** * If checked, the dungeon generation process will be spread across multiple frames instead of happening all at once. This prevents the game from hanging during potentially long generation times, allowing loading screens or animations to continue playing. Note Asynchronous generation might take slightly longer overall compared to synchronous generation. * **Max Frame Time:** * (Only used if `Generate Asynchronously` is checked). The maximum time (in milliseconds) that DunGen is allowed to spend on generation tasks within a single frame. Lower values lead to better game responsiveness during generation but increase the total generation time. Higher values shorten total generation time but might cause noticeable frame stutters. * **Pause Between Rooms:** * (Only used if `Generate Asynchronously` is checked). An optional delay (in seconds) to pause _after_ placing each room. Primarily useful for visualizing the step-by-step generation process for debugging purposes. Set to `0` for normal asynchronous generation. This is automatically disabled in standalone builds. * * * ### Collision Settings controlling how tiles interact spatially. * **Trigger Placement:** * If enabled, DunGen will automatically add a `BoxCollider` (or `BoxCollider2D`) component as a trigger to the root of each placed Tile prefab. These triggers encompass the bounds of the tile. This should be set to match the type of dungeon you're making (2D or 3D). * Can be used in conjunction with the [DunGen Character Component](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/) or your own scripts to detect when an object enters/exits a specific tile area. * **Trigger Layer:** * Specifies the physics layer on which the auto-generated `Tile Triggers` (if enabled above) should be placed. * **Overlap Threshold:** * A small value determining how much two _connected_ tiles are allowed to overlap spatially. Usually doesn't need changing. * **Collide All Dungeons:** * If checked, DunGen will check for collisions against tiles from _all_ previously generated dungeons in the scene, not just the tiles within the dungeon currently being generated. Useful if you have multiple independent DunGen instances active. * **Disallow Overhangs?:** * If checked, tiles are prevented from being placed vertically above or below other tiles if their X/Z bounds overlap. * **Padding:** * The minimum amount of empty space that must exist between the bounding boxes of any two _unconnected_ tiles. Helps prevent unwanted visual overlap and clutter. * * * ### Constraints Settings for restricting where tiles can be placed. * **Restrict to Bounds?:** * If checked, DunGen will only place tiles _within_ the volume defined by the `Placement Bounds` below. * **Placement Bounds:** * (Only used if `Restrict to Bounds?` is checked). Defines a world-space bounding box (Center and Extents) outside of which no tiles can be generated. Warning Using bounds restrictions can significantly increase the chance of generation failure if the bounds are too small for the requested dungeon length and complexity. It may also increase generation time. * * * ### Global Overrides These settings allow you to optionally override specific behaviours for _all_ tiles generated by this component, regardless of their individual [Tile Component](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/) settings. If an override is not enabled, the behaviour is determined _per-tile_. [![Active Override](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/override-active.png)](https://www.aegongames.com/dungen-documentation/assets/images/core-concepts/override-active.png) The checkbox to the left of the setting determines whether the override is active or not. * **Repeat Mode:** * Forces all tiles to adhere to a specific repeat mode (`Allow`, `Disallow Immediate`, `Disallow`), overriding any `Repeat Mode` set on individual Tile components. Defaults to `Allow`. See [Repeat Mode](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/#repeat-mode) on the Tiles page for details. * **Allow Tile Rotation:** * Forces all tiles to either allow rotation or disallow rotation, overriding any `Allow Rotation` setting on individual Tile components. * * * The `Runtime Dungeon` component is the primary interface for launching and controlling the DunGen process within your game scene. Back to top --- # Tiles & Tile Component - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/#core-concepts-tiles-tile-component) Core Concepts: Tiles & Tile Component ===================================== What is a Tile? --------------- **Tiles** are the fundamental building blocks of your dungeons. Think of them as reusable room prefabs, corridor segments, or any distinct piece of level geometry that DunGen will piece together. You design these Tiles visually within the Unity editor, just like any other prefab. DunGen's power comes from how it connects these pre-designed pieces based on rules you define. The Tile Component ------------------ The `Tile` component provides DunGen with specific metadata and allows you to override certain global generation settings on a per-tile basis. ### Tile Component Settings Here are the key settings available on the `Tile` component inspector: * * * #### Allow Rotation * **Functionality:** If checked, DunGen is allowed to rotate this Tile 90, 180, or 270 degrees around its Y-axis (up-axis) to match the orientation of an adjacent Tile's doorway. * **When to Uncheck:** You should uncheck this if your Tile: * Is designed for an isometric or fixed perspective where rotation would break the visual style. * Has a specific "back wall" or orientation that must be preserved. Global Override The [Dungeon Generator](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-generator/) component has a global `Allow Tile Rotation` setting. If you need to disable rotation for _all_ tiles, use the global setting instead of configuring each tile individually. * * * #### Repeat Mode * **Functionality:** Determines how DunGen handles placing multiple instances of this _specific_ Tile prefab within a single dungeon layout. * **Options:** * `Allow`: No restrictions. All repetition is allowed. * `Disallow Immediate`: This Tile can appear multiple times in the dungeon, but never directly connected to another instance of the _same_ Tile prefab. * `Disallow`: This Tile prefab can appear at most _once_ in the entire generated dungeon layout. Use `Disallow` Carefully If you use `Disallow` mode, ensure you have enough unique Tile prefabs available in your [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) for the configured dungeon length. Otherwise, DunGen might fail to generate a valid layout if it runs out of non-repeating tiles. Global Override The [Dungeon Generator](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-generator/) component has a global `Repeat Mode` override setting that applies to all tiles. * * * #### Override Automatic Tile Bounds * **Functionality:** By default, DunGen calculates the physical boundaries (an Axis-Aligned Bounding Box - AABB) of a Tile based on the Renderers and Colliders within its hierarchy. Checking this box allows you to manually define the bounds used for collision detection during generation. * **When to Use:** Useful if the automatic bounds calculation isn't accurate for your Tile's effective space, perhaps due to complex shapes or invisible helper objects affecting the bounds. Note The **Fit to Tile** button can be used to match the overridden bounds to what DunGen's automatic calculation _would_ be, giving you a starting point for manual adjustments. * * * #### Override Connection Chance * **Functionality:** Allows this specific Tile to override the global `Connection Chance` set in the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) asset. This chance determines the likelihood of DunGen connecting two _otherwise unconnected_ doorways that happen to overlap spatially (potentially creating shortcuts or loops). Interaction If two tiles with overlapping doorways _both_ have this override enabled, the _lower_ of the two percentage chances will be used. * * * #### Entrance / Exit Doorways * **Functionality:** You can optionally designate specific [Doorway](https://www.aegongames.com/dungen-documentation/getting-started/1-creating-tiles/) GameObjects within this Tile as the required entry or primary exit points. * **Entrance:** * If set, DunGen _must_ connect to this specific Doorway when placing this Tile. The Tile can only be entered through this doorway. * If unset (None), DunGen can enter the Tile through _any_ available Doorway. * **Exit:** * If set, DunGen _must_ use this specific Doorway as the _first_ point of exit when pathing continues _from_ this Tile. * If unset (None) or once the exit is already in use, DunGen can exit the Tile through _any_ available Doorway. * **Use Cases:** Essential for controlling flow within complex tiles or ensuring specific placements, such as positioning a locked door (related to the [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) ) correctly at the entrance of a boss room. * * * #### Tags * **Functionality:** Allows you to assign one or more custom tags to this Tile. * **Purpose:** These tags are used by the [Tile Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/) system (configured in the Dungeon Flow asset) to allow or deny connections between specific types of tiles (e.g., preventing two "Corridor" tagged tiles from connecting directly). Tags are extremely versatile and can be used for any number of purposes in your own code. * * * By understanding and utilizing these `Tile` component settings, you gain significantly more control over how your individual Tile prefabs behave and integrate into the final generated dungeon layout. Back to top --- # Doors - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#advanced-features-doors) Advanced Features: Doors ======================== In the [Getting Started](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) section, we saw how to add **Connectors** and **Blockers** to Doorway definitions. While Connectors _can_ be simple archways or openings, they are often used to spawn functional **Door** prefabs. Doors can also be placed automatically via the [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) . This page focuses on what happens when DunGen places a prefab designated as a door and the crucial `Door` component that gets added. * * * Spawning Doors -------------- Typically, you designate a door prefab within the **Connectors > Random Prefab** list of a [Doorway component](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) on your Tile prefab. * **Priority:** Remember the `Priority` setting within the Connectors list? If two connected doorways both list potential door prefabs, the doorway with the _higher_ priority value gets its prefab chosen. If priorities are equal, one is chosen randomly. Only _one_ door prefab is spawned per doorway connection pair. * * * The `Door` Component -------------------- Whenever DunGen successfully places a prefab that functions as a door (either through the Connectors list or the Lock & Key system), it automatically adds a `Door` component to the **root GameObject of the instantiated door prefab** if one does not already exist. This component acts as a vital link between the visual door object and various DunGen systems. It holds information about the connection it represents and, most importantly, its current state. * * * ### Key Properties & Information The `Door` component provides the following useful information (accessible via code): * **`IsOpen` (bool):** This is the most important property. It represents the _logical state_ of the door (open or closed). You control this property from your custom door scripts (see below). It directly influences visibility for culling and traversability for pathfinding. **Default Value:** `true` (open). * **`DontCullBehind` (bool):** If true, the culling system (if any) will not cull tiles behind this door, even when closed. * **`DoorwayA` (Doorway):** A reference to the Doorway component on the first tile of the connection. * **`DoorwayB` (Doorway):** A reference to the Doorway component on the second tile of the connection. * **`TileA` (Tile):** A reference to the Tile component of the first tile. * **`TileB` (Tile):** A reference to the Tile component of the second tile. * * * Interaction with Other Systems ------------------------------ The state of the `Door.IsOpen` property is crucial for integrating doors with other DunGen features: 1. **Culling:** DunGen's built-in [Adjacent Room Culling](https://www.aegongames.com/dungen-documentation/optimization/culling/) systems check the `IsOpen` state. If `Cull Behind Closed Doors` is enabled on the culling component, tiles beyond a door where `IsOpen` is `false` will not be rendered. Setting `IsOpen` to `true` allows the culling system to potentially "see" through the doorway. 2. **Pathfinding:** Supported [Pathfinding](https://www.aegongames.com/dungen-documentation/pathfinding/) integrations (like Unity NavMesh Components and A\* Pathfinding Project Pro) use the `IsOpen` state to determine traversability. * For **Unity NavMesh**, NavMeshLinks generated across the doorway are typically enabled when `IsOpen` is `true` and disabled when `false`. * For **A\* Pathfinding Project Pro**, graph connection rules or tag updates often depend on `IsOpen`, making areas beyond closed doors unwalkable. * * * Creating Custom Doors --------------------- If you create your own custom door prefabs (e.g., with animations for opening and closing), it is **essential** that your custom door script correctly manages the `Door.IsOpen` property. Update `IsOpen` State Your custom script (e.g., `MyAnimatedDoor.cs`) **must** get a reference to the `Door` component on the same GameObject and set the `IsOpen` property whenever the door's visual state changes. `[](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-4) [RequireComponent(typeof(Door))] // Ensure the Door component exists [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-5) public class MyAnimatedDoor : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-6) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-7) private Door dunGenDoor; [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-8) private Animator doorAnimator; // Example [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-10) void Awake() [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-12) // Get the component added by DunGen [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-13) dunGenDoor = GetComponent(); [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-14) doorAnimator = GetComponent(); // Example [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-15) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-16) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-17) // Call this when your door visually opens [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-18) public void OpenDoor() [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-19) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-20) // Play animation, sound, etc. [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-21) // doorAnimator.SetTrigger("Open"); // Example [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-22) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-23) // CRITICAL: Update the DunGen Door component state [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-24) if (dunGenDoor != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-25) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-26) dunGenDoor.IsOpen = true; [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-27) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-28) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-29) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-30) // Call this when your door visually closes [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-31) public void CloseDoor() [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-32) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-33) // Play animation, sound, etc. [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-34) // doorAnimator.SetTrigger("Close"); // Example [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-35) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-36) // CRITICAL: Update the DunGen Door component state [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-37) if (dunGenDoor != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-38) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-39) dunGenDoor.IsOpen = false; [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-40) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-41) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-42) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-43) // Example: Simple interaction [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-44) void OnTriggerEnter(Collider other) [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-45) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-46) if (other.CompareTag("Player")) // Example tag [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-47) { [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-48) OpenDoor(); [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-49) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-50) } [](https://www.aegongames.com/dungen-documentation/advanced-features/doors/#__codelineno-0-51) }` By correctly updating `Door.IsOpen`, you ensure that DunGen's culling and pathfinding systems accurately reflect the current state of your custom doors, leading to correct visibility and navigation behaviour in your generated dungeons. Back to top --- # Props for Variety - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#advanced-features-props-for-variety) Advanced Features: Props for Variety ==================================== Creating many unique Tile prefabs can be time-consuming. DunGen offers several "Prop" components that allow you to add significant visual variety and randomness to your existing Tiles without needing to create entirely new room geometry. These components let you dynamically include, exclude, or choose between different GameObjects or prefabs within your Tiles during dungeon generation. There are three main types of prop components: 1. **Local Prop Set:** Manages a collection of _existing_ GameObjects within a Tile, keeping some and discarding others. 2. **Random Prefab:** Spawns _one_ chosen prefab from a list at a specific location within a Tile. 3. **Global Prop:** Ensures only a specific total number of a certain type of prop exists across the _entire_ generated dungeon. Recursive Props Props are processed recursively, allowing you to have props that control other props. For example, you might have a "decoration" **Random Prefab** that spawns a random decorative object that could go on a table (e.g., a book, candle, or ornament). You could then have this prop be controlled by a **Local Prop Set**, that decides which of the "decoration" objects to keep. Let's explore each one. * * * Local Prop Set -------------- * **Purpose:** To selectively keep a subset of GameObjects that are already placed within your Tile prefab. Ideal for over-decorating a room in the editor and then having DunGen randomly remove some items for variety. * **Setup:** Add the `Local Prop Set` component (`Add Component > DunGen > Random Props > Local Prop Set`) to a GameObject _within_ your Tile prefab. The GameObjects you want this component to manage should be **children** of the GameObject holding the `Local Prop Set` component. ### Inspector Settings: * **Count Mode:** Determines how the number of props to _keep_ is decided: * `Random`: A random number between the `Min` and `Max` values of the `Count` range below will be chosen. * `Depth Based`: Uses the `Depth Scale` curve (see Prop Weights below). The X-axis (0-1) represents the normalized path depth, and the Y-axis (0-1) maps to the number of props kept (0 = Min Count, 1 = Max Count). * `Depth Multiply`: A random number between `Min` and `Max` is chosen (like `Random` mode), but this number is then multiplied by the value from the `Depth Scale` curve (Y-axis 0-1) at the current path depth. * **Count (Min/Max):** Defines the minimum and maximum number of child GameObjects that this component should keep active. * **Prop Weights:** This list holds references to the child GameObjects that the Local Prop Set manages. * **Adding Props:** Drag the child GameObjects from the Hierarchy into this list, or click "Add Selected Props" after selecting them in the Hierarchy. * **Weight per Prop:** Each prop entry has its own weight settings (`Main Path`, `Branch Path`, `Depth Scale`). When the component needs to decide _which_ props to keep (if it needs to discard some to meet the count), props with a higher effective weight are more likely to be chosen. Refer to the [Weighting](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) page for details. **Outcome:** When the Tile containing this component is placed, the `Local Prop Set` calculates how many of its child props to keep based on the `Count Mode` and `Count` range. It then selects _which_ props to keep based on their weights and disables (discards) the rest. * * * Random Prefab ------------- * **Purpose:** To spawn a _single_ prefab instance chosen randomly from a list you provide. Ideal for placing randomized decorations, containers, or interactive objects at specific points. * **Setup:** Add the `Random Prefab` component (`Add Component > DunGen > Random Props > Random Prefab`) to an **empty GameObject** within your Tile prefab. This empty GameObject acts as a marker for the spawn location and rotation. ### Inspector Settings: * **Zero Position:** If checked, the chosen prefab will be spawned at the exact position of the marker GameObject, ignoring any positional offset the prefab itself might have relative to its own pivot. If unchecked, the prefab spawns _at_ the marker's position, but _offset_ by the prefab's own internal position (usually (0,0,0), but could be different). * **Zero Rotation:** If checked, the chosen prefab will be spawned with the exact rotation of the marker GameObject, ignoring the prefab's own base rotation. If unchecked, the prefab spawns with the marker's rotation _plus_ the prefab's own base rotation. * **Prefab Weights:** This list holds references to the **prefabs** (from your Project view) that can be spawned by this component. * **Adding Prefabs:** Drag prefabs from your Project view onto the list. * **Weight per Prefab:** Each prefab entry has its own weight settings (`Main Path`, `Branch Path`, `Depth Scale`). The effective weight determines the likelihood of each prefab being chosen for instantiation. Refer to the [Weighting](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) page for details. **Outcome:** When the Tile containing this marker is placed, the `Random Prefab` component selects _one_ prefab from its list based on weights and instantiates it at the marker GameObject's position and rotation (potentially modified by the Zero Position/Rotation settings). * * * Global Props ------------ * **Purpose:** To control the _total number_ of a specific category of object across the entire generated dungeon, regardless of how many potential instances exist within the placed Tiles. Useful for ensuring uniqueness (e.g., only one "Altar of Power") or controlling scarcity (e.g., between 1 and 3 "Treasure Chests"). * **Setup:** Add the `Global Prop` component (`Add Component > DunGen > Random Props > Global Prop`) directly to the **GameObject you want to manage** within your Tile prefab (e.g., if you're wanting to limit the number of treasure chests, this should go on the treasure chest instance inside your tile). ### Component Inspector Settings: * **Group ID:** A **crucial integer** identifier. All props that should be counted together must share the _same_ Group ID. (e.g., all potential Treasure Chests might have Group ID `1`, all Shrines might have Group ID `2`). * **Weights (`Main Path`, `Branch Path`, `Depth Scale`):** These weights **do not** determine if the prop spawns initially (it's already part of the Tile). Instead, they act as a **priority score**. If DunGen places more potential Global Props of a specific Group ID than the allowed maximum (set in the Dungeon Flow, see below), it uses these weights to decide _which instances to keep_. Higher effective weight means higher priority to survive the culling process. Refer to the [Weighting](https://www.aegongames.com/dungen-documentation/core-concepts/weighting/) page for details. ### Dungeon Flow Configuration: The _actual limit_ for each Global Prop category is set in your [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) asset: 1. Select your Dungeon Flow asset in the Project view. 2. Find the **Global Props** section in the Inspector. 3. Click the **+** button. 4. Enter the **`Group ID`** that matches the `Group ID` you set on the components in your Tile prefabs. 5. Set the **`Count` (Min/Max)** range. This tells DunGen the minimum and maximum number of props with this `Group ID` that should exist in the final generated dungeon. **Outcome:** During the post-processing phase of generation, DunGen gathers all enabled GameObjects that have a `Global Prop` component. For each unique `Group ID`, it checks if the total count falls within the Min/Max range defined in the Dungeon Flow asset. * If there are _too many_ props of a certain ID, it discards props at random based on the effective weight (priority) until the count reaches the maximum limit. * DunGen currently doesn't enforce the _minimum_ count if too few potential props were placed initially. * * * Custom Prop Implementation -------------------------- Custom prop behaviour can be achieved by creating a new component derived from the `RandomProp` abstract class. Simply implement the `Process()` method and DunGen will automatically call it when processing props. `[](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#__codelineno-0-1) public abstract class RandomProp : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#__codelineno-0-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#__codelineno-0-3) public abstract void Process(RandomStream randomStream, Tile tile, ref List spawnedObjects); [](https://www.aegongames.com/dungen-documentation/advanced-features/props-variety/#__codelineno-0-4) }` * **randomStream:** The random number generator used to generate the dungeon. This ensures that the same dungeon will be generated again if an identical seed is used. * **tile:** The tile that this prop belongs to. * **spawnedObjects:** An list reference allowing us to let DunGen know if we spawned any objects of our own when processing the prop. This ensures that DunGen can properly process props recursively. * * * By strategically using these three prop components, you can dramatically increase the replayability and visual diversity of your dungeons without needing an excessive number of base Tile prefabs. Back to top --- # Multiple Floors - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/multiple-floors/#advanced-features-multiple-floors) Advanced Features: Multiple Floors ================================== Adding verticality to your dungeons can create more interesting exploration, distinct floor levels, and a better sense of scale or progression. DunGen supports multiple floors not through a specific feature, but by leveraging the core Tile and Doorway system. * * * How it Works: Vertical Doorway Placement ---------------------------------------- The key to achieving multi-floor layouts is simple: **create Tile prefabs where Doorway components are placed at different Y-coordinates (heights).** DunGen's generation process works by aligning the world-space **position and orientation** of doorways when connecting tiles. If two connected doorways have different Y-positions in their respective Tile prefabs, the newly placed Tile will naturally be positioned higher or lower than the previous one, creating a change in floor level. A common example is a Tile representing a staircase: [![Doorway Height Variation](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/doorway-height-variance.png)](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/doorway-height-variance.png) A `Tile` with multiple `Doorways` at different heights When DunGen uses such a Tile, it seamlessly integrates vertical movement into the layout. If you simply include these "transition" Tiles in your regular [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) , floor changes will occur organically based on random selection. However, if you need more precise control over _when_ and _how_ floor transitions happen, you can use the following techniques. * * * Controlling Floor Transitions ----------------------------- Here are several ways to manage verticality in your dungeon generation: ### Forcing Transition Direction (via Doorway Constraints) You can dictate the direction of travel through a transition tile. If you want a specific staircase Tile to _only_ ever lead upwards from the point of entry: 1. Select the transition Tile prefab. 2. Inspect its [Tile Component](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/) . 3. In the `Entrances` list, assign **only the lower Doorway(s)**. Now, DunGen can only enter this Tile via the bottom doorways, forcing the connection path to proceed upwards to exit through the higher doorways. Conversely, assigning only the _upper_ doorways to `Entrances` forces downward transitions. * * * ### Dedicated Transition Points (via Flow Nodes) To ensure a floor transition happens at a specific point in the dungeon's progression: 1. Create a dedicated [Tile Set](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) containing _only_ your floor transition Tiles (like staircases, ramps, elevators). 2. In the [Dungeon Flow Editor](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/) , add a new Node along the main path where you want the transition to occur. 3. Assign your dedicated transition Tile Set to this specific Node. DunGen will be forced to pick a transition Tile at that exact point in the layout. * * * ### Generating Distinct Floors Sequentially To create completely separate floors generated one after another: 1. Design your first floor's layout in the [Dungeon Flow Editor](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/) . 2. Assign a Tile Set containing _only_ upward transition Tiles (e.g., stairs leading up) to the **`Goal` Node** of this first floor's flow graph. 3. Generate the first floor dungeon. It will end with a transition Tile leading to an unused Doorway at the upper level. 4. Use the [Generating Attached Dungeons](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/) feature to generate a _second_ dungeon instance, instructing it to attach specifically to that unused upper Doorway. This second dungeon instance will represent the next floor. Repeat as needed for more floors. * * * Effective use of multiple floors adds depth and complexity to your generated levels. By designing appropriate transition Tiles and using DunGen's flow control features, you can create compelling multi-level environments. Back to top --- # Injecting Special Tiles - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#advanced-features-injecting-special-tiles) Advanced Features: Injecting Special Tiles ========================================== Sometimes, the standard random selection of tiles based on [Tile Sets](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) and [Archetypes](https://www.aegongames.com/dungen-documentation/core-concepts/archetypes/) isn't enough. You might need to guarantee that a specific type of tile (like a boss room, a unique quest location, or a special challenge room) appears in the dungeon, perhaps only once, or within a specific area. This is where **Tile Injection** comes in. It allows you to "inject" tiles from a specified Tile Set into the dungeon generation process, overriding the normal selection based on a set of rules you define. There are two main ways to implement Tile Injection: 1. **Using the Inspector (Simple Rules):** Configure injection rules directly on your [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) asset for common scenarios. 2. **Using Code (Complex Rules):** Write custom logic to add injection rules dynamically for maximum flexibility. * * * Method 1: Tile Injection via Inspector -------------------------------------- For straightforward injection rules based on location within the dungeon, you can configure them directly in the **Special Tile Injection** section of your `Dungeon Flow` asset inspector. 1. Select your `Dungeon Flow` asset in the Project view. 2. Find the **Special Tile Injection** foldout in the Inspector. 3. Click **"Add New Rule"** to create an injection entry. Each rule defines conditions under which a tile from a specified Tile Set should be injected: * **Tile Set (e.g., "Special Tiles"):** Drag the Tile Set asset containing the tile(s) you want to inject here. When this rule triggers, DunGen will randomly select **one** tile from this Tile Set to place. * **Is Required?** * **Checked:** This tile _must_ be successfully placed according to the rules. If DunGen fails to generate a valid dungeon layout that includes this required injection (e.g., due to restrictive placement rules or collisions), it will **retry the entire dungeon generation** until it succeeds. * **Unchecked:** DunGen will _attempt_ to place this tile according to the rules, but if it fails (e.g., no suitable location found within the depth range), generation will continue without it. Performance Impact Using `Is Required?` can increase generation time, especially if the placement rules (`Path Depth`, `Branch Depth`) are very narrow or if collisions are likely. Use it only when placement is absolutely essential. * **Can appear on Main Path?** If checked, this rule allows the tile to be injected somewhere along the main path (Start to Goal). * **Can appear on Branch Path?** If checked, this rule allows the tile to be injected somewhere along an optional branch path. * **Locked:** If checked, the entrance to this tile will be locked. * **Lock Type:** Which lock from the `KeyManager` to use. * **Path Depth:** Defines the normalized range along the **main path** where this injection is allowed. * `0` represents the Start tile location. * `1` represents the Goal tile location. * A range of `0.4` to `0.6` means the tile can only be injected near the middle of the main path. * **Branch Depth:** (Only used if `Can appear on Branch Path` is checked) Defines the normalized range along a **branch path** where this injection is allowed. * `0` represents the first tile of the branch (connected to the main path). * `1` represents the final tile (dead end) of the branch. * A range of `0.9` to `1.0` means the tile can only be injected near the end of a branch. You can add multiple rules to inject different types of special tiles under various conditions. * * * Method 2: Tile Injection Through Code ------------------------------------- For more advanced scenarios where injection rules depend on dynamic game state, complex logic, or need more fine-grained control, you can inject tiles via code. This involves creating a method that matches the `TileInjectionDelegate` signature and adding it to the `TileInjectionMethods` list on the `DungeonGenerator` instance. **The Delegate Signature:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-0-1) // Your method needs to match this pattern [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-0-2) void MyInjectionLogic(DunGen.RandomStream randomStream, ref List tilesToInject);` * `randomStream`: The `DunGen.RandomStream` instance used for the current dungeon generation. Use this if your injection logic needs randomness consistent with the dungeon seed. * `tilesToInject`: A list of `InjectedTile` objects. Your method must add new `InjectedTile` instances to this list. DunGen will then process this list during generation. * * * ### The InjectedTile Class: You create instances of `InjectedTile` to represent the tiles you want to inject. The `InjectedTile` class has the following properties: * **TileSet (`TileSet`):** The TileSet to inject. * **NormalizedPathDepth (`float`):** Normalized (0-1) depth along the main path that this tile should be spawned (0 = Start, 1 = Goal). * **NormalizedBranchDepth (`float`):** (Only valid if spawned on a branch) Normalized (0-1) depth along the branch that this tile should be spawned (0 = Branch Entrance, 1 = Branch Cap) * **IsOnMainPath (`bool`):** Should this tile be spawned on the main path? If false, it will be spawned on a branch. * **IsRequired (`bool`):** If true, DunGen will regenerate the dungeon if it fails to spawn this injected tile. * **IsLocked (`bool`):** Should the entrance to this tile be locked using the [Lock & Key System](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) ? * **LockID (`int`):** (Only used if `IsLocked` is true) The ID of the lock to use. This is the index of the lock found in the `KeyManager`. Example Implementation In this example, we will inject a random tile from the `TileSet` assigned to `MySpecialTileSet` onto the end of the first branch encountered after the halfway point of the main path. CustomTileInjector.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-3) using System.Collections.Generic; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-4)[](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-5) public class CustomTileInjector : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-6) { [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-7) // Assign your Runtime Dungeon Generator here [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-8) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-10) // Assign the TileSet containing your special tile(s) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-11) public TileSet MySpecialTileSet; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-12) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-13) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-14) private void Start() [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-15) { [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-16) if (RuntimeDungeon != null && RuntimeDungeon.Generator != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-17) RuntimeDungeon.Generator.TileInjectionMethods += InjectMySpecialTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-18) else [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-19) Debug.LogError("RuntimeDungeon or its Generator is not assigned"); [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-20) } [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-21) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-22) // This method matches the TileInjectionDelegate [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-23) private void InjectMySpecialTile(RandomStream randomStream, ref List tilesToInject) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-24) { [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-25) // Define the injection parameters [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-26) bool tryOnMainPath = false; // Let's target a branch path in this example [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-27) float targetPathDepth = 0.5f; // We want this to spawn at the halfway point of the main path [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-28) float targetBranchDepth = 1.0f; // Target the very end of the branch [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-29) bool mustBePlaced = false; // It's okay if this tile isn't placed [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-30) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-31) var tileToInject = new InjectedTile(MySpecialTileSet, tryOnMainPath, targetPathDepth, targetBranchDepth, mustBePlaced); [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-32) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-33) // Add it to the list DunGen will process [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-34) tilesToInject.Add(tileToInject); [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-35) } [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-36) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-37) // Unsubscribe when the object is destroyed [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-38) private void OnDestroy() [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-39) { [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-40) if (RuntimeDungeon != null && RuntimeDungeon.Generator != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-41) RuntimeDungeon.Generator.TileInjectionMethods -= InjectMySpecialTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-42) } [](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/#__codelineno-1-43) }` ### Attaching the Delegate: You typically add your custom injection method to the `TileInjectionMethods` list before generation begins, often in a `Start()` or `Awake()` method after getting a reference to the `DungeonGenerator`. Remember to unsubscribe (-=) in `OnDestroy()` or `OnDisable()` to prevent issues if the generator object persists longer than your injector script. * * * When to Use Which Method ------------------------ * **Inspector:** Best for simple, static rules based purely on placement depth (main/branch path ranges) and whether the tile is required. Easy to set up and manage without code. * **Code:** Necessary when injection logic is complex, depends on external factors (game state, player progress), requires dynamic calculation of placement, or needs to inject multiple different tiles based on intricate conditions. Offers ultimate flexibility but requires scripting knowledge. Tile Injection is a powerful tool for adding specific, authored moments or structures within your otherwise randomized dungeons. Back to top --- # Lock & Key System - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#advanced-features-lock-key-system) Advanced Features: Lock & Key System ==================================== DunGen includes a robust system for procedurally placing locked doors and their corresponding keys within your dungeon layouts. This allows you to create progression gates, control access to specific areas (like boss rooms), and add another layer of dynamic gameplay. Implementing the Lock & Key system involves configuration across several assets and requires some C# scripting to integrate the key pickup and door unlocking logic into your actual game mechanics. **The Core Components:** 1. **Key Manager Asset:** Defines the different types of keys available in your dungeon. 2. **Tile Set Asset:** Specifies which prefabs to use for locked doors. 3. **Dungeon Flow Asset:** Determines where locks and keys should be placed within the dungeon structure. 4. **Runtime Interfaces (`IKeySpawner`, `IKeyLock`):** C# interfaces you implement to tell DunGen _how_ to spawn key objects and _notify_ your prefabs when they are assigned a specific key type. * * * 1\. Creating the Key Manager ---------------------------- First, you need to define the types of keys your dungeon can use. 1. Create a **Key Manager** asset: Right-click in Project view > `Create > DunGen > Key Manager`. 2. Select the asset. In the Inspector, click **"Add New Key"** for each distinct key type you need (e.g., Red Key, Blue Key, Boss Key). 3. Configure each Key Type: * **Name:** A human-readable name (e.g., "Red Skeleton Key"). Used for identification, potentially in UI. * **Prefab:** (Optional) A prefab representing the key visually in the scene (e.g., a collectible key model). DunGen will tell your code _which_ prefab to potentially spawn via the `IKeySpawner` interface. * **Colour:** (Optional) A color used for visual debugging in the editor and potentially for color-coding locks and keys in your game via the `IKeyLock` interface. Note These properties (Prefab, Colour) are conveniences. Whether you use them depends entirely on how you implement the runtime interfaces later. 4. **Link to Dungeon Flow:** You must assign this Key Manager asset to the **`Key Manager`** field in your [Dungeon Flow asset](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) so DunGen knows which keys are available for that flow. * * * 2\. Assigning a Locked Door Prefab ---------------------------------- Next, tell DunGen which prefab(s) represent a locked door. This is done _per Tile Set_. 1. Select a [Tile Set asset](https://www.aegongames.com/dungen-documentation/core-concepts/tile-sets/) that contains tiles where locked doors might appear. 2. In the Inspector, find the **"Locked Door Prefabs"** section. 3. Click **"Add"** to create an entry for a specific [Doorway Socket](https://www.aegongames.com/dungen-documentation/core-concepts/doorways/#doorway-sockets) . Choose the relevant socket from the dropdown (e.g., "Default"). * This means _when a lock is placed_ on a connection using this socket type, and involving a tile from this Tile Set, DunGen will look here for the prefab to use. 4. Within that socket entry, click **"Add New Prefab"** and drag your locked door prefab(s) into the slot(s). 5. Configure **Weights** if you add multiple locked door prefabs for the _same_ socket type. The weights determine the likelihood of each prefab being chosen when that type of locked door is needed. * * * 3\. Placing Keys and Locks (Dungeon Flow) ----------------------------------------- Now, define _where_ in the dungeon structure keys and locks should appear. This is configured in the [Dungeon Flow editor](https://www.aegongames.com/dungen-documentation/core-concepts/flow-editor/) . 1. Select your [Dungeon Flow asset](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) and click **"Open Flow Editor"**. 2. Select a **Node** or a **Line Segment** in the graph. 3. In the Inspector, you'll find **`Keys`** and **`Locks`** lists. ### Assigning Keys/Locks: * Click **"Add"** under the `Keys` or `Locks` list. * Select the desired **Key Type** (defined in your Key Manager) from the dropdown. ### Placement Differences: * **Nodes:** Keys/Locks assigned here will be placed _specifically within the single tile_ generated by that node. * **Line Segments:** Keys/Locks assigned here will be placed _randomly somewhere along the sequence of tiles_ generated by that line segment. ### Node-Specific Setting: `Lock Placement` * When assigning a **Lock** to a **Node**, you get an extra `Lock Placement` option: * `Entrance`: The locked door will _only_ be placed on the doorway the player enters the node's tile through. Essential for boss rooms or requiring a key found earlier to enter a specific tile. * `Exit`: The locked door will _only_ be placed on the doorway used to exit the node's tile. * `Any`: The locked door can be placed on any doorway connected to the node's tile. ### Line Segment Setting: Lock `Count` * When assigning a **Lock** to a **Line Segment**, you can specify a `Count` (Min/Max) for how many instances of that lock type should appear within that segment. Solvability Guarantee DunGen's logic ensures dungeons are always completable regarding locks and keys: 1. It places **Locks** first based on your Flow configuration. 2. It then determines where the corresponding **Keys** _must_ be placed. 3. It guarantees that keys are placed in locations accessible _before_ their corresponding locks are encountered along the main path. It uses the potential key locations you assigned in the Flow Editor to find valid spots. * * * 4\. Tying it into our Game (Runtime Integration) ------------------------------------------------ DunGen handles the _placement_ logic, but it needs your C# code to handle the _game-specific actions_ of spawning key objects and reacting to lock/key assignments. This is done by implementing two interfaces: ### `IKeySpawner` Interface * **Purpose:** Implement this interface on a component to tell DunGen _how_ and _where_ a key object should actually appear in the game. * **Method:** `void SpawnKey(KeySpawnParameters keySpawnParameters);` * **Workflow:** 1. When DunGen decides a specific `Key` needs to be placed at a location defined in the Dungeon Flow (Node or Line Segment). 2. It searches for GameObjects at valid positions within the target Tile(s). 3. It finds components on those GameObjects that implement `IKeySpawner`. 4. It randomly selects one of these components. 5. It calls the `SpawnKey` method on the selected component, passing information about the specific `Key` type. * **Implementation Examples:** * **Spawn Prefab:** Your `SpawnKey` method could instantiate the `key.Prefab` at the component's position (like the demo scene's `KeySpawnPoint` script). * **Add to Inventory:** Your `SpawnKey` method on an enemy's script could add the `key` to that enemy's drop loot table. * **Place in Chest:** Your `SpawnKey` method on a chest script could add the `key` to the chest's contents. KeySpawnPoint.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-3) using DunGen.LockAndKey; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-4)[](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-5) public class KeySpawnPoint : MonoBehaviour, IKeySpawner [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-6) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-7) // Check if the key has already been spawned [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-8) public bool HasSpawnedKey => spawnedKey != null; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-10) private GameObject spawnedKey; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-11) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-12) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-13) public bool CanSpawnKey(KeyManager keyManager, Key key) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-14) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-15) // We can't spawn a key if one has already been spawned [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-16) if (HasSpawnedKey) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-17) return false; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-18) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-19) // We can't spawn a key if it has no prefab [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-20) return key.Prefab != null; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-21) } [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-22) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-23) public void SpawnKey(KeySpawnParameters keySpawnParameters) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-24) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-25) var key = keySpawnParameters.Key; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-26) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-27) if (keySpawnParameters.Key.Prefab == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-28) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-29) Debug.LogWarning($"Key '{key.Name}' needs to be spawned here, but has no Prefab assigned in the Key Manager.", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-30) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-31) } [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-32) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-33) // Instantiate the key prefab defined in the Key Manager [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-34) spawnedKey = Instantiate(key.Prefab, transform.position, transform.rotation); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-35) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-36) // Notify the DunGen about any IKeyLock components that were created [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-37) var keyLockComponents = spawnedKey.GetComponentsInChildren(); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-38) keySpawnParameters.OutputSpawnedKeys.AddRange(keyLockComponents); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-39) } [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-0-40) }` Props & Keys Timing Props (Local, Random, Global) are processed _before_ the Lock & Key system runs. This means if you have a chest placed as a random prop, DunGen can correctly identify it later as a potential spawn location for a key if the chest's script implements `IKeySpawner`. ### `IKeyLock` Interface * **Purpose:** Implement this interface on components within your **Locked Door prefabs** and your **Key prefabs** to be notified _which specific Key type_ has been assigned to them. * **Method:** `void OnKeyAssigned(Key key, KeyManager manager);` * **Workflow:** 1. When DunGen places a **locked door prefab**, it calls `OnKeyAssigned` on all components implementing `IKeyLock` within that prefab's hierarchy, passing the assigned `Key`. 2. When DunGen tells your `IKeySpawner` to spawn a key and you (optionally) return a list of spawned `IKeyLock` back to DunGen. `OnKeyAssigned` will be called automatically on all of these components. * **Implementation Examples:** * **Visual Feedback:** Change the color of a mesh renderer on the lock/key based on `key.Colour` (like the demo scene's `KeyColour` script). * **Store Key Info:** Store the required `Key` object on the locked door script so you know what key the player needs when they interact with it. * **Initialize Key Object:** Set up properties on the collectible key script based on the assigned `Key` type. KeyColour.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-4) public class KeyColour : MonoBehaviour, IKeyLock [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-5) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-6) // Assign in Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-7) public Renderer TargetRenderer; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-8) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-9) // Used to change material properties without leaking material instances into the scene [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-10) private MaterialPropertyBlock propertyBlock; [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-11) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-12) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-13) public void OnKeyAssigned(Key key, KeyManager manager) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-14) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-15) if (TargetRenderer != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-16) { [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-17) if(propertyBlock == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-18) propertyBlock = new MaterialPropertyBlock(); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-19) [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-20) // Use the color defined in the Key Manager [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-21) propertyBlock.SetColor("_Color", key.Colour); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-22) TargetRenderer.SetPropertyBlock(propertyBlock); [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-23) } [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-24) } [](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/#__codelineno-1-25) }` By combining asset configuration with these runtime interfaces, you can create complex and solvable lock and key puzzles within your procedurally generated DunGen levels. Remember that the actual player interaction logic (detecting key pickup, checking inventory, triggering door unlocks) needs to be implemented in your own game systems. Back to top --- # Generating Attached Dungeons - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#advanced-features-generating-attached-dungeons) Advanced Features: Generating Attached Dungeons =============================================== Typically, DunGen generates a dungeon based purely on the rules defined in the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) , starting from the world origin. However, you might need to generate a dungeon that physically connects to an existing piece of geometry in your scene. This is useful for scenarios like: * Connecting a procedurally generated area (like a mine or cave system) to a static, hand-designed part of your level (like a town entrance). * Dynamically spawning a new dungeon section attached to a previously generated one. * Starting generation from a specific, manually placed entrance Tile. DunGen allows this through the **`AttachmentSettings`** property on the `DungeonGenerator` class. This is configured **entirely through code** before triggering the generation process. * * * The `AttachmentSettings` Class ------------------------------ Before initiating dungeon generation via code, you can create an instance of the `DunGen.AttachmentSettings` class and assign it to `RuntimeDungeon.Generator.AttachmentSettings`. This class tells DunGen _where_ and _how_ to attach the start of the new dungeon layout. There are two primary ways to specify the attachment point: ### 1\. Attaching to a Tile You can provide a reference to an existing `Tile` component in your scene. DunGen will then attempt to attach the new dungeon to one of the `Doorway` components found on that Tile. * **How it works:** DunGen randomly selects an available `Doorway` on the target `Tile`. If the initially chosen doorway is blocked (e.g., by scene geometry or another tile), DunGen will **keep trying** other available doorways on that same `Tile` until it finds a valid connection point or runs out of options. * **Constructor/Usage:** You typically instantiate `AttachmentSettings` by passing the target `Tile` reference: `[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-0-1) RuntimeDungeon runtimeDungeon;//... Get reference to your RuntimeDungeon component [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-0-2) Tile targetTile;//... Get reference to your existing Tile component [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-0-4) var settings = new DunGen.AttachmentSettings(targetTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-0-5) runtimeDungeon.Generator.AttachmentSettings = settings;` * **Use Case:** Useful when you want to connect to a specific room or prefab already placed in the scene, but you don't need to dictate the _exact_ doorway used for the connection. ### 2\. Attaching to a Specific Doorway For more precise control, you can provide a reference directly to a specific `Doorway` component on an existing Tile. * **How it works:** DunGen will attempt to attach the start of the new dungeon _only_ to the specified `Doorway`. Warning If you provide a specific `Doorway`, **DunGen will not try other doorways** on the same tile if the chosen one is blocked or invalid for attachment. It's your responsibility to ensure the provided `Doorway` is positioned correctly and has clear space for the new dungeon to generate outwards from it. If the connection fails at this specific doorway, the dungeon generation might fail entirely. * **Constructor/Usage:** You typically instantiate `AttachmentSettings` by passing the target `Doorway` reference: `[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-1-1) RuntimeDungeon runtimeDungeon;//... Get reference to your RuntimeDungeon component [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-1-2) Doorway targetDoorway;//... Get reference to your existing Doorway component [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-1-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-1-4) var settings = new DunGen.AttachmentSettings(targetTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-1-5) runtimeDungeon.Generator.AttachmentSettings = settings;` * **Use Case:** Ideal when you need the dungeon to connect at a very specific point on an existing tile, like a pre-defined exit archway. * * * Code Examples ------------- Here are a collection of basic example scripts demonstrating how to set up attached generation. For each example, you would: 1. Attach the script to a GameObject in your scene. 2. Assign the reference to your `RuntimeDungeon` component in the inspector. 3. Call the `GenerateAttached()` method. Continue from the previous dungeon In this example, we will generate a new dungeon attached to the last tile on the main path (the Goal) of the **previous dungeon** that was generated by the `RuntimeDungeon` component. ContinueDungeon.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-1) public class ContinueDungeon : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-3) // The dungeon generator to use for generating the new dungeon. Set in inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-4) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-5) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-6) public void GenerateAttached() [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-7) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-8) var previousDungeon = RuntimeDungeon.Generator.CurrentDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-10) if (previousDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-12) var lastTile = previousDungeon.MainPathTiles[previousDungeon.MainPathTiles.Count - 1]; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-13) RuntimeDungeon.Generator.AttachmentSettings = new DungeonAttachmentSettings(lastTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-14) RuntimeDungeon.Generate(); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-15) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-16) else [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-17) Debug.LogError("No previous dungeon found to attach to."); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-18) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-2-19) }` Attach to a random Tile from the previous dungeon In this example, we will generate a new dungeon attached to a random tile of the **previous dungeon** that was generated by the `RuntimeDungeon` component. AttachToRandomTile.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-1) public class AttachToRandomTile : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-3) // The dungeon generator to use for generating the new dungeon. Set in inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-4) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-5) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-6) public void GenerateAttached() [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-7) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-8) var previousDungeon = RuntimeDungeon.Generator.CurrentDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-10) if (previousDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-12) // Find all tiles that have unused doorways [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-13) var possibleTiles = previousDungeon.AllTiles [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-14) .Where(x => x.UnusedDoorways.Any()); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-15) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-16) if (possibleTiles.Any()) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-17) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-18) // Pick a Tile at random [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-19) var chosenTile = possibleTiles.ElementAt(UnityEngine.Random.Range(0, possibleTiles.Count())); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-20) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-21) // Generate a new dungeon attached to the chosen tile [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-22) RuntimeDungeon.Generator.AttachmentSettings = new DungeonAttachmentSettings(chosenTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-23) RuntimeDungeon.Generate(); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-24) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-25) else [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-26) Debug.LogError("No tiles with unused doorways found in the previous dungeon."); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-27) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-28) else [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-29) Debug.LogError("No previous dungeon found to attach to."); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-30) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-3-31) }` Attach to a specific Doorway In this example, we generate a new dungeon attached to a specific `Doorway` component that exists in the scene. AttachToSpecificDoorway.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-1) public class AttachToSpecificDoorway : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-3) // The dungeon generator to use for generating the new dungeon. Set in inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-4) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-5) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-6) // The existing doorway component to attach to. Set in inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-7) public Doorway SpecificDoorway; [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-8) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-10) public void GenerateAttached() [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-12) RuntimeDungeon.Generator.AttachmentSettings = new DungeonAttachmentSettings(SpecificDoorway); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-13) RuntimeDungeon.Generate(); [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-14) } [](https://www.aegongames.com/dungen-documentation/advanced-features/attached-dungeons/#__codelineno-4-15) }` Back to top --- # Tile Connection Rules - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#advanced-features-tile-connection-rules) Advanced Features: Tile Connection Rules ======================================== By default, DunGen tries to connect any two compatible [Doorways](https://www.aegongames.com/dungen-documentation/getting-started/1-creating-tiles/) that line up correctly. However, sometimes you need more control. You might want to prevent certain types of rooms from connecting directly (like two dead-end corridors) or enforce specific connection patterns (like ensuring puzzle rooms only connect to main halls). DunGen provides **Tile Connection Rules** to achieve this level of control, offering two primary methods: 1. **Tag-Based Rules (Inspector):** A simple, visual way to define rules based on tags you assign to your tiles. Configured in the [Dungeon Flow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/) asset. 2. **Code-Based Rules (Advanced):** Allows you to write custom C# logic for complex connection scenarios, providing fine-grained control based on tile properties, doorway types, or even game state. * * * Method 1: Tag-Based Rules (Inspector) ------------------------------------- This method uses DunGen's built-in tag system. You define custom tags, assign them to your [Tile](https://www.aegongames.com/dungen-documentation/core-concepts/tiles/) prefabs, and then set rules in the Dungeon Flow asset based on pairings of these tags. **Step 1: Define Tags** [![Tags Window](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/tags-window.png)](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/tags-window.png) * First, you need to create the tags you want to use (e.g., "Room", "Corridor", "Puzzle", "Secret"). * Open the DunGen Tag Editor window via the Unity menu: `Window > DunGen > Tags`. * Click "+ Add Tag" to create new tags. Give them meaningful names. DunGen Tags vs. Unity Tags These are DunGen-specific tags and are separate from Unity's built-in GameObject tags. **Step 2: Assign Tags to Tiles** * Select your Tile prefab in the Project view. * Ensure it has a `Tile` component (DunGen adds one automatically if needed, or add it manually: `Add Component > DunGen > Tile`). * At the bottom of the `Tile` component inspector, find the **Tags** list. * Click the '+' button to add a tag slot, then select the desired tag from the dropdown menu. * A single tile can have multiple tags assigned to it. **Step 3: Configure Rules in Dungeon Flow** * Select your `Dungeon Flow` asset in the Project view. * Find the **Tile Connection Rules** section at the bottom of the Inspector. * **Mode:** Choose how the rules are applied: * `Accept`: Tiles are **only allowed** to connect if **both** tiles have a tag that matches **one of the defined Tag Pairs** below. If a potential connection doesn't match any pair, it's rejected. * `Reject`: Tiles are **always allowed** to connect **unless** **both** tiles have a tag that matches **one of the defined Tag Pairs** below. If a potential connection matches a pair, it's rejected. * **Tag Pairs:** This list defines the specific tag combinations the `Mode` setting acts upon. * Click the '+' button to add a new pair. * Use the dropdowns to select the two tags for the pair (e.g., Tag A <-> Tag B). The order doesn't matter (`Room <-> Corridor` is the same as `Corridor <-> Room`). [![Tags Window](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/tile-connection-rules.png)](https://www.aegongames.com/dungen-documentation/assets/images/advanced-features/tile-connection-rules.png) **Examples:** * **Scenario:** Only allow Rooms to connect to other Rooms or to Corridors. Corridors cannot connect directly to other Corridors. * **Mode:** `Accept` * **Tag Pairs:** * `Room` <-> `Room` * `Room` <-> `Corridor` * **Scenario:** Prevent Corridors from connecting directly to other Corridors, but allow all other connections. * **Mode:** `Reject` * **Tag Pairs:** * `Corridor` <-> `Corridor` * * * Method 2: Code-Based Rules (Advanced) ------------------------------------- For rules that go beyond simple tag matching (e.g., checking specific doorway properties, tile components, or dynamic conditions), you can implement custom logic in C#. This involves adding a delegate to a static list that DunGen checks during connection evaluation. **The Delegate and List:** * **List:** `DoorwayPairFinder.CustomConnectionRules` - A static list where you add your custom rule methods wrapped in a `TileConnectionRule` class. Rules are evaluated in order based on the priority of the rules. Higher priority rules are evaluated first. * **Delegate Signature:** Your method must match the `TileConnectionRule.TileConnectionDelegate` signature, which provides information about the potential connection: `[](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-0-1) // Your method needs to match this signature [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-0-2) ConnectionResult MyCustomRule(ProposedConnection connection);` **Return Values (`ConnectionRuleResult`):** Your delegate method **must** return one of the following enum values: * `ConnectionRuleResult.Allow`: Explicitly allows this connection, overriding any subsequent custom rules or default logic. * `ConnectionRuleResult.Deny`: Explicitly denies this connection, overriding any subsequent custom rules or default logic. * `ConnectionRuleResult.Passthrough`: Your rule makes no decision about this specific connection. DunGen will proceed to check the next rule in the `CustomConnectionRules` list, or fall back to the default connection logic if no custom rules make a decision. **Adding/Removing the Rule:** * **Add:** Use `DoorwayPairFinder.CustomConnectionRules.Add()`; typically in `Awake()` or `Start()`. * **Remove:** Crucially, you must remove your delegate when it's no longer needed (e.g., in `OnDestroy()` or `OnDisable()`) using `DoorwayPairFinder.CustomConnectionRules.Remove()`. Failure to do so can lead to errors if the delegate points to a destroyed object, or cause rules to persist unexpectedly between generations or scene loads. * * * ### Example Implementation Let's say we have a set of large Tiles that we've tagged "Large" using DunGen's tagging system. We want to allow connections between two large Tiles _only if_ both doorways use a specific "Large" `DoorwaySocket` asset, otherwise pass the decision to other rules. LargeTileConnectionRule.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-2) using DunGen.Tags; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-3) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-4)[](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-5) public class LargeTileConnectionRule : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-6) { [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-7) // This is the socket we want to use for large rooms. Set in the inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-8) public DoorwaySocket LargeSocket = null; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-9) // This is the tag we want to use to identify large rooms. Set in the inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-10) public Tag LargeRoomTag; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-11) // The priority of this rule. Higher numbers are evaluated first [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-12) public int Priority = 0; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-13) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-14) // Keep our rule instance around so we can remove it later [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-15) private TileConnectionRule rule; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-16) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-17) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-18) // Register our custom connection rule with the DoorwayPairFinder [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-19) private void OnEnable() [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-20) { [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-21) rule = new TileConnectionRule(CanTilesConnect, Priority); [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-22) DoorwayPairFinder.CustomConnectionRules.Add(rule); [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-23) } [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-24) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-25) // Unregister our custom connection rule when this object is disabled [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-26) private void OnDisable() [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-27) { [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-28) DoorwayPairFinder.CustomConnectionRules.Remove(rule); [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-29) rule = null; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-30) } [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-31) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-32) // Our custom delegate for checking if two tiles can connect [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-33) private TileConnectionRule.ConnectionResult CanTilesConnect(ProposedConnection connection) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-34) { [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-35) // Check if the two tiles are large. This is using DunGen's tag system, but we could [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-36) // have also checked the tile names, or looked for a specific component to identify large rooms [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-37) bool previousTileIsLarge = connection.PreviousTile.Tags.HasTag(LargeRoomTag); [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-38) bool nextTileIsLarge = connection.NextTile.Tags.HasTag(LargeRoomTag); [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-39) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-40) // Are we interested in this connection? [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-41) if (previousTileIsLarge && nextTileIsLarge) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-42) { [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-43) // If both sockets are large, allow the connection, otherwise deny [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-44) if (connection.PreviousDoorway.Socket == LargeSocket && connection.NextDoorway.Socket == LargeSocket) [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-45) return TileConnectionRule.ConnectionResult.Allow; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-46) else [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-47) return TileConnectionRule.ConnectionResult.Deny; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-48) } [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-49) // We're not interested in this connection, pass it on to be handled later [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-50) else [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-51) return TileConnectionRule.ConnectionResult.Passthrough; [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-52) } [](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/#__codelineno-1-53) }` * * * When to Use Which Method ------------------------ * **Tag-Based:** Ideal for simple, static rules based on broad categories of tiles (Room, Corridor, Theme A, Theme B). Easy to set up and visualize in the Inspector. * **Code-Based:** Necessary for complex logic involving specific component checks, doorway socket types, comparisons between tile properties, or conditions based on dynamic game state. Offers maximum flexibility but requires C# scripting. Using Tile Connection Rules effectively allows for more structured, predictable, and logically sound procedural dungeon layouts. Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/optimization/#optimization-overview) Optimization: Overview ====================== Procedural dungeon generation offers incredible flexibility and replayability, but generating complex layouts at runtime can sometimes impact performance. DunGen provides several built-in features and supports integrations to help you manage the performance cost and ensure a smooth player experience. This section covers key techniques for optimizing your DunGen-powered levels: * **[Built-in Culling](https://www.aegongames.com/dungen-documentation/optimization/culling/) :** Learn about DunGen's simple adjacency-based culling system, designed primarily for first-person interior environments. Understand its two modes (`Basic` and `Multi-Cam`) and their trade-offs for hiding unseen rooms. * **[Tile Pooling](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/) :** Discover how to use object pooling for your Tile prefabs. This can significantly reduce generation times caused by frequent instantiation and destruction of complex Tile GameObjects. Choosing the right optimization strategies depends on your game's specific requirements, target platform, and the complexity of your generated dungeons. Review the pages in this section to determine which techniques will provide the most benefit for your project. Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/pathfinding/#pathfinding-overview) Pathfinding: Overview ===================== Once your dungeon layout is generated by DunGen, a crucial next step for many games is enabling Artificial Intelligence (AI) agents, such as enemies or NPCs, to navigate the space effectively. This requires a **pathfinding system** to analyze the generated geometry and create navigation data (like a NavMesh or pathfinding graph). DunGen itself focuses solely on generating the dungeon's layout and structure; it **does not include its own pathfinding logic**. However, since the dungeon is created dynamically at runtime, static pathfinding data baked in the editor won't work. The navigation data needs to be generated or updated _after_ the DunGen layout is complete. DunGen addresses this by providing **Integration Adapters**. These are components you add alongside your `Runtime Dungeon` component. They hook into DunGen's [post-processing](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) phase and automatically trigger the necessary actions in your chosen pathfinding system (like baking a NavMesh or scanning a graph) once the dungeon geometry is finalized. * * * Supported Pathfinding Systems ----------------------------- DunGen comes with built-in adapters for several popular pathfinding solutions: * **[Unity NavMesh Components](https://www.aegongames.com/dungen-documentation/pathfinding/unity-navmesh/) :** Integration with Unity's modern, component-based NavMesh system (requires separate package installation from Unity). Supports runtime baking and linking across tiles. Includes a 2D variant. * **[A\* Pathfinding Project Pro](https://www.aegongames.com/dungen-documentation/pathfinding/astar-pathfinding/) :** Support for the Recast NavMesh in Aron Granberg's powerful third-party pathfinding asset. Enables runtime graph scanning after generation. * * * Custom Integrations ------------------- If you are using a different pathfinding system not listed above, you can create your own integration: * **[Custom Adapters](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/) :** Learn how to write your own adapter script by inheriting from DunGen's `BaseAdapter` class. This allows you to trigger any custom logic needed by your pathfinding solution during DunGen's post-processing phase. * * * Handling Doors -------------- A common requirement is handling doors that open and close, dynamically changing path availability. The specific integration pages detail how each adapter typically handles doors, often relying on DunGen's built-in [Door](https://www.aegongames.com/dungen-documentation/advanced-features/doors/) component to toggle walkability in the pathfinding data. * * * Please navigate to the page corresponding to the pathfinding system you are using in your project for specific setup instructions and details. Back to top --- # Built-in Culling - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/optimization/culling/#optimization-built-in-culling) Optimization: Built-in Culling ============================== DunGen includes a basic, built-in visibility culling system designed primarily for optimizing **interior dungeons viewed from a first-person (or over the shoulder third-person) perspective**. It works particularly well when doorways have doors that automatically close behind the player. Use Case Specific This built-in solution is quite specific and **may not be suitable for all game types**, such as top-down games. It relies on a simple adjacency check rather than true camera frustum culling. * * * How it Works ------------ The system determines which Tiles should be _visible_ based on simple rules: 1. **Player's Location:** The Tile the player (or target camera/object) is currently inside is always considered visible. 2. **Adjacency:** Tiles directly connected to the player's current Tile are considered visible. This check can extend outwards to neighbours of neighbours, up to a configurable depth (`Adjacent Tile Depth`). 3. **Closed Doors (Optional):** If enabled (`Cull Behind Closed Doors`), tiles that would otherwise be visible via adjacency are hidden (culled) if the doorway connecting them to an already visible tile is blocked by a **closed** `Door` component. Any Tile _not_ considered visible by these rules will have its Renderers temporarily disabled, preventing them from being drawn by the camera. * * * Enabling Culling ---------------- To use the built-in culling: 1. Select the **Camera** GameObject you want the culling to apply to in your scene. 2. Add one of the following DunGen culling components to it: * `Adjacent Room Culling` * `Adjacent Room Culling (Multi-Cam)` * * * Choosing the Right Component ---------------------------- There are two versions of the component, each with trade-offs: * **`Adjacent Room Culling` (Basic):** * **Pros:** Very efficient, minimal performance overhead. * **Cons:** * Only functions correctly for the **single camera** it's attached to. Results viewed from the Scene view or other cameras may appear incorrect. * It directly modifies the enabled state of Renderers and **leaves them in their culled state**. This means any other script trying to control renderer visibility might conflict or have its changes overwritten. * **`Adjacent Room Culling (Multi-Cam)`:** * **Pros:** * Works correctly with **multiple cameras** viewing the scene. * Properly **restores the original enabled state** of renderers after the camera finishes rendering, preventing conflicts with other scripts. * **Cons:** Significantly more performance-intensive than the basic version due to the state management overhead per frame. Which to Choose? * Use **`Adjacent Room Culling` (Basic)** if you only have one main game camera, performance is critical, and you don't have other systems managing renderer visibility. * Use **`Adjacent Room Culling (Multi-Cam)`** if you need multi-camera support (like spectator cameras, mini-maps, split-screen) or if you need to ensure renderer states are preserved for other game systems. * * * Component Settings ------------------ Both culling components share the same settings: * **`Adjacent Tile Depth`:** * Controls how many steps away from the player's current tile are considered visible. * `0`: Only the tile the player is currently in is visible. * `1`: The current tile and all directly adjacent tiles are visible. * `2`: The current tile, its neighbours, and _their_ neighbours are visible, and so on. * Higher values show more of the dungeon but reduce the effectiveness of the culling. * **`Cull Behind Closed Doors`:** * If checked, visibility checks will be blocked by doorways that have a `Door` component whose `IsOpen` property is `false`. * This requires that your door prefabs (used as [Connectors in Doorways](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) or via the [Lock & Key system](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) ) have a script that correctly manages the `Door` component and its `IsOpen` state. See the [Doors](https://www.aegongames.com/dungen-documentation/advanced-features/doors/) page for more details on the `Door` component. * **`Target Override`:** * An optional `Transform` component. By default, the culling system uses the position of the camera it's attached to for visibility checks. * If your player character controller is physically separate from the camera object, you can drag the player's root Transform here. The system will then use the `Target Override` object's position to determine the "current tile" instead of the camera's position. * * * Alternatives & Integration -------------------------- If the built-in culling doesn't meet your needs, consider: * **Third-Party Assets:** Solutions like [SECTR](https://www.aegongames.com/dungen-documentation/integrations/sectr/) (which has direct DunGen integration) offer portal-based culling. * **Custom Integration:** You can integrate other culling systems by creating a custom adapter class derived from `DunGen.Adapters.CullingAdapter` and implementing the `PrepareForCulling` method. DunGen will execute this as part of its [post-processing](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) steps. Back to top --- # DunGen Character Component - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#advanced-features-dungen-character-component) Advanced Features: DunGen Character Component ============================================= The **DunGen Character** component is a simple helper utility provided with DunGen that makes it easy to detect when a specific GameObject (like your player character or an important NPC) moves from one generated Tile to another. * * * What it Does ------------ * It monitors the Tile that the GameObject it's attached to currently occupies. * When the GameObject enters a _different_ Tile's bounds, it fires an event. * This requires the GameObject to have a **Collider** component attached. * It relies on the **"Trigger Placement"** option being **enabled** on the [Runtime Dungeon Generator](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-generator/) , as it uses these trigger volumes to detect transitions. It has **no configurable settings** in the Inspector – its sole purpose is to provide this transition event via code. * * * How to Use It ------------- 1. **Add the Component:** Attach the `DunGen Character` component to the GameObject you want to track (e.g., your player character). You can add it via the menu: `Add Component > DunGen > Character`. Ensure this GameObject also has a `Collider` component. 2. **Enable Tile Triggers:** Make sure the `Trigger Placement` mode is set to either **3D** or **2D** (depending on your dungeon's perspective) on your `Runtime Dungeon` component in the scene. Set the `Trigger Layer` appropriately if needed. 3. **Subscribe to the Event:** In another script (e.g., your player controller or a UI manager), get a reference to the `DunGenCharacter` component and subscribe to its `OnTileChanged` event. **Example Script:** PlayerTileTracker.cs `[](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-2) using DunGen; // Required for DunGenCharacter, Tile [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-4) public class PlayerTileTracker : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-5) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-6) private DungenCharacter characterComponent; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-7) private Tile currentTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-8) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-9) private void Start() [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-10) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-11) // Get the DunGenCharacter component attached to the same GameObject [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-12) characterComponent = GetComponent(); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-13) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-14) if (characterComponent == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-15) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-16) Debug.LogError("DungenCharacter component not found on this GameObject!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-17) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-18) } [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-19) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-20) // Subscribe to the tile changed event [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-21) // The 'OnPlayerTileChanged' method below will be called when the event fires [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-22) characterComponent.OnTileChanged += OnPlayerTileChanged; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-23) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-24) // Optional: Get the initial tile the character starts in [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-25) currentTile = characterComponent.CurrentTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-26) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-27) if (currentTile != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-28) Debug.Log($"Player started in Tile: {currentTile.name}"); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-29) } [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-30) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-31) private void OnDestroy() [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-32) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-33) // IMPORTANT: Always unsubscribe from events when the listener is destroyed [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-34) if (characterComponent != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-35) characterComponent.OnTileChanged -= OnPlayerTileChanged; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-36) } [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-37) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-38) // This method signature matches the event delegate [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-39) // It will be executed whenever the character enters a new tile trigger [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-40) private void OnPlayerTileChanged(DungenCharacter character, Tile previousTile, Tile newTile) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-41) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-42) // Store the new current tile [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-43) currentTile = newTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-44) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-45) // Log the transition [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-46) string prevTileName = (previousTile != null) ? previousTile.name : "None"; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-47) string newTileName = (newTile != null) ? newTile.name : "None"; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-48) Debug.Log($"Player moved from Tile '{prevTileName}' to Tile '{newTileName}'"); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-49) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-50) // --- Add your custom logic here --- [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-51) // UpdateMinimap(newTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-52) // TriggerRoomSpecificAmbience(newTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-53) // LoadResourcesForTile(newTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-54) // UnloadResourcesForTile(previousTile); [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-55) } [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-56) [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-57) // Example method you might call from elsewhere [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-58) public Tile GetCurrentTile() [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-59) { [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-60) return currentTile; [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-61) } [](https://www.aegongames.com/dungen-documentation/advanced-features/character-component/#__codelineno-0-62) }` **Event Handler Parameters:** * `DunGenCharacter character`: A reference to the `DunGenCharacter` component that triggered the event (useful if you have multiple tracked characters sharing the same handler). * `Tile previousTile`: The `Tile` the character was in _before_ the transition. Can be `null` if this is the first tile entered. * `Tile newTile`: The `Tile` the character has just entered. Can be `null` if the character exits all tile triggers. Use Cases --------- * **Minimap Updates:** Highlight the current room/tile on a minimap UI. * **Environment Effects:** Change lighting, ambient sounds, or particle effects based on the current tile the player is in. * **Resource Streaming:** Trigger loading/unloading of assets specific to the entered/exited tiles (if using an asset streaming system). * **AI Behavior:** Notify AI agents about the player's current tile location. * **Debugging:** Log tile transitions to help diagnose generation or gameplay issues. The `DunGen Character` component provides a convenient, event-driven way to react to character movement within your generated dungeons without needing to manually manage trigger collisions yourself. Remember the prerequisites: a Collider on the tracked object and "Trigger Placement" enabled on the generator. Back to top --- # Custom Post-Processing - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#advanced-features-custom-post-processing-steps) Advanced Features: Custom Post-Processing Steps =============================================== DunGen's generation process involves several stages: creating the main path, adding branches, placing props, handling the lock & key system, etc. Sometimes, you need to inject your own custom logic _during_ this process, specifically after the main dungeon layout (`Dungeon` data structure) exists but before generation is fully marked as complete. This is useful for: * Integrating third-party systems (like pathfinding baking or custom culling setups) that need the final level geometry. * Running complex analysis or modification routines on the generated `Dungeon` data. * Implementing custom prop placement logic that depends on the overall dungeon structure. * Performing tasks that need to happen _after_ DunGen's built-in post-processing (like lock/key placement) but _before_ the final `GenerationStatus.Complete` event fires. DunGen offers two ways to add your custom post-processing logic: 1. **Registering Steps via Code:** Use the `RegisterPostProcessStep` method on the `DungeonGenerator` for fine-grained control. 2. **Creating Custom Adapters:** Derive a component from `BaseAdapter` for a more component-based approach, often used for integrations. * * * Method 1: Registering Steps via Code (`RegisterPostProcessStep`) ---------------------------------------------------------------- This method allows you to dynamically register a C# method to be called during the post-processing phase. **How it Works:** 1. Get a reference to your `DungeonGenerator` instance. 2. Call the `generator.RegisterPostProcessStep()` method, providing your callback method and configuration options. 3. DunGen will execute your callback method at the appropriate time during its post-processing phase. **The Method Signature:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-0-1) void RegisterPostProcessStep(Action postProcessCallback, int priority, PostProcessPhase phase);` * **`Action postProcessCallback`:** This is your custom method (or lambda expression) that will be executed. It receives the `DungeonGenerator` instance as an argument, allowing you to access the generated dungeon data via `generator.CurrentDungeon`. * **`int priority`:** Determines the execution order _within_ a specific phase. **Higher priority numbers execute first.** Steps with the same priority have an undefined execution order relative to each other. DunGen's built-in steps (like lock/key placement) also have priorities. * **`PostProcessPhase phase`:** An enum specifying _when_ your step should run relative to DunGen's internal post-processing: * `PostProcessPhase.BeforeBuiltIn`: Your step runs _before_ DunGen handles its standard post-processing (Locks, Keys, Props, etc). * `PostProcessPhase.AfterBuiltIn`: Your step runs _after_ DunGen handles its standard post-processing. **Example:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-1) public class MyCustomPostProcessor : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-3) // Assign your Runtime Dungeon component in the inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-4) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-5) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-6) private void Start() [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-7) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-8) if (RuntimeDungeon == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-9) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-10) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-11) // Register our custom method to run AFTER DunGen's built-in steps, with priority 0 [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-12) RuntimeDungeon.Generator.RegisterPostProcessStep(MyCustomPostProcessLogic, 0, PostProcessPhase.AfterBuiltIn); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-13) } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-14) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-15) private void OnDestroy() [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-16) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-17) if (RuntimeDungeon == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-18) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-19) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-20) // Unregister our custom method [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-21) RuntimeDungeon.Generator.UnregisterPostProcessStep(MyCustomPostProcessLogic); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-22) } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-23) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-24) // This is the method that gets called by DunGen [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-25) private void MyCustomPostProcessLogic(DungeonGenerator generator) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-26) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-27) Debug.Log("Running custom post-process step!"); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-28) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-29) // Access the generated dungeon data [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-30) Dungeon dungeon = generator.CurrentDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-31) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-32) // Perform your custom logic here [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-33) Debug.Log($"Dungeon has {dungeon.AllTiles.Count} tiles."); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-34) } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-1-35) }` **Use Cases:** Ideal for one-off post-processing tasks defined in specific scripts, or when you need precise control over execution order relative to DunGen's built-in steps. * * * Method 2: Creating Custom Adapters (`BaseAdapter`) -------------------------------------------------- This approach is more component-oriented and is the standard way DunGen integrates systems like Pathfinding and Culling. You create a new script that inherits from `DunGen.Adapters.BaseAdapter`. **How it Works:** 1. Create a new C# script. 2. Make it inherit from `DunGen.Adapters.BaseAdapter`. 3. Override the abstract `Run(DungeonGenerator generator)` method. This is where your custom logic goes. 4. Attach this new component script to the **same GameObject** that has the `RuntimeDungeon` component. 5. DunGen will automatically find all `BaseAdapter` components on that GameObject and execute their `Run` methods during the post-processing phase. **Adapter Properties:** * **`Priority` (Inspector Field):** Inherited from `BaseAdapter`. This integer value controls the execution order of all post-processing steps within the same phase. **Higher priority adapters run first.** Execution Phase Adapters derived from `BaseAdapter` run _after_ DunGen's built-in post-processing steps, similar to `PostProcessPhase.AfterBuiltIn`. **Example:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-3) using DunGen.Adapters; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-4)[](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-5) // Attach this component to the same GameObject as RuntimeDungeon [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-6) public class MyCustomAdapter : BaseAdapter [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-7) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-8) protected override void Run(DungeonGenerator generator) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-9) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-10) Debug.Log($"Running MyCustomAdapter (Priority: {Priority})"); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-11) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-12) Dungeon dungeon = generator.CurrentDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-13) if (dungeon == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-14) { [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-15) Debug.LogError("Dungeon data is null in custom adapter!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-16) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-17) } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-18) [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-19) // --- Add custom logic here --- [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-20) Debug.Log($"Adapter processing dungeon with {dungeon.AllTiles.Count} tiles."); [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-21) // Example: Find all objects with a specific tag and activate them [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-22) // foreach(var tile in dungeon.AllTiles) { ... } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-23) } [](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/#__codelineno-2-24) }` **Use Cases:** Excellent for creating reusable integration components (like the built-in pathfinding/culling adapters), especially when the logic might need configuration via Inspector fields on the component itself. Easier to manage as self-contained units. * * * Choosing the Right Method ------------------------- * **`RegisterPostProcessStep`:** * Use when you need very fine control over execution order relative to DunGen's internal steps (`BeforeBuiltIn` vs. `AfterBuiltIn`). * Use when the logic is part of a script that isn't naturally attached to the `RuntimeDungeon` GameObject. * Use when you need to dynamically add/remove steps based on runtime conditions. * **`BaseAdapter`:** * Use for creating self-contained, reusable integration components (preferred for integrations like pathfinding, culling, etc.). * Use when you want to configure the step via the Inspector (add public fields to your adapter). * Generally simpler setup if you just need logic to run _after_ the main generation and built-in steps. Ordering is primarily relative to other adapters. Custom post-processing provides a vital hook for tailoring the generated dungeon and integrating it fully with your game systems. Back to top --- # Runtime Events & Code Execution - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#advanced-features-runtime-events-code-execution) Advanced Features: Runtime Events & Code Execution ================================================== After DunGen has finished generating the dungeon layout, placing tiles, handling props, and potentially running integrations like pathfinding, you'll often need to execute your own custom game logic. This could involve: * Spawning the player character at the start tile. * Initializing enemies or interactive objects placed within tile prefabs. * Activating global game systems that depend on the dungeon layout. * Fading in from a loading screen. DunGen provides two primary mechanisms to hook into the generation process and run your code once the dungeon is ready: 1. **On Specific Objects:** Implement an interface (`IDungeonCompleteReceiver`) on components attached to GameObjects _within_ your Tile prefabs. 2. **Globally:** Listen to completion or status change events directly from the `DungeonGenerator` instance. * * * Method 1: On Objects Inside the Dungeon (IDungeonCompleteReceiver) ------------------------------------------------------------------ This method is ideal when you want logic to run that is specific to a particular GameObject or prefab placed as part of the dungeon. **How it Works:** 1. Create a C# script. 2. Implement the `DunGen.IDungeonCompleteReceiver` interface in your script. 3. This interface requires you to implement one method: `void OnDungeonComplete(Dungeon dungeon)`. 4. Attach this script component to a GameObject that is **part of one of your Tile prefabs**. 5. After DunGen successfully generates the _entire_ dungeon layout, it will search all GameObjects within the final layout for components that implement `IDungeonCompleteReceiver` and call their `OnDungeonComplete` method. **Parameters:** * `Dungeon dungeon`: Provides access to the data structure representing the completed dungeon layout (containing information about tiles, doorways, paths, etc.). **Example: Spawning an Item or Enemy within a Tile** `[](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-4) // Attach this script to a GameObject inside one of your Tile prefabs [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-5) public class PostGenerationSpawner : MonoBehaviour, IDungeonCompleteReceiver [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-6) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-7) // Assign the prefab to spawn in the Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-8) public GameObject PrefabToSpawn; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-10) public void OnDungeonComplete(Dungeon dungeon) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-12) // Check if we actually have a prefab assigned [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-13) if (PrefabToSpawn == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-14) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-15) Debug.LogWarning("PrefabToSpawn is not set!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-16) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-17) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-18) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-19) Debug.Log($"Dungeon complete! Spawning '{PrefabToSpawn.name}' at {transform.position}", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-20) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-21) // Instantiate the prefab at this GameObject's position and rotation [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-22) // Parent it to this object's parent (likely the Tile root) for organisation [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-23) // NOTE: If you're using Tile pooling, you will need to clean up the spawned objects manually [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-24) GameObject instance = Instantiate(PrefabToSpawn, transform.position, transform.rotation, transform.parent); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-25) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-26) // Optional: You could add logic here to initialize the spawned object [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-27) // EnemyController enemy = instance.GetComponent(); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-28) // if(enemy != null) { enemy.Initialize(); } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-29) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-0-30) }` **Use Cases:** * Activating specific logic within a room once the whole dungeon is ready. * Spawning enemies or items at designated locations within tiles. * Initializing puzzle elements placed inside prefabs. * * * Method 2: Globally via Generator Events --------------------------------------- This method is suitable when you need to run logic that relates to the dungeon generation process as a whole, rather than a specific object within it. You subscribe to an event on the `DungeonGenerator`. **How it Works:** 1. Get a reference to your `RuntimeDungeon` component and its underlying `DungeonGenerator` instance. 2. The `DungeonGenerator` has a delegate/event called `OnGenerationComplete`. 3. Create a method in your script that matches the required signature: `void OnGenerationComplete(DungeonGenerator generator, GenerationStatus status)` 4. Subscribe your method to the `OnGenerationComplete` event (using +=). 5. Crucially, remember to unsubscribe from the event (using -=) when your listener object is destroyed or disabled to prevent errors. **Parameters:** * `DungeonGenerator generator:` The instance of the generator that fired the event. **Example: Spawning the Player After Dungeon Completion** `[](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-1) public class GlobalDungeonCompleteListener : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-2) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-3) // Assign your Runtime Dungeon in the Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-4) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-5) // Assign your player prefab in the Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-6) public GameObject PlayerPrefab; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-7) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-8) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-9) private void Start() [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-10) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-11) if (RuntimeDungeon == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-12) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-13) Debug.LogError("RuntimeDungeon is not assigned!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-14) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-15) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-16) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-17) var generator = RuntimeDungeon.Generator; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-18) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-19) // Subscribe to the event [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-20) generator.OnGenerationComplete += HandleDungeonCompletion; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-21) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-22) // Optional: If generation might already be complete before Start runs [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-23) // (e.g., if GenerateOnStart was true), check current status. [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-24) if (generator.Status == GenerationStatus.Complete) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-25) HandleDungeonCompletion(generator); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-26) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-27) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-28) void OnDestroy() [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-29) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-30) // IMPORTANT: Unsubscribe when this object is destroyed [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-31) if (RuntimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-32) RuntimeDungeon.Generator.OnGenerationComplete -= HandleDungeonCompletion; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-33) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-34) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-35) private void HandleDungeonCompletion(DungeonGenerator generator) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-36) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-37) Debug.Log("Dungeon Generation Complete! Spawning Player..."); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-38) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-39) if (PlayerPrefab == null) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-40) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-41) Debug.LogError("Player Prefab is not assigned!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-42) return; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-43) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-44) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-45) // Get the start tile location from the generated dungeon data [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-46) if (generator.CurrentDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-47) { [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-48) var startTile = generator.CurrentDungeon.MainPathTiles[0]; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-49) Vector3 spawnPosition = startTile.transform.position; [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-50) // You might want to offset this slightly or use a specific spawn point transform within the start tile [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-51) Instantiate(PlayerPrefab, spawnPosition, Quaternion.identity); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-52) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-53) else [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-54) Debug.LogError("Could not find generated dungeon to spawn player!", this); [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-55) } [](https://www.aegongames.com/dungen-documentation/advanced-features/runtime-events/#__codelineno-1-56) }` **Use Cases:** * Spawning the player character. * Initializing global managers or systems after the level is built. * Signaling that loading is complete and fading in the game view. Choosing the Right Method ------------------------- * Use `IDungeonCompleteReceiver` for logic tightly coupled to specific prefabs or locations within the dungeon. * Use the `OnGenerationComplete` event for global actions that need to happen once the entire dungeon generation process is finished. Back to top --- # Tile Pooling - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#optimization-tile-pooling) Optimization: Tile Pooling ========================== Important Consideration Enabling Tile Pooling requires careful management of object states within your Tiles. Objects might persist in an altered state (e.g., an opened chest) when a Tile is reused. See the [Managing State](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#managing-state) section for more details. What is Tile Pooling? --------------------- By default, when a Tile is no longer needed, it is simply destroyed. By contrast, with Tile Pooling enabled, Tiles are instead disabled and returned to the pool when they are no longer needed. This allows them to be reused later, avoiding costly instantiation of new Tile GameObjects. As you can see from the charts below, enabling Tile Pooling significantly speeds up dungeon generation, reducing time spent on instantiating tiles by as much as 70%. [![Tile Pooling Performance - Basic Sample](https://www.aegongames.com/dungen-documentation/assets/images/optimization/pooling-performance-basic.png)](https://www.aegongames.com/dungen-documentation/assets/images/optimization/pooling-performance-basic.png) [![Tile Pooling Performance - Dungeon Crawler Sample](https://www.aegongames.com/dungen-documentation/assets/images/optimization/pooling-performance-dungeon-crawler.png)](https://www.aegongames.com/dungen-documentation/assets/images/optimization/pooling-performance-dungeon-crawler.png) Note Tile Pooling will not improve the generation speed of the first dungeon you generate, as there will be no Tiles in the pool at that point. See the [Pre-Warming the Pool](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#pre-warming-the-pool) section below to see how pooling can be used to improve first-run dungeons as well. * * * Enabling Tile Pooling --------------------- Tile Pooling can be enabled from the project settings (`Edit > Project Settings... > DunGen`). Under the 'Optimization' section, check the **`Enable Tile Pooling`** checkbox. That's it! DunGen will now reuse old tiles. * * * Pre-Warming the Pool -------------------- By default, Tile Pooling will only improve performance in subsequent dungeon generations, as there are no tiles yet in the pool for the initial generation. We can solve this by pre-warming the pool with some tiles that we will instantiate in the editor and save alongside the scene. We do this with the `Tile Pool Preloader` component. ### Creating the `Tile Pool Preloader` 1. Create a new GameObject in your scene 2. Add the `Tile Pool Preloader` component (`Add Component > DunGen > Pooling > Tile Pool Pre-loader`) ### Using the Pre-loader The main area of interest in the inspector is the 'Tile Pool Entries' list. New entries can be added to the list by simply dragging DunGen assets (`Tile`, `TileSet`, `Archetype`, or `DungeonFlow`) from your project view onto the list. All Tiles in the asset will be extracted and put into the list. **Tile Pool Entries** Each entry in the list has two components: * **Tile:** The Tile prefab we want to add to the pool * **Count:** The number of instances we want to seed the pool with **Utilities** For ease of use, there is a 'List Controls' foldout at the top of the inspector which includes some tools for speeding up the process. * **Clear List (Button):** Clears all entries from the list. * **Set All Counts:** Type in a number and press the **Apply** button and the instance count for all tiles in the list will be set all at once. **Creating Instances** Clicking the **Refresh Instances** button will prompt you to confirm that you would like to instantiate the specified number of tiles, once you accept, it will update the Tile instances spawned inside your scene to match the chosen instance counts. Pressing the **Clear Instances** button will destroy all spawned Tile instances. How Many Tiles Should I Pre-load? The ideal number depends on your project's specific needs. A good starting point is to estimate the maximum number of each Tile type you expect to see in your largest possible dungeon configuration. Pre-loading enough to cover this means you might avoid runtime instantiation altogether, but will increase initial scene loading times and memory usage. Insufficient pre-loading means you still gain benefits but might occasionally instantiate new tiles at runtime if the pool runs dry. Experimentation is key to finding the right balance for your target platform and dungeon complexity. Now, when DunGen generates a new DunGen on this scene, it will automatically pull in all of the Tile instances created by the pre-loader and put them into the pool, ready for use immediately. * * * Managing State -------------- There is a major downside to enabling Tile Pooling to consider. Now that Tiles are reused, they will retain any changes made to them by the player. For example, if the player opens a treasure chest in the boss room, the next time that boss room is needed, the chest will still be open from before. This means that any stateful object will either need to be: * Spawned outside of your Tiles (ideally attached to the Dungeon root so it will be automatically cleaned up). * Have their state reset when the Tile it's in is returned to the pool. You can receive a callback on any object inside a Tile when its containing Tile is **taken from the pool (spawned)** or **returned to the pool (de-spawned)** by implementing the `ITileSpawnEventReceiver` interface. Implement the following functions: `[](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#__codelineno-0-1) // Called when the Tile instance containing this component is retrieved from the pool and placed in the dungeon [](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#__codelineno-0-2) void OnTileSpawned(Tile tile); [](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#__codelineno-0-4) // Called just before the Tile instance containing this component is disabled and returned to the pool [](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/#__codelineno-0-5) void OnTileDespawned(Tile tile);` Use `OnTileSpawned` or `OnTileDespawned` to reset the state of your interactive objects (e.g., close chests, reset enemy spawners, restore breakable objects) before the Tile is potentially reused. * * * Tile Pooling can be a powerful option for reducing dungeon generation times, but it requires a more thoughtful approach to designing Tiles with interactive elements. Back to top --- # A* Pathfinding Project Pro - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/pathfinding/astar-pathfinding/#pathfinding-a-pathfinding-project-pro) Pathfinding: A\* Pathfinding Project Pro ======================================== DunGen provides integration for Aron Granberg's powerful **A\* Pathfinding Project Pro** asset, allowing you to automatically generate or update pathfinding graphs at runtime after your dungeon layout is created. Third-Party Asset Required A\* Pathfinding Project Pro is a separate asset available on the Unity Asset Store and must be purchased and imported into your project. * * * Prerequisites ------------- Install **A\* Pathfinding Project Pro** into your Unity project. * * * Setup ----- 1. Ensure you have an **Astar Path** component configured somewhere in your scene (typically on a dedicated manager GameObject). You need to have at least one Recast graph type set up. Configure the basic settings of your graph (like agent size, collision masks, etc.) as needed _before_ runtime. 2. Locate the GameObject in your scene that has the **`Runtime Dungeon`** component attached. 3. Add the **`A* Pathfinding NavMesh Generator`** component to this **same** GameObject (`Add Component > DunGen > NavMesh > A* Pathfinding NavMesh Generator`). This adapter component will automatically run during DunGen's [post-processing phase](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) after the dungeon geometry is finalized. * * * Adapter Component Settings -------------------------- The specific settings on the `A* Pathfinding NavMesh Generator` component might vary slightly depending on DunGen and A\*PP versions, but they typically include: * **`Priority`:** Determines the order in which multiple DunGen adapters are run. Lower numbers run first. The default is usually sufficient. * **Settings for Door Handling:** Specific fields related to tags for open and closed doors (see [Handling Doors](https://www.aegongames.com/dungen-documentation/pathfinding/astar-pathfinding/#handling-doors) below). * * * Handling Doors -------------- A common requirement is making doors block pathfinding when closed and allow it when open. The recommended approach with A\*PP and DunGen relies on **Tags**: 1. **Create a Layer:** In Unity's Tag & Layer Manager (`Edit > Project Settings > Tags and Layers`), create a new physics layer specifically for your doors (e.g., "Doors"). 2. **Configure A\* Graph:** In your **Astar Path** component's graph settings (e.g., for your Recast Graph), find the collision testing or masking options. Ensure that the "Doors" layer you created is **excluded** from the mask used for building the graph. This prevents the graph from being built _under_ the physical space occupied by closed doors. 3. **Set Door Prefab Layer:** Make sure all door prefabs used by DunGen ([Connectors](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) , [Locked Doors](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) , etc.) are assigned to the "Doors" layer you created. 4. **Configure Adapter Tags:** In the **`A* Pathfinding NavMesh Generator`** component settings, assign the "Open Door" and "Closed Door" tags you created in A\*PP to the corresponding fields in the adapter. 5. **Configure AI Agents:** In your A\* agent scripts (like `AIPath`), configure the "Traversable Tags" to include your standard walkable tag(s) and the "Open Door" tag, but **exclude** the "Closed Door" tag. This setup ensures that the initial scan ignores closed doors, the adapter applies initial tags correctly, and door objects dynamically update path availability by changing tags, which your AI agents respect. * * * By using the `A* Pathfinding NavMesh Generator` adapter and correctly configuring layers and tags, you can effectively integrate A\* Pathfinding Project Pro with your DunGen-powered procedural dungeons. Back to top --- # Avoid Collisions With the Scene - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#advanced-features-avoiding-collisions-with-scene-objects) Advanced Features: Avoiding Collisions with Scene Objects ========================================================= By default, DunGen only checks for collisions between the Tiles it is currently placing within the _same_ generation process. It isn't inherently aware of other objects you might have manually placed in your scene (like important landmarks, puzzle elements, or structural pillars). This can lead to generated dungeons overlapping or intersecting with these crucial scene elements. DunGen provides two primary methods, implemented via code, to tell the generator about additional areas it should avoid colliding with. * * * Method 1: Additional Bounding Boxes ----------------------------------- This is the simpler approach for defining basic "keep-out" zones. You provide DunGen with a list of pre-defined `Bounds` objects representing volumes in world space that generated Tiles should not overlap. * **Concept:** Define one or more invisible, axis-aligned rectangular boxes around your important scene objects. DunGen will treat these boxes as obstacles during its collision checks. * **Implementation:** 1. You need access to the `DungeonGenerator` instance used by your `Runtime Dungeon` component. Typically, you get this in `Awake` or `Start` in a script attached to the same GameObject as the `Runtime Dungeon`. 2. The `DungeonGenerator` has a public property: `CollisionSettings`, which in turn has an `AdditionalCollisionBounds` property (a `List`). 3. Create new `Bounds` objects (defining their `center` and `size`) that encompass the areas you want to protect. 4. Add these `Bounds` objects to the `AdditionalCollisionBounds` list _before_ DunGen starts generating. * **Example Code:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-4) public class SceneCollisionSetup : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-5) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-6) // Optional: Assign important scene objects in the Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-7) // public Transform importantPillar; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-8) // public Collider importantStructureCollider; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-10) private void Awake() [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-11) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-12) // Get the Runtime Dungeon component (assuming this script is on the same GameObject) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-13) var runtimeDungeon = GetComponent(); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-14) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-15) if (runtimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-16) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-17) var collisionSettings = runtimeDungeon.Generator.CollisionSettings; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-18) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-19) // --- Example 1: Define a specific volume --- [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-20) Bounds forbiddenZone = new Bounds( [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-21) new Vector3(10, 0, 0), // Center of the zone [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-22) new Vector3(20, 10, 20) // Total size of the zone [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-23) ); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-24) collisionSettings.AdditionalCollisionBounds.Add(forbiddenZone); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-25) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-26) // --- Example 2: Use the bounds of an existing Collider --- [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-27) // if (importantStructureCollider != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-28) // { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-29) // collisionSettings.AdditionalCollisionBounds.Add(importantStructureCollider.bounds); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-30) // } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-31) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-32) Debug.Log("Added custom collision bounds to DunGen Generator."); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-33) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-34) else [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-35) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-36) Debug.LogError("RuntimeDungeon or its Generator not found!"); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-37) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-38) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-0-39) }` * **Limitations:** This method only works with axis-aligned bounding boxes. It might protect a larger area than necessary for complex or rotated objects. * * * Method 2: Custom Collision Function (Predicate) ----------------------------------------------- For more complex collision logic or checking against specific objects without relying on simple bounding boxes, you can provide DunGen with a custom function (a predicate). * **Concept:** You define a function that DunGen calls _every time_ it considers placing a Tile. This function receives information about the potential Tile's bounds and returns `true` if the placement should be _prevented_ (collision detected) or `false` if the placement is _allowed_. * **Implementation:** 1. Access the `DungeonGenerator` instance as described in Method 1 and get its `CollisionSettings` property. 2. The `DungeonCollisionSettings` class has a public property: `AdditionalCollisionsPredicate`. This expects a delegate of type `AdditionalCollisionsDelegate`. 3. Create a function in your script that matches the required signature: `bool YourFunctionName(Bounds potentialTileBounds, bool isTileCollidingWithDungeon)`. 4. Assign your function to the `AdditionalCollisionsPredicate` property _before_ generation starts. * **Delegate Signature Explained:** * `Bounds potentialTileBounds`: The world-space AABB of the Tile that DunGen is _considering_ placing. * `bool isTileCollidingWithDungeon`: A boolean indicating if DunGen's _internal_ checks have already detected a collision between this potential Tile and other Tiles _within the currently generating dungeon_. This is useful to avoid redundant checks or to allow your custom logic to override DunGen's internal check if needed (though usually you'll want to respect it). * **Return Value:** * `true`: Collision detected by your custom logic. Prevent placement. * `false`: No collision detected by your custom logic. Allow placement. * **Example Code:** `[](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-3)[](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-4) public class SceneCollisionSetupCustom : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-5) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-6) // Define which layers to check against in the Inspector [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-7) public LayerMask CollisionCheckLayer; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-8) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-9) private RuntimeDungeon runtimeDungeon; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-10) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-11) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-12) private void Awake() [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-13) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-14) runtimeDungeon = GetComponent(); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-15) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-16) if (runtimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-17) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-18) var collisionSettings = runtimeDungeon.Generator.CollisionSettings; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-19) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-20) collisionSettings.AdditionalCollisionsPredicate = ShouldTilePlacementBeBlocked; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-21) Debug.Log("Assigned custom collision predicate to DunGen Generator."); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-22) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-23) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-24) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-25) private void OnDestroy() [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-26) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-27) if (runtimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-28) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-29) var collisionSettings = runtimeDungeon.Generator.CollisionSettings; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-30) collisionSettings.AdditionalCollisionsPredicate = null; [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-31) Debug.Log("Removed custom collision predicate from DunGen Generator."); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-32) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-33) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-34) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-35) // Function matching the AdditionalCollisionsDelegate signature [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-36) private bool ShouldTilePlacementBeBlocked(Bounds potentialTileBounds, bool isTileCollidingWithDungeon) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-37) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-38) // 1. Respect DunGen's internal collision check first [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-39) if (isTileCollidingWithDungeon) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-40) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-41) return true; // Already colliding with another generated tile, definitely block. [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-42) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-43) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-44) // 2. Perform your custom check (e.g., check for overlap with specific layers) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-45) Collider[] overlaps = Physics.OverlapBox( [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-46) potentialTileBounds.center, [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-47) potentialTileBounds.extents, // OverlapBox uses extents (half-size) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-48) Quaternion.identity, // AABBs are not rotated [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-49) CollisionCheckLayer // Check only against specified layers [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-50) ); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-51) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-52) // 3. Decide based on the custom check [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-53) if (overlaps.Length > 0) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-54) { [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-55) // Optional: Add more logic here, e.g., ignore triggers, check specific tags... [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-56) // For now, any overlap on the specified layer blocks placement. [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-57) // Debug.Log($"Custom collision detected for tile at {potentialTileBounds.center}"); [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-58) return true; // Found an object on the collision layer within the bounds, block placement. [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-59) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-60) [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-61) // 4. No collision found by DunGen or custom logic [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-62) return false; // Allow placement. [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-63) } [](https://www.aegongames.com/dungen-documentation/advanced-features/additional-collisions/#__codelineno-1-64) }` * **Flexibility:** This method is much more powerful. You can implement complex checks: query specific objects, use `Physics.OverlapBox`, `Physics.CheckSphere`, check tags, ignore triggers, etc. * * * Choosing a Method ----------------- * Use **Additional Bounding Boxes** for simple, rectangular keep-out zones around non-rotated objects. It's easier to set up. * Use the **Custom Collision Function** for more precise checks, handling complex shapes, checking against specific layers or tags, or implementing any custom collision logic your project requires. Remember to apply these settings in `Awake` or `Start` in a script that runs before the `Runtime Dungeon` component attempts to generate the dungeon (e.g., if generating on start). Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/integrations/#integrations-overview) Integrations : Overview ======================= DunGen is designed to work alongside other powerful tools from the Unity Asset Store to enhance your procedural generation workflow and improve runtime performance or usability. While pathfinding systems have their own dedicated section due to their complexity ([Pathfinding Overview](https://www.aegongames.com/dungen-documentation/pathfinding/) ), this section covers other specific third-party asset integrations provided directly with DunGen. These integrations often utilize DunGen's [Adapter system](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/) or specific hooks to automate setup or provide easier control. Included Integrations --------------------- Currently, DunGen offers built-in support for the following assets: * **[SECTR Portal Culling](https://www.aegongames.com/dungen-documentation/integrations/sectr/) :** Automatically generate SECTR portals and sectors based on your DunGen room layout. This leverages SECTR's powerful visibility culling to significantly improve rendering performance in complex dungeons by hiding rooms that are not visible to the camera. * **[PlayMaker Actions](https://www.aegongames.com/dungen-documentation/integrations/playmaker/) :** Provides custom PlayMaker actions allowing you to trigger DunGen generation and clearing processes directly from your PlayMaker Finite State Machines (FSMs), enabling visual scripting control over dungeon creation. Please refer to the specific pages linked above for detailed setup instructions and usage information for each integration. If you are using an asset not listed here, you may still be able to integrate it with DunGen by leveraging its runtime API or by creating a [Custom Adapter](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/) to run custom logic during DunGen's post-processing phase. Back to top --- # Unity NavMesh Components - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/pathfinding/unity-navmesh/#pathfinding-unity-navmesh-components) Pathfinding: Unity NavMesh Components ===================================== DunGen offers built-in integration with Unity's modern, component-based **NavMesh Components** system (package `com.unity.ai.navigation`). This allows you to automatically generate or utilize NavMesh data for your procedurally generated dungeons at runtime, enabling AI navigation. Separate Package Required Unity's NavMesh Components system is **not** included with the Unity Editor by default (as of writing). You must install it via the Unity Package Manager (`Window > Package Management > Package Manager`). Search for `AI Navigation` or add it by name: `com.unity.ai.navigation`. * * * Prerequisites ------------- Install the **NavMesh Components** package (`com.unity.ai.navigation`) into your Unity project using the Package Manager. * * * Setup ----- 1. Locate the GameObject in your scene that has the **`Runtime Dungeon`** component attached. 2. Add the **`Unity Nav Mesh Adapter`** component to this **same** GameObject (`Add Component > DunGen > NavMesh > Unity NavMesh Adapter`). This adapter will automatically run during DunGen's [post-processing phase](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) after the dungeon layout is generated. * * * Adapter Component Settings -------------------------- The `Unity Nav Mesh Adapter` component has several settings to control how NavMesh generation occurs: * **`Priority`:** Determines the order in which multiple DunGen adapters are run. Lower numbers run first. Usually, the default value is fine unless you have complex inter-adapter dependencies. * **`Runtime Bake Mode`:** This crucial setting defines _how_ the NavMesh data is generated or handled at runtime: * **`Pre-Baked Only`:** * **Requires:** You must add a `NavMeshSurface` component to _each_ of your Tile prefabs and bake them individually in the Editor beforehand. * **Functionality:** DunGen will **not** generate any new NavMesh data at runtime. It assumes the necessary data already exists on the tiles. This is the most performant runtime option as no baking occurs. Use `Link Rooms` (see below) to connect these separate surfaces. * **`Add If No Surface Exists`:** * **Functionality:** If a placed Tile prefab _doesn't_ already have a `NavMeshSurface`, the adapter will add one and bake it at runtime. Tiles that _do_ have a pre-baked surface are left untouched. * **Use Case:** Useful if you want to pre-bake complex tiles but have simpler tiles baked dynamically. * **`Always Re-bake`:** * **Functionality:** Ignores any existing `NavMeshSurface` components on Tile prefabs. Adds a new `NavMeshSurface` to _every_ placed Tile instance that doesn't already have, and bakes _every_ Tile's surface at runtime. * **`Full Dungeon Bake`:** * **Functionality:** Ignores any NavMesh data on individual tiles. After the _entire_ dungeon layout is generated, it adds a _single_, large `NavMeshSurface` component encompassing the whole dungeon and performs one bake operation. * **Pros:** Can result in a more seamless NavMesh, especially for complex layouts or large open areas within the dungeon. Simpler setup as you don't need surfaces on prefabs. * **Cons:** Can be significantly slower than other modes, especially for large dungeons, as the entire bake happens at once. * **`Link Rooms`:** * **Functionality:** If checked, DunGen will automatically place `NavMeshLink` components across connected doorways between adjacent Tiles. * **Purpose:** This is essential when using pre-baked NavMeshes (`Pre-Baked Only` mode) or tile-by-tile baking (`Add If No Surface Exists`, `Always Re-bake`) as it allows AI agents to pathfind _between_ the separate NavMesh surfaces of each tile. * **Ignored:** This setting has no effect in `Full Dungeon Bake` mode, as there's only one continuous surface. * **`Auto-Calculate Link Points`:** * If checked, DunGen will attempt to automatically calculate the start and end points of the link between rooms. If unchecked, the start and end points of the link will be a fixed distance from the doorway (see below). * **`Distance from Doorway`:** * Controls how far from the center of the doorway (on either side) the generated `NavMeshLink` starts and ends. Adjust this based on your agent size and doorway geometry. Only relevant if `Link Rooms` is checked. * **`Agent Types Link Info`:** * Allows you to configure `NavMeshLink` generation settings on a per-agent-type basis (Agent Types are defined in Unity's Navigation settings). Add entries to this list to customize link generation. * **`Agent Type`:** The specific agent type this link configuration applies to. * **`Area`:** The NavMesh Area type assigned to the generated link (e.g., "Walkable", "Jump"). This allows different agents to treat traversals differently. * Only relevant if `Link Rooms` is checked. * **`Disable When Door is Closed`:** * **Functionality:** If checked, the generated `NavMeshLink`'s enabled state will be controlled by the `IsOpen` property of the [Door Component](https://www.aegongames.com/dungen-documentation/advanced-features/doors/) found on any door prefab placed in the doorway. * **Requires:** Your door prefabs must have a script that correctly updates the `Door` component's `IsOpen` status when the door opens or closes. * **Purpose:** Allows doors to dynamically block or allow pathfinding routes. Only relevant if `Link Rooms` is checked. * **`Auto-Generate Surfaces`:** * **Visible Only:** This setting only appears when `Runtime Bake Mode` is set to `Full Dungeon Bake`. * **Functionality:** * If checked, the adapter automatically creates a default `NavMeshSurface` configuration for each Agent Type defined in your project settings during the full dungeon bake. * If unchecked, you must manually provide a list of pre-configured `NavMeshSurface` components (e.g., on the same GameObject as the adapter) that will be used for the full dungeon bake. This gives you more control over the baking settings (voxel size, agent radius, etc.). * * * Handling Doors -------------- As mentioned in the settings: 1. Ensure `Link Rooms` is checked (unless using `Full Dungeon Bake`). 2. Ensure `Disable When Door is Clos` is checked. 3. Your door prefabs (used as Connectors/Blockers or via Lock & Key) **must** have a script attached that includes a `Door` component and correctly sets its `IsOpen` property to `true` when the door is open and `false` when it's closed. DunGen will then automatically toggle the associated `NavMeshLink` component based on the door's state. * * * 2D NavMesh Integration ---------------------- DunGen also provides limited support for 2D NavMesh generation using Unity's NavMesh Components. Use the Correct Adapter For 2D projects, you must use the **`Unity NavMesh Adapter (2D)`** component _instead_ of the standard `Unity Nav Mesh Adapter`. The 2D adapter works similarly but specifically looks for the following components within your Tile prefabs to generate the NavMesh shape: * **`SpriteRenderer`:** Considers the sprite's mesh data. Uses the layers defined in the adapter's "Included Layers" setting to determine walkability (sprites on other layers are considered non-walkable). * **`Tilemap`:** Considers tiles based on their `Collider Type`: * `None`: Considered walkable. * `Sprite` or `Grid`: Considered non-walkable obstacles. * The shape is derived from the _tile's mesh_, not its collider shape. Other settings on the 2D adapter generally mirror the standard adapter where applicable. * * * By using the appropriate Unity NavMesh Adapter, you can seamlessly integrate robust pathfinding into your DunGen-generated levels. Choose the `Runtime Bake Mode` and configure linking options carefully based on your project's needs and performance targets. Back to top --- # SECTR Portal Culling - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/integrations/sectr/#integrations-sectr-portal-culling) Integrations: SECTR Portal Culling ================================== DunGen provides built-in integration with **SECTR**, a powerful portal-based visibility culling system available on the Unity Asset Store. This integration automatically generates SECTR Sectors and Portals based on your DunGen Tile layout, helping to significantly improve rendering performance by culling rooms (Sectors) that are not visible through doorways (Portals). Third-Party Asset Required SECTR is a separate asset available on the Unity Asset Store and must be purchased and imported into your project _before_ setting up this integration. * * * Prerequisites ------------- 1. Install **SECTR World Straming** into your Unity project from the Asset Store. 2. Ensure the DunGen integration scripts are available. If you haven't already, navigate to `Assets/DunGen/Integration/` in your Project view and double-click the `SECTR_VIS.unitypackage` file to extract its contents. * * * Setup ----- Setting up the integration is straightforward: 1. Locate the GameObject in your scene that has the **`Runtime Dungeon`** component attached. 2. Add the **`SECTR VIS Portal Culling Adapter`** component to this **same** GameObject (`Add Component > DunGen > Culling > SECTR VIS Portal Culling Adapter`). 3. Select your main **Player Camera** GameObject. 4. Add the **`SECTR Culling Camera`** component to your Player Camera (`Add Component > Procedural Worlds > SECTR > Vis > SECTR Culling Camera`). That's it! The DunGen adapter will now run automatically during the [post-processing phase](https://www.aegongames.com/dungen-documentation/advanced-features/post-processing/) after dungeon generation. * * * Adapter Component Settings -------------------------- The `SECTR VIS Portal Culling Adapter` has a few settings: * **`Priority`:** Determines the execution order if multiple DunGen adapters are present. Usually, the default (-1, often running after pathfinding) is suitable. * **`Directional Shadow Caster`:** (Optional) Assign your main directional light here if you want SECTR to manage shadow culling based on Sector visibility. * **`Extra Bounds`:** Allows you to add padding to the automatically calculated Sector bounds. * **`Cull Each Child`:** Determines SECTR should cull child Sectors individually or if culling is done based solely on the single Sector for the Tile. SECTR Documentation For detailed explanations of these SECTR-specific settings (`Directional Shadow Caster`, `Extra Bounds`, `Cull Each Child`), please refer to the official SECTR documentation. * * * Runtime Behaviour ----------------- Once set up: 1. DunGen generates the dungeon layout. 2. During post-processing, the `SECTR VIS Portal Culling Adapter` runs. 3. The adapter automatically creates: * A `SECTR Sector` component for each `Tile` instance in the dungeon. * A `SECTR Portal` component spanning each connected `Doorway` between Tiles. 4. The `SECTR Culling Camera` on your camera then uses this Sector and Portal information to perform visibility culling each frame. * * * Handling Doors -------------- To allow doors to dynamically open and close, affecting visibility: 1. Ensure your door prefabs (used as [Connectors](https://www.aegongames.com/dungen-documentation/getting-started/2-doorways/) or via the [Lock & Key system](https://www.aegongames.com/dungen-documentation/advanced-features/lock-key-system/) ) have a script attached that includes a `Door` component. 2. This script **must** correctly set the `Door` component's `IsOpen` property to `true` when the door is open and `false` when it's closed. The DunGen integration automatically configures the generated `SECTR Portal` components to check the `IsOpen` status of the associated `Door` component. When `IsOpen` is `false`, the portal will be closed, and SECTR VIS will cull the Sector behind it. When `true`, the portal opens, allowing SECTR VIS to potentially render the Sector beyond. * * * Using the SECTR VIS integration is an effective way to boost rendering performance in your DunGen-powered levels, especially in complex interior environments. Back to top --- # PlayMaker Actions - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/integrations/playmaker/#integrations-playmaker) Integrations: PlayMaker ======================= DunGen offers basic integration with Hutong Games' **PlayMaker**, a popular visual scripting tool for Unity. This allows you to control DunGen's dungeon generation process directly from your PlayMaker Finite State Machines (FSMs) without needing to write traditional C# code. Third-Party Asset Required PlayMaker is a separate asset available on the Unity Asset Store and must be purchased and imported into your project _before_ setting up this integration. * * * Setup ----- 1. Ensure PlayMaker is successfully installed and operational in your project. 2. Navigate to `Assets/DunGen/Integration/` in your Project view. 3. Double-click the **`PlayMaker.unitypackage`** file to import its contents into your project. Once imported, you should find new DunGen-specific actions available in the PlayMaker Action Browser. * * * Available PlayMaker Actions --------------------------- Currently, DunGen provides the following PlayMaker actions: * * * ### Generate * **Description:** Generates a new dungeon layout using the settings configured on an _existing_ `Runtime Dungeon` component in the scene. * **Usage:** * You **must** have a GameObject in your scene with a `Runtime Dungeon` component already set up (with a Dungeon Flow asset assigned, etc.). * In the PlayMaker action settings, specify the GameObject that contains this pre-configured `Runtime Dungeon` component. * This action is useful when you prefer to manage your main generation settings directly on a component in the scene hierarchy. * * * ### Generate with Settings * **Description:** Generates a new dungeon layout using settings specified _directly within the PlayMaker action itself_. * **Usage:** * Configure the desired settings (like the `Dungeon Flow` asset, randomization seed, etc.) within the action's properties in the PlayMaker Editor. * You do **not** necessarily need a pre-existing `Runtime Dungeon` component in the scene; if the specified target GameObject doesn't have one, this action can create one for you. * **Optional `Runtime Dungeon` Parameter:** You _can_ still specify a GameObject with an existing `Runtime Dungeon` component. If you do, the settings _from the action_ will be used primarily, but any settings on the component _not_ directly exposed in the PlayMaker action (like attached adapters, specific overrides, root object) will still be respected. * This action is useful for more self-contained generation logic within your FSM, requiring less initial scene setup. * * * ### Clear * **Description:** Removes/destroys a previously generated dungeon layout associated with a specific `Runtime Dungeon` component. * **Usage:** * Specify the GameObject that currently holds the `Runtime Dungeon` component whose generated dungeon you want to clear. * This is typically used before generating a new dungeon layout to clean up the old one, or when transitioning away from the level. * * * Basic Usage Example ------------------- You could create a simple FSM on a GameManager object: 1. **Start State:** Waits for a trigger (e.g., "Start Game" event). 2. **Generate Dungeon State:** Uses the `Generate` or `Generate with Settings` action to create the dungeon. Stores the GameObject containing the `Runtime Dungeon` component in a variable if needed for clearing later. 3. **Gameplay State:** The game proceeds. 4. **(Optional) Clear Dungeon State:** Triggered by an event (e.g., "Exit Level"). Uses the `Clear` action, referencing the stored GameObject variable, to remove the dungeon before loading a new scene. * * * By using these actions, you can integrate DunGen's procedural capabilities into your projects using PlayMaker's intuitive visual scripting interface. Back to top --- # Custom Adapters - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#pathfinding-custom-adapters) Pathfinding: Custom Adapters ============================ While DunGen provides built-in integration adapters for popular pathfinding solutions like Unity NavMesh Components and A\* Pathfinding Project Pro, you might be using a different system. DunGen offers a flexible way to integrate _any_ third-party system (including custom pathfinding solutions) by creating your own **Custom Adapter**. * * * What's an Adapter? ------------------ DunGen Adapters are C# script components that hook into the dungeon generation lifecycle, specifically during the **post-processing phase**. This phase occurs _after_ the main dungeon layout (Tiles and connections) has been generated and placed in the scene. By creating a script that inherits from DunGen's `NavMeshAdapter` class, you can execute your custom logic at the right time, allowing you to trigger actions in your chosen pathfinding system, such as: * Scanning or baking navigation data based on the generated geometry. * Placing specific pathfinding-related objects or markers. * Updating pathfinding graphs based on door states or other dynamic elements. * * * The `NavMeshAdapter` Class -------------------------- To create a custom adapter, your script must inherit from `DunGen.Adapters.NavMeshAdapter`. `[](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-1) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-2) using DunGen; [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-3) using DunGen.Adapters; [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-4)[](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-5) public class MyCustomPathfindingAdapter : NavMeshAdapter [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-6) { [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-7) // Your custom settings can go here (exposed in the Inspector) [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-8) // [SerializeField] private float scanResolution = 0.5f; [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-10) // You MUST override the abstract Generate method [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-11) public override void Generate(Dungeon dungeon) [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-12) { [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-13) Debug.Log("My Custom Pathfinding Adapter is running!"); [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-14) [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-15) // --- Add your custom pathfinding logic here --- [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-16) // Example: Trigger your pathfinding system's API [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-17) // MyPathfindingSystem.Instance.ScanNewArea(dungeon.AllTiles); [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-18) } [](https://www.aegongames.com/dungen-documentation/pathfinding/custom-adapters/#__codelineno-0-19) }` Key points about `NavMeshAdapter`: * It inherits from `MonoBehaviour`, so it's a standard Unity component. * It includes a virtual `Priority` property (defaulting to 0) which you can override if you need to control the execution order relative to other DunGen adapters (lower priority runs first). * It defines the abstract `Generate` method, which you **must** implement. * * * The `Generate` Method --------------------- This is the core of your custom adapter. DunGen automatically calls this method during its post-processing phase. * **Parameter:** It receives a `Dungeon` object as input. * **`Dungeon` Object:** This object contains comprehensive information about the just-generated dungeon layout, including: * `dungeon.AllTiles`: A collection of all `Tile` instances placed in the scene. * `dungeon.MainPathTiles`: Tiles belonging to the main path. * `dungeon.BranchPathTiles`: Tiles belonging to branch paths. * `dungeon.Connections`: A collection of `DoorwayConnection` objects detailing which doorways were connected. * `dungeon.Root`: The root GameObject containing the generated dungeon. * ... and other useful properties about the layout. * **Timing:** This method executes _after_ all tiles, props (via `Global Props`), doors (via `Doorway` Connectors), and Lock & Key elements have been placed. * * * Implementation Steps -------------------- 1. **Create Script:** Create a new C# script in your Unity project (e.g., `MyCustomPathfindingAdapter.cs`). 2. **Inherit & Implement:** Make the class inherit from `DunGen.Adapters.NavMeshAdapter` and implement the required `public override void Generate(Dungeon dungeon)` method. Include the necessary `using` statements. 3. **Add Logic:** Inside the `Generate` method, write the code needed to interact with your specific pathfinding system's API. Use the provided `dungeon` object to get information about the layout (e.g., bounds of tiles, doorway connection points). 4. **Attach Component:** Add your custom adapter script as a component to the **same GameObject** in your scene that has the **`Runtime Dungeon`** component. DunGen automatically detects and runs all `BaseAdapter` components attached to this GameObject. 5. **(Optional) Set Priority:** If the execution order matters relative to other adapters (like built-in ones or other custom ones), override the `Priority` property in your script. * * * Considerations -------------- * **Performance:** Be mindful that complex pathfinding calculations performed synchronously within the `Generate` method can cause a noticeable hitch or delay when the dungeon generation completes. Consider if your pathfinding system offers asynchronous updating options that you can trigger from the adapter. * **Dependencies:** Ensure any necessary manager objects or setup for your pathfinding system are already present and initialized in the scene _before_ DunGen generation starts. * **Error Handling:** Implement robust error checking (e.g., checking for nulls, using try-catch blocks) within your `Generate` method to prevent issues in your pathfinding logic from breaking the entire generation process. By creating a custom adapter, you can seamlessly integrate virtually any pathfinding system with DunGen's powerful procedural generation capabilities. Back to top --- # Limitations & Considerations - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/troubleshooting/limitations/#troubleshooting-limitations-considerations) Troubleshooting: Limitations & Considerations ============================================= DunGen is a powerful tool, but like any system, it operates based on certain internal logic and assumptions. Understanding these limitations is crucial for designing compatible content and troubleshooting potential generation failures. Being aware of these constraints upfront can save significant debugging time. The most critical limitation relates to how DunGen performs collision checks between Tiles. * * * Doorway Placement ----------------- * **The Core Mechanism:** DunGen determines if Tiles overlap by checking their **Axis-Aligned Bounding Boxes (AABB)**. This is a fast and efficient method suitable for runtime generation, but it's less precise than mesh-based collision. * **The Critical Rule:** Because collision is based on the AABB, **Doorway components MUST be placed on the outer edge of their Tile's calculated AABB.** * **What This Means:** * The Doorway component's position must lie on one of the six faces of the invisible rectangular box that encompasses all renderers and colliders within the Tile prefab. * DunGen can handle doorways that are _slightly_ offset from the absolute edge, but they must fundamentally reside _on_ the boundary plane of the AABB. * **The Problem - Concave Shapes:** Doorways placed on **concave** portions of a Tile (parts that indent inwards relative to the overall bounding box) **will NOT work**. DunGen's connection logic relies on finding doorways on the AABB edge where two tiles meet. If a doorway is inside this edge, it won't be detected correctly for connections. * **Visual Example:** The image below illustrates this. The `orange box` represents the Tile's AABB, and the `blue line` represents the Doorway's position. * **(✓ Correct):** Doorways are placed on the flat, outer edges of the AABB. Even if the visible mesh curves slightly _inside_ the AABB near the doorway, the Doorway component itself is positioned on the AABB boundary. * **(X Incorrect):** Doorways are placed on indented parts of the Tile geometry. These positions are _inside_ the AABB's boundary, not on its edge. DunGen cannot connect these doorways. [![Doorway Placement Correct vs Incorrect](https://www.aegongames.com/dungen-documentation/assets/images/troubleshooting/valid-doorway-placement.png)](https://www.aegongames.com/dungen-documentation/assets/images/troubleshooting/valid-doorway-placement.png) * **When Does This Matter Most?** * **Simple Rectangular Tiles:** If your tiles are basically rectangular prisms, this is usually not a concern, as all walls naturally align with the AABB edges. * **Complex Shapes (L-shapes, T-shapes, Alcoves, etc.):** This restriction becomes extremely important when designing Tiles with non-rectangular footprints. You _must_ ensure doorways are only placed on segments of the Tile that correspond to the _outer faces_ of its overall bounding box. Visualize the AABB around your complex tile and place doorways accordingly. Consequences of Incorrect Placement Failing to adhere to the AABB edge placement rule for Doorways is a common cause of dungeon generation failures or unexpected connectivity issues. If DunGen seems unable to connect certain tiles, verify the Doorway placement relative to the Tile's AABB. * * * Other Considerations -------------------- * **Performance:** While not a hard limitation on _what_ can be generated, extremely complex Tile prefabs (high polygon counts, numerous components, complex scripts) can increase instantiation time and potentially impact runtime generation performance. Consider optimization or using features like [Tile Pooling](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/) . Understanding the AABB collision system and its implication for doorway placement is the most important technical limitation to grasp when designing content for DunGen, especially when moving beyond simple rectangular rooms. Back to top --- # Overview - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/troubleshooting/#troubleshooting-overview) Troubleshooting: Overview ========================= While DunGen aims to be robust and easy to use, you might occasionally encounter unexpected behaviour, performance issues, or situations where the generated dungeon doesn't quite meet your expectations. This section provides guidance on identifying and resolving common problems, understanding DunGen's limitations, and analysing the generation process. * * * Topics Covered: --------------- * **[Limitations & Considerations](https://www.aegongames.com/dungen-documentation/troubleshooting/limitations/) :** Before diving into complex debugging, understand the inherent design constraints of DunGen. This page covers crucial aspects like the requirements for **Doorway Placement** relative to a Tile's bounding box (AABB) and how the collision system works. Understanding these limitations can often explain why certain layouts might fail or why specific Tile shapes are problematic. * **[Analysing Generation Performance](https://www.aegongames.com/dungen-documentation/troubleshooting/analysis/) :** Performance analysis is crucial for optimizing your dungeon generation, especially for complex layouts or lower-spec target platforms. This page introduces tools like the `Runtime Analyzer` component for gathering statistics on generation time and failure rates, and how to use asynchronous generation with pauses for visual debugging of the step-by-step layout process. Understanding _where_ time is spent or _why_ generation might fail is the first step to fixing it. * * * Common Issues (General Guidance) -------------------------------- While specific issues often relate to the topics above, here are some general areas to investigate when troubleshooting: * **Generation Failures:** If DunGen frequently fails to generate a dungeon (especially noticeable in the Editor where it has a retry limit), check: * **Insufficient Tile Variety:** Do you have enough unique Tile prefabs, especially if using `Disallow` repeat modes? * **Overly Restrictive Rules:** Are your [Tile Connection Rules](https://www.aegongames.com/dungen-documentation/advanced-features/connection-rules/) too strict? Are your [Tile Injection](https://www.aegongames.com/dungen-documentation/advanced-features/injecting-tiles/) rules impossible to satisfy? * **Tight Constraints:** Is the dungeon length too long for the available space, or are the branch constraints too demanding? * **Incorrect Doorway Placement:** Are doorways placed correctly on the Tile bounds as described in [Limitations](https://www.aegongames.com/dungen-documentation/troubleshooting/limitations/) ? * **Scene Collisions:** Is DunGen colliding with hidden or unexpected objects in the scene? * **Performance Problems:** If generation is slow or causes hitches: * **Complex Tiles:** Are your Tile prefabs overly detailed or have too many components? * **Instantiation Cost:** Consider enabling [Tile Pooling](https://www.aegongames.com/dungen-documentation/optimization/tile-pooling/) . * **Runtime Baking:** Is runtime pathfinding baking ([Unity NavMesh](https://www.aegongames.com/dungen-documentation/pathfinding/unity-navmesh/) , [A\* Pathfinding](https://www.aegongames.com/dungen-documentation/pathfinding/astar-pathfinding/) ) taking too long? Consider pre-baking or optimizing bake settings. * Use the tools described in [Analyzing Performance](https://www.aegongames.com/dungen-documentation/troubleshooting/analysis/) to pinpoint bottlenecks. * **Visual Glitches:** Check Tile prefab alignment, Doorway component orientation, and ensure materials/shaders are compatible with runtime instantiation if issues arise. Refer to the specific pages in this section for more detailed solutions and techniques related to these common troubleshooting areas. Back to top --- # FAQ - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/faq/#frequently-asked-questions) Frequently Asked Questions ========================== Can DunGen be used for 2D games? -------------------------------- Yes. DunGen works just as well with 2D games as it does with 3D. There's even a (very) simple 2D demo scene included. Does DunGen support loops? -------------------------- Loops (paths that connect back up to the rest of the dungeon) are not supported. You can achieve incidental loops by using the `Doorway Connection Chance` feature in the [DungeonFlow](https://www.aegongames.com/dungen-documentation/core-concepts/dungeon-flow/#inspector-settings) . This will try to connect any Doorways that coincidentally overlap, but were otherwise not connected. Can I generate dungeons in the editor, or does DunGen only support runtime dungeons? ------------------------------------------------------------------------------------ DunGen can generate dungeon layouts entirely in the editor if you'd like. Just use the window located on the main menu under `Window > DunGen > Generate Dungeon`. Can you save a dungeon layout and come back to it later? -------------------------------------------------------- The random number generator used by DunGen is seeded. If you need your players to be able to revisit a previous floor, for example, you would store the seed used to generate that floor. DunGen could then take that seed and generate an identical layout (including props). Of course, you'd need to also save any changes that were made to the dungeon (such as chests being opened) and re-apply them once DunGen has finished generating the layout. Does DunGen work with outdoor dungeons as well? ----------------------------------------------- While DunGen wasn't made with outdoor scenes in mind, it doesn't care what is contained within a tile. These are a few things you'll have to consider when using DunGen in an outdoor setting: * DunGen was made for interior scenes, so in order to avoid your scene looking like a corridor, each Tile will need to be fairly large. * You'll need a way to cover any Tile edges that aren't connected. The best way to do this is to have a cliff mesh (or some other large, natural structure) that blocks the edge of the tile. You'd then use a Doorways Blocker list to make this mesh only appear when the Tile is not connected to anything along that edge. See the [Doorways](https://www.aegongames.com/dungen-documentation/core-concepts/doorways/) section for more information. * Standard portal culling won't provide much benefit (if any) when your doorways stretch the length of your tile. You'll need to make use of some other culling solution. Will DunGen work with this art pack? ------------------------------------ There are no strict requirements when it comes to the assets you use with DunGen. Any modular art pack should work without issue (although if you're mixing packs, it's best if all of the art uses the same grid size). Back to top --- # Analysis - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/troubleshooting/analysis/#troubleshooting-analysing-generation-performance-process) Troubleshooting: Analysing Generation Performance & Process =========================================================== When your dungeon generation isn't working as expected, whether it's failing frequently, taking too long, or producing undesirable layouts, you need ways to diagnose the problem. DunGen provides tools and features to help you analyse the performance and visualize the step-by-step process of dungeon creation. * * * Generation Statistics --------------------- The generation statistics window provides some simple information about your successful dungeon generation. * **What it Does:** Provides a list of basic statistics including total generation time, the number of rooms of each type that were spawned, total retry count, and how long each step in the generation process took. * **How to Use:** 1. Open the generation statistics window (`Window > DunGen > Generation Stats`). 2. Generate a dungeon. This can be done at runtime using the `Runtime Dungeon` component or in the editor (`Window > DunGen > Generate Dungeon`). 3. The window will update to show that stats of the last generated dungeon. Generating another dungeon will update the stats for the new dungeon generation. * * * Runtime Analyzer Component -------------------------- For quantitative analysis, especially regarding performance and success rates over multiple runs, DunGen provides the `Runtime Analyzer` component. * **What it Does:** This component repeatedly generates dungeons using specified settings and gathers statistics about the process, such as average generation time, failure rates, and time spent on different generation steps. * **How to Use (Easiest Way):** 1. Locate the demo scene provided with DunGen: `Assets/DunGen/Demo/Analysis Scene`. 2. Open this scene. 3. Find the `Analyzer` GameObject in the hierarchy. 4. In the Inspector, find the `Runtime Dungeon (Script)` component attached to the `Analyzer` GameObject. 5. Replace the default `Dungeon Flow` asset in its slot with **your own** `Dungeon Flow` asset that you want to test. 6. Enter Play mode. The analyser will run multiple generation cycles (configurable on the `Runtime Analyzer` component) and print the statistics to the Console once finished. * **How to Use (Manual Setup):** 1. Add the `Runtime Analyzer` component to a GameObject in your scene (`Add Component > DunGen > Analysis > Runtime Analyzer`). 2. Ensure this GameObject also has a `Runtime Dungeon` component configured with your desired settings. 3. Configure the `Runtime Analyzer` settings (number of iterations, etc.). 4. Enter Play mode. * **What Information it Provides:** * Total number of successful generations vs. attempts. * Average time taken per successful generation. * Average time spent on specific phases (e.g., Main Path Generation, Branch Path Generation, Post-Processing). * Average number of rooms in total, as well as individually on the Main Path and Branch Paths. * **Why it's Useful:** * Identifies performance bottlenecks (which step takes the longest?). * Quantifies the impact of changes (e.g., did adding more complex tiles significantly increase generation time?). * Helps determine if generation failures are frequent or rare under specific rule sets. * * * Asynchronous Generation Visualization ------------------------------------- Sometimes, seeing _how_ the dungeon is built step-by-step is more revealing than statistics, especially when debugging layout failures or unexpected tile placements. You can achieve this using DunGen's asynchronous generation mode with pauses. * **What it Does:** Allows DunGen to generate the dungeon over multiple frames and optionally pause after placing each Tile, letting you watch the process unfold in the Scene view. * **How to Enable:** 1. Select the GameObject containing your `Runtime Dungeon` component. 2. In the Inspector, find these settings: * **`Generate Asynchronously`:** Check this box. This tells DunGen not to block the main thread during generation, enabling pauses. * **`Pause Between Rooms`:** Set this to a small positive value (e.g., `0.5` or `1.0`). This is the duration (in seconds) DunGen will pause after placing each room/tile. A value of `0` means no pause. 3. Enter Play mode. Observe the Scene view as the dungeon constructs itself incrementally. * **Why it's Useful:** * **Visual Debugging:** See the exact order tiles are placed and connected. * **Failure Point Identification:** If generation fails, you can often see exactly _which_ tile placement failed or where the process got stuck. * **Understanding Logic:** Visually grasp how main path vs. branch path generation proceeds, how connection rules are applied, or why certain areas might be unreachable. * **Collision Issues:** Helps spot if tiles are colliding unexpectedly with each other or scene objects during placement. * * * By utilizing the `Runtime Analyzer` for performance metrics and asynchronous visualization for process debugging, you gain valuable insights into how DunGen is operating, making it much easier to troubleshoot issues and optimize your procedural dungeon generation setup. Back to top --- # Cookbook - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/cookbook/#dungen-cookbook-practical-recipes) DunGen Cookbook: Practical Recipes ================================== Welcome to the DunGen Cookbook! This section provides a collection of practical examples, code snippets, and solutions for common tasks and customizations you might want to implement when working with DunGen. Think of these entries as focused "recipes" designed to help you quickly achieve a specific goal without necessarily diving deep into the underlying theory (though links to relevant documentation sections may be provided). Prerequisites These recipes generally assume you have a basic understanding of DunGen's core concepts, such as Tiles, Doorways, Dungeon Flow, and the Runtime Dungeon component, as covered in the [Getting Started](https://www.aegongames.com/dungen-documentation/getting-started/) and [Core Concepts](https://www.aegongames.com/dungen-documentation/core-concepts/) sections. * * * How to Use This Section ----------------------- Browse the list of recipes below. Each link will take you to a dedicated page containing the specific example, code snippets, and explanations needed to implement that particular feature. Adaptation May Be Required The code provided in these recipes is intended as a starting point and example. You may need to adapt it to fit the specific needs and architecture of your own project. * * * Recipe Index ------------ Here are the currently available recipes: * [Spawning the Player at Spawn Points](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/) * [Main Path Connection Rule](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/) * [Line Segment Injection](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/) * [Programmatically Modifying DunGen Assets](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/) Back to top --- # Spawning the Player - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#spawning-the-player) Spawning the Player =================== * **Goal:** We want to spawn our player prefab at a random spawn point, designated by a Unity tag, * **Usage:** 1. Create a Unity tag that will be used to identify your potential spawn points. 2. Attach the script to any GameObject outside of the dungeon hierarchy. 3. In the inspector, set the `RuntimeDungeon` to the dungeon generator you want to use and set `PlayerPrefab` to the player prefab you want to spawn. Set the `SpawnPointTag` to the tag created earlier. 4. Apply the tag to empty objects placed inside your Tiles. These are the places where the player can spawn. SimplePlayerSpawner.cs `[](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-2) using System.Collections.Generic; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-3) using System.Linq; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-4) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-5) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-6)[](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-7) public class SimplePlayerSpawner : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-8) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-9) // The dungeon generator we are using [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-10) public RuntimeDungeon RuntimeDungeon; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-11) // The prefab we want to spawn to represent the player [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-12) public GameObject PlayerPrefab; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-13) // The tag we are using to identify spawn points [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-14) public string SpawnPointTag = "PlayerSpawn"; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-15) // Whether we should only spawn on the start tile [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-16) public bool StartTileOnly = true; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-17) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-18) private GameObject player; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-19) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-20) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-21) private void OnEnable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-22) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-23) RuntimeDungeon.Generator.OnGenerationStatusChanged += OnDungeonGenerationStatusChanged; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-24) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-25) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-26) private void OnDisable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-27) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-28) RuntimeDungeon.Generator.OnGenerationStatusChanged -= OnDungeonGenerationStatusChanged; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-29) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-30) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-31) private void OnDungeonGenerationStatusChanged(DungeonGenerator generator, GenerationStatus status) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-32) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-33) if (status == GenerationStatus.Complete) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-34) SpawnPlayer(generator.CurrentDungeon); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-35) else [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-36) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-37) // Destroy any existing player [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-38) if (player != null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-39) Destroy(player); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-40) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-41) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-42) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-43) private void SpawnPlayer(Dungeon dungeon) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-44) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-45) // Determine where the player can spawn [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-46) var hierarchyToSearch = (StartTileOnly) ? dungeon.MainPathTiles[0].transform : dungeon.transform; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-47) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-48) // Find all valid spawn points (all GameObjects with the appropriate tag) within out chosen search hierarchy [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-49) var spawnPoints = FindSpawnPointsInHierarchy(hierarchyToSearch); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-50) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-51) // Select one of the spawn points at random [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-52) int spawnPointIndex = UnityEngine.Random.Range(0, spawnPoints.Count()); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-53) var selectedSpawnPoint = spawnPoints.ElementAt(spawnPointIndex); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-54) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-55) // Spawn the player prefab at the target [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-56) player = Instantiate(PlayerPrefab, selectedSpawnPoint.position, selectedSpawnPoint.rotation); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-57) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-58) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-59) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-60) /// Search through a transform hierarchy to find any objects with the appropriate tag [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-61) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-62) private IEnumerable FindSpawnPointsInHierarchy(Transform currentTransform) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-63) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-64) if (currentTransform.gameObject.CompareTag(SpawnPointTag)) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-65) yield return currentTransform; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-66) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-67) for (int i = 0; i < currentTransform.childCount; i++) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-68) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-69) var childTransform = currentTransform.GetChild(i); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-70) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-71) foreach (var spawnPoint in FindSpawnPointsInHierarchy(childTransform)) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-72) yield return spawnPoint; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-73) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-74) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/spawn-player/#__codelineno-0-75) }` Back to top --- # Line Segment Injection - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#line-segment-injection) Line Segment Injection ====================== The following example script demonstrates how to procedurally add tile injection rules, allowing us to inject tiles onto specific line segments in the dungeon flow. `[](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-2) using System; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-3) using System.Collections.Generic; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-4) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-5)[](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-6) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-7) /// Injects tiles into the dungeon based on the line segment inside the dungeon flow. 0 is the first line segment in the dungeon flow [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-8) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-9) public class TileSegmentInjector : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-10) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-11) [Serializable] [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-12) public class LineSegmentInjectedTileSet [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-13) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-14) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-15) /// Which line segment does this rule apply to? 0 is the first line segment in the dungeon flow [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-16) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-17) public int LineSegmentIndex = 0; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-18) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-19) /// The tile set to inject [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-20) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-21) public TileSet TileSet = null; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-22) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-23) /// If required, DunGen will retry generating the dungeon until this tile is successfully injected [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-24) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-25) public bool Required = true; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-26) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-27) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-28) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-29) /// The runtime dungeon to inject tiles into [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-30) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-31) public RuntimeDungeon RuntimeDungeon = null; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-32) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-33) /// Padding as a percentage of the line segment, to prevent injected tiles from appearing too close to the start or end of the segment [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-34) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-35) [Range(0f, 25f)] [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-36) public float PaddingPercentage = 0.0f; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-37) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-38) /// A list of injection rules [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-39) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-40) public List InjectionRules = new List(); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-41) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-42) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-43) private void OnEnable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-44) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-45) if(RuntimeDungeon == null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-46) RuntimeDungeon = FindObjectOfType(); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-47) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-48) if(RuntimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-49) RuntimeDungeon.Generator.TileInjectionMethods += InjectTiles; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-50) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-51) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-52) private void OnDisable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-53) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-54) if (RuntimeDungeon != null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-55) RuntimeDungeon.Generator.TileInjectionMethods -= InjectTiles; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-56) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-57) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-58) private void InjectTiles(RandomStream randomStream, ref List tilesToInject) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-59) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-60) var generator = RuntimeDungeon.Generator; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-61) var dungeonFlow = generator.DungeonFlow; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-62) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-63) float normalizedPaddingPercentage = PaddingPercentage / 100.0f; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-64) float normalizedLengthSoFar = 0.0f; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-65) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-66) for (int i = 0; i < dungeonFlow.Lines.Count; i++) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-67) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-68) float min = normalizedLengthSoFar; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-69) float max = normalizedLengthSoFar + dungeonFlow.Lines[i].Length; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-70) float length = max - min; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-71) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-72) var rule = InjectionRules.Find(x => x.LineSegmentIndex == i); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-73) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-74) if(rule != null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-75) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-76) float normalizedPathDepth = Mathf.Lerp(min + normalizedPaddingPercentage, max - normalizedPaddingPercentage, (float)randomStream.NextDouble()); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-77) tilesToInject.Add(new InjectedTile(rule.TileSet, true, normalizedPathDepth, 0.0f, rule.Required)); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-78) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-79) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-80) normalizedLengthSoFar = max; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-81) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-82) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/line-segment-injection/#__codelineno-0-83) }` Back to top --- # Use a Specific Socket for the Main Path - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#use-a-specific-socket-for-the-main-path) Use a Specific Socket for the Main Path ======================================= * **Goal:** We want to force all main path connections to use a specific doorway socket. All Tiles along the main path will have to connect to one-another (and to branch Tiles that start from them), using a `DoorwaySocket` that we specify. * **Usage:** Attach the script to any GameObject in the scene and assign an appropriate socket to the MainPathSocket field in the inspector. MainPathConnectionRule.cs `[](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-2) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-3)[](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-4) public class MainPathConnectionRule : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-5) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-6) public DoorwaySocket MainPathSocket = null; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-7) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-8) private TileConnectionRule rule; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-9) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-10) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-11) private void OnEnable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-12) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-13) rule = new TileConnectionRule(CanTilesConnect); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-14) DoorwayPairFinder.CustomConnectionRules.Add(rule); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-15) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-16) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-17) private void OnDisable() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-18) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-19) DoorwayPairFinder.CustomConnectionRules.Remove(rule); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-20) rule = null; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-21) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-22) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-23) private TileConnectionRule.ConnectionResult CanTilesConnect(ProposedConnection connection) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-24) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-25) bool isOnMainPath = connection.PreviousTile.Placement.IsOnMainPath; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-26) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-27) // We're only interested in main path connections [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-28) if (isOnMainPath) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-29) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-30) // Only allow main path connections if they use the correct socket on both doorways [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-31) bool allowConnection = connection.PreviousDoorway.Socket == MainPathSocket && [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-32) connection.NextDoorway.Socket == MainPathSocket; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-33) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-34) if (allowConnection) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-35) return TileConnectionRule.ConnectionResult.Allow; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-36) else [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-37) return TileConnectionRule.ConnectionResult.Deny; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-38) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-39) // If we're not on the main path, just ignore it [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-40) else [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-41) return TileConnectionRule.ConnectionResult.Passthrough; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-42) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/main-path-connections/#__codelineno-0-43) }` Back to top --- # Programmatically Modify the DungeonFlow - DunGen [Skip to content](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#programmatically-modify-the-dungeonflow) Programmatically Modify the DungeonFlow ======================================= It's possible to modify the DungeonFlow or any other DunGen asset at runtime to manipulate how the dungeon is generated. Permanent Changes Care must be taken when modifying any DunGen asset that derives from `ScriptableObject` (e.g., TileSet, Archetype, DungeonFlow, etc). Modifying these assets will make permanent changes to your project. You will need to copy the asset first (using `Instantiate(originalAsset)`) and **work only on the duplicate asset** to avoid permanent change to your project. You'll also need to consider deep copies if, for example, you'd like to change one of the Tiles inside a `TileSet` that belongs to your `DungeonFlow`. Here's an example of how you could duplicate a `DungeonFlow` and swap the Tiles that appear on the Goal node with one or more boss Tiles. Useful for if you'd like a boss to appear only on certain floors, but otherwise want the DungeonFlow to be identical to your regular floors, and don't want to have to maintain multiple near-identical Dungeon Flows. SwapGoalNode.cs `[](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-1) using DunGen; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-2) using DunGen.Graph; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-3) using System.Linq; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-4) using UnityEngine; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-5)[](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-6) public class SwapGoalNode : MonoBehaviour [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-7) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-8) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-9) /// The original dungeon flow asset we want to swap the goal of [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-10) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-11) public DungeonFlow OriginalFlow; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-12) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-13) /// The replacement boss room tiles to use as the goal [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-14) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-15) public TileSet BossRoomTileSet; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-16) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-17) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-18) /// The duplicated dungeon flow with its goal overridden. We can pass this [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-19) /// to the dungeon generator to generate a copy of our dungeon with the swapped goal node [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-20) /// [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-21) public DungeonFlow BossRoomFlow { get; private set; } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-22) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-23) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-24) private void Start() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-25) { [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-26) if (OriginalFlow == null) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-27) return; [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-28) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-29) // Make a copy of the original flow [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-30) // IMPORTANT: Be very careful modifying the dungeon flow asset at runtime. Since it's a [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-31) // ScriptableObject, any changes to the original will affect the settings inside your actual project. [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-32) // This also goes for sub-objects inside the dungeon flow (such as TileSets). Anything derived from a [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-33) // ScriptableObject should be duplicated first before any modifications are applied to avoid making [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-34) // permanent changes to your project [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-35) BossRoomFlow = Instantiate(OriginalFlow); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-36) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-37) // Find the goal node [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-38) var goalNode = BossRoomFlow.Nodes.First(x => x.NodeType == NodeType.Goal); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-39) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-40) // Set the boss room TileSet as the only goal node [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-41) goalNode.TileSets.Clear(); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-42) goalNode.TileSets.Add(BossRoomTileSet); [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-43) [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-44) // Now we can pass our new BossRoomFlow into the Generator of our RuntimeDungeon component and call Generate() [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-45) } [](https://www.aegongames.com/dungen-documentation/reference/cookbook/modify-dungeon-flow/#__codelineno-0-46) }` Back to top ---