Skip to content

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<Bounds>).
    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:

    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 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:

    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).