Advanced Features: Runtime Events & Code Execution
After DunGen has finished generating the dungeon layout, placing tiles, handling props, and potentially running integrations like pathfinding, you'll often need to execute your own custom game logic. This could involve:
- Spawning the player character at the start tile.
- Initializing enemies or interactive objects placed within tile prefabs.
- Activating global game systems that depend on the dungeon layout.
- Fading in from a loading screen.
DunGen provides two primary mechanisms to hook into the generation process and run your code once the dungeon is ready:
- On Specific Objects: Implement an interface (
IDungeonCompleteReceiver) on components attached to GameObjects within your Tile prefabs. - Globally: Listen to completion or status change events directly from the
DungeonGeneratorinstance.
Method 1: On Objects Inside the Dungeon (IDungeonCompleteReceiver)
This method is ideal when you want logic to run that is specific to a particular GameObject or prefab placed as part of the dungeon.
How it Works:
- Create a C# script.
- Implement the
DunGen.IDungeonCompleteReceiverinterface in your script. - This interface requires you to implement one method:
void OnDungeonComplete(Dungeon dungeon). - Attach this script component to a GameObject that is part of one of your Tile prefabs.
- After DunGen successfully generates the entire dungeon layout, it will search all GameObjects within the final layout for components that implement
IDungeonCompleteReceiverand call theirOnDungeonCompletemethod.
Parameters:
Dungeon dungeon: Provides access to the data structure representing the completed dungeon layout (containing information about tiles, doorways, paths, etc.).
Example: Spawning an Item or Enemy within a Tile
using UnityEngine;
using DunGen;
// Attach this script to a GameObject inside one of your Tile prefabs
public class PostGenerationSpawner : MonoBehaviour, IDungeonCompleteReceiver
{
// Assign the prefab to spawn in the Inspector
public GameObject PrefabToSpawn;
public void OnDungeonComplete(Dungeon dungeon)
{
// Check if we actually have a prefab assigned
if (PrefabToSpawn == null)
{
Debug.LogWarning("PrefabToSpawn is not set!", this);
return;
}
Debug.Log($"Dungeon complete! Spawning '{PrefabToSpawn.name}' at {transform.position}", this);
// Instantiate the prefab at this GameObject's position and rotation
// Parent it to this object's parent (likely the Tile root) for organisation
// NOTE: If you're using Tile pooling, you will need to clean up the spawned objects manually
GameObject instance = Instantiate(PrefabToSpawn, transform.position, transform.rotation, transform.parent);
// Optional: You could add logic here to initialize the spawned object
// EnemyController enemy = instance.GetComponent<EnemyController>();
// if(enemy != null) { enemy.Initialize(); }
}
}
Use Cases:
- Activating specific logic within a room once the whole dungeon is ready.
- Spawning enemies or items at designated locations within tiles.
- Initializing puzzle elements placed inside prefabs.
Method 2: Globally via Generator Events
This method is suitable when you need to run logic that relates to the dungeon generation process as a whole, rather than a specific object within it. You subscribe to an event on the DungeonGenerator.
How it Works:
- Get a reference to your
RuntimeDungeoncomponent and its underlyingDungeonGeneratorinstance. - The
DungeonGeneratorhas a delegate/event calledOnGenerationComplete. - Create a method in your script that matches the required signature:
void OnGenerationComplete(DungeonGenerator generator, GenerationStatus status) - Subscribe your method to the
OnGenerationCompleteevent (using +=). - Crucially, remember to unsubscribe from the event (using -=) when your listener object is destroyed or disabled to prevent errors.
Parameters:
DungeonGenerator generator:The instance of the generator that fired the event.
Example: Spawning the Player After Dungeon Completion
public class GlobalDungeonCompleteListener : MonoBehaviour
{
// Assign your Runtime Dungeon in the Inspector
public RuntimeDungeon RuntimeDungeon;
// Assign your player prefab in the Inspector
public GameObject PlayerPrefab;
private void Start()
{
if (RuntimeDungeon == null)
{
Debug.LogError("RuntimeDungeon is not assigned!", this);
return;
}
var generator = RuntimeDungeon.Generator;
// Subscribe to the event
generator.OnGenerationComplete += HandleDungeonCompletion;
// Optional: If generation might already be complete before Start runs
// (e.g., if GenerateOnStart was true), check current status.
if (generator.Status == GenerationStatus.Complete)
HandleDungeonCompletion(generator);
}
void OnDestroy()
{
// IMPORTANT: Unsubscribe when this object is destroyed
if (RuntimeDungeon != null)
RuntimeDungeon.Generator.OnGenerationComplete -= HandleDungeonCompletion;
}
private void HandleDungeonCompletion(DungeonGenerator generator)
{
Debug.Log("Dungeon Generation Complete! Spawning Player...");
if (PlayerPrefab == null)
{
Debug.LogError("Player Prefab is not assigned!", this);
return;
}
// Get the start tile location from the generated dungeon data
if (generator.CurrentDungeon != null)
{
var startTile = generator.CurrentDungeon.MainPathTiles[0];
Vector3 spawnPosition = startTile.transform.position;
// You might want to offset this slightly or use a specific spawn point transform within the start tile
Instantiate(PlayerPrefab, spawnPosition, Quaternion.identity);
}
else
Debug.LogError("Could not find generated dungeon to spawn player!", this);
}
}
Use Cases:
- Spawning the player character.
- Initializing global managers or systems after the level is built.
- Signaling that loading is complete and fading in the game view.
Choosing the Right Method
- Use
IDungeonCompleteReceiverfor logic tightly coupled to specific prefabs or locations within the dungeon. - Use the
OnGenerationCompleteevent for global actions that need to happen once the entire dungeon generation process is finished.