Skip to content

Advanced Features: Injecting Special Tiles

Sometimes, the standard random selection of tiles based on Tile Sets and 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 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:

// Your method needs to match this pattern
void MyInjectionLogic(DunGen.RandomStream randomStream, ref List<InjectedTile> 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?
  • 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
using UnityEngine;
using DunGen;
using System.Collections.Generic;

public class CustomTileInjector : MonoBehaviour
{
    // Assign your Runtime Dungeon Generator here
    public RuntimeDungeon RuntimeDungeon;

    // Assign the TileSet containing your special tile(s)
    public TileSet MySpecialTileSet;


    private void Start()
    {
        if (RuntimeDungeon != null && RuntimeDungeon.Generator != null)
            RuntimeDungeon.Generator.TileInjectionMethods += InjectMySpecialTile;
        else
            Debug.LogError("RuntimeDungeon or its Generator is not assigned");
    }

    // This method matches the TileInjectionDelegate
    private void InjectMySpecialTile(RandomStream randomStream, ref List<InjectedTile> tilesToInject)
    {
        // Define the injection parameters
        bool tryOnMainPath = false;  // Let's target a branch path in this example
        float targetPathDepth = 0.5f; // We want this to spawn at the halfway point of the main path
        float targetBranchDepth = 1.0f; // Target the very end of the branch
        bool mustBePlaced = false; // It's okay if this tile isn't placed

        var tileToInject = new InjectedTile(MySpecialTileSet, tryOnMainPath, targetPathDepth, targetBranchDepth, mustBePlaced);

        // Add it to the list DunGen will process
        tilesToInject.Add(tileToInject);
    }

    // Unsubscribe when the object is destroyed
    private void OnDestroy()
    {
        if (RuntimeDungeon != null && RuntimeDungeon.Generator != null)
            RuntimeDungeon.Generator.TileInjectionMethods -= InjectMySpecialTile;
    }
}

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.