Skip to content

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

  1. Select your Dungeon Flow asset 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
    using UnityEngine;
    using DunGen;
    using DunGen.LockAndKey;
    
    public class KeySpawnPoint : MonoBehaviour, IKeySpawner
    {
        // Check if the key has already been spawned
        public bool HasSpawnedKey => spawnedKey != null;
    
        private GameObject spawnedKey;
    
    
        public bool CanSpawnKey(KeyManager keyManager, Key key)
        {
            // We can't spawn a key if one has already been spawned
            if (HasSpawnedKey)
                return false;
    
            // We can't spawn a key if it has no prefab
            return key.Prefab != null;
        }
    
        public void SpawnKey(KeySpawnParameters keySpawnParameters)
        {
            var key = keySpawnParameters.Key;
    
            if (keySpawnParameters.Key.Prefab == null)
            {
                Debug.LogWarning($"Key '{key.Name}' needs to be spawned here, but has no Prefab assigned in the Key Manager.", this);
                return;
            }
    
            // Instantiate the key prefab defined in the Key Manager
            spawnedKey = Instantiate(key.Prefab, transform.position, transform.rotation);
    
            // Notify the DunGen about any IKeyLock components that were created
            var keyLockComponents = spawnedKey.GetComponentsInChildren<IKeyLock>();
            keySpawnParameters.OutputSpawnedKeys.AddRange(keyLockComponents);
        }
    }
    

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
    using UnityEngine;
    using DunGen;
    
    public class KeyColour : MonoBehaviour, IKeyLock
    {
        // Assign in Inspector
        public Renderer TargetRenderer;
    
        // Used to change material properties without leaking material instances into the scene
        private MaterialPropertyBlock propertyBlock;
    
    
        public void OnKeyAssigned(Key key, KeyManager manager)
        {
            if (TargetRenderer != null)
            {
                if(propertyBlock == null)
                    propertyBlock = new MaterialPropertyBlock();
    
                // Use the color defined in the Key Manager
                propertyBlock.SetColor("_Color", key.Colour);
                TargetRenderer.SetPropertyBlock(propertyBlock);
            }
        }
    }
    

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.