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:
- Using the Inspector (Simple Rules): Configure injection rules directly on your Dungeon Flow asset for common scenarios.
- 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.
- Select your
Dungeon Flowasset in the Project view. - Find the Special Tile Injection foldout in the Inspector.
- 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
KeyManagerto use. - Path Depth: Defines the normalized range along the main path where this injection is allowed.
0represents the Start tile location.1represents the Goal tile location.- A range of
0.4to0.6means the tile can only be injected near the middle of the main path.
- Branch Depth: (Only used if
Can appear on Branch Pathis checked) Defines the normalized range along a branch path where this injection is allowed.0represents the first tile of the branch (connected to the main path).1represents the final tile (dead end) of the branch.- A range of
0.9to1.0means 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: TheDunGen.RandomStreaminstance used for the current dungeon generation. Use this if your injection logic needs randomness consistent with the dungeon seed.tilesToInject: A list ofInjectedTileobjects. Your method must add newInjectedTileinstances 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 ifIsLockedis true) The ID of the lock to use. This is the index of the lock found in theKeyManager.
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.
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.