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:
- You need access to the
DungeonGeneratorinstance used by yourRuntime Dungeoncomponent. Typically, you get this inAwakeorStartin a script attached to the same GameObject as theRuntime Dungeon. - The
DungeonGeneratorhas a public property:CollisionSettings, which in turn has anAdditionalCollisionBoundsproperty (aList<Bounds>). - Create new
Boundsobjects (defining theircenterandsize) that encompass the areas you want to protect. - Add these
Boundsobjects to theAdditionalCollisionBoundslist before DunGen starts generating.
- You need access to the
-
Example Code:
using UnityEngine; using DunGen; public class SceneCollisionSetup : MonoBehaviour { // Optional: Assign important scene objects in the Inspector // public Transform importantPillar; // public Collider importantStructureCollider; private void Awake() { // Get the Runtime Dungeon component (assuming this script is on the same GameObject) var runtimeDungeon = GetComponent<RuntimeDungeon>(); if (runtimeDungeon != null) { var collisionSettings = runtimeDungeon.Generator.CollisionSettings; // --- Example 1: Define a specific volume --- Bounds forbiddenZone = new Bounds( new Vector3(10, 0, 0), // Center of the zone new Vector3(20, 10, 20) // Total size of the zone ); collisionSettings.AdditionalCollisionBounds.Add(forbiddenZone); // --- Example 2: Use the bounds of an existing Collider --- // if (importantStructureCollider != null) // { // collisionSettings.AdditionalCollisionBounds.Add(importantStructureCollider.bounds); // } Debug.Log("Added custom collision bounds to DunGen Generator."); } else { Debug.LogError("RuntimeDungeon or its Generator not found!"); } } } -
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
trueif the placement should be prevented (collision detected) orfalseif the placement is allowed. -
Implementation:
- Access the
DungeonGeneratorinstance as described in Method 1 and get itsCollisionSettingsproperty. - The
DungeonCollisionSettingsclass has a public property:AdditionalCollisionsPredicate. This expects a delegate of typeAdditionalCollisionsDelegate. - Create a function in your script that matches the required signature:
bool YourFunctionName(Bounds potentialTileBounds, bool isTileCollidingWithDungeon). - Assign your function to the
AdditionalCollisionsPredicateproperty before generation starts.
- Access the
-
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:
using UnityEngine; using DunGen; public class SceneCollisionSetupCustom : MonoBehaviour { // Define which layers to check against in the Inspector public LayerMask CollisionCheckLayer; private RuntimeDungeon runtimeDungeon; private void Awake() { runtimeDungeon = GetComponent<RuntimeDungeon>(); if (runtimeDungeon != null) { var collisionSettings = runtimeDungeon.Generator.CollisionSettings; collisionSettings.AdditionalCollisionsPredicate = ShouldTilePlacementBeBlocked; Debug.Log("Assigned custom collision predicate to DunGen Generator."); } } private void OnDestroy() { if (runtimeDungeon != null) { var collisionSettings = runtimeDungeon.Generator.CollisionSettings; collisionSettings.AdditionalCollisionsPredicate = null; Debug.Log("Removed custom collision predicate from DunGen Generator."); } } // Function matching the AdditionalCollisionsDelegate signature private bool ShouldTilePlacementBeBlocked(Bounds potentialTileBounds, bool isTileCollidingWithDungeon) { // 1. Respect DunGen's internal collision check first if (isTileCollidingWithDungeon) { return true; // Already colliding with another generated tile, definitely block. } // 2. Perform your custom check (e.g., check for overlap with specific layers) Collider[] overlaps = Physics.OverlapBox( potentialTileBounds.center, potentialTileBounds.extents, // OverlapBox uses extents (half-size) Quaternion.identity, // AABBs are not rotated CollisionCheckLayer // Check only against specified layers ); // 3. Decide based on the custom check if (overlaps.Length > 0) { // Optional: Add more logic here, e.g., ignore triggers, check specific tags... // For now, any overlap on the specified layer blocks placement. // Debug.Log($"Custom collision detected for tile at {potentialTileBounds.center}"); return true; // Found an object on the collision layer within the bounds, block placement. } // 4. No collision found by DunGen or custom logic return false; // Allow placement. } } -
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).