i used ai tools to build procedural level generation in unity 6 and here is what took a week to crack and what came together in an afternoon
Procedural generation is one of those things that looks simple in concept diagrams and produces weeks of debugging in practice. I spent five weeks building a dungeon level generator in Unity 6 using Cursor, Claude, and Muse Chat alongside it. Some parts assembled surprisingly fast with AI help. One part took a full week to get right even with AI assistance. This is the honest personal account of what I built, what broke, and what the AI tools actually contributed.
Cursor
Primary coding tool for all generation algorithm implementation, Pro plan $20 per month
cursor.sh
Claude
Used for generation algorithm design and debugging logic errors, Pro plan $20 per month
claude.ai
Unity Muse
Muse Chat used for Unity 6 specific Tilemap and prefab spawning questions, $30 per month
unity.com
Alex Chen
June 28, 2026
What I built: a dungeon level generator for a 2D roguelite game. The generator creates rooms connected by corridors, places enemies and loot based on room type and distance from start, ensures every map is solvable with a guaranteed path to the exit, and generates different tile arrangements each run. Five weeks total. The room placement algorithm took one week to get right. The corridor generation, enemy placement, and solvability check all came together faster than expected with AI help. The final generator produces a complete playable level in under 0.3 seconds.
The Design Session With Claude Before Any Code
I had tried to build a dungeon generator once before without planning the algorithm first. I started implementing a Binary Space Partitioning algorithm I had seen in a tutorial, hit problems with the corridor generation, and abandoned it after two weeks. This time I spent two hours with Claude discussing dungeon generation algorithms before writing anything. I described my constraints: 2D tilemap in Unity 6, dungeon must fit within a defined grid size, must have a guaranteed exit, must feel varied but not random-looking. Claude walked me through three algorithms with their trade-offs and recommended a room placement with flood-fill connectivity check approach for my constraints. That recommendation turned out to be correct.
What Came Together Fast With Cursor
- The Room data structure and RoomManager: Cursor generated the Room class with position, size, type enum, and connection list based on my description. The RoomManager ScriptableObject that holds room prefab variants by type used my existing ScriptableObject architecture correctly from project context. Under 30 minutes.
- The enemy spawning system: given room type and distance from start as inputs, the spawning system selects enemy types and counts from a weighted table. Cursor wrote the weighted random selection function correctly in one pass. The Unity 6 specific Instantiate call with the correct parent transform parameter came out correctly without version specification.
- The Tilemap painting logic: using Muse Chat to confirm the correct Unity 6 Tilemap API and then Cursor to implement the actual painting. The corridor painting in particular, filling L-shaped paths between room centers on the tilemap, was generated correctly by Cursor after I described the desired output in plain language.
The Part That Took a Full Week: Room Overlap Detection
Room placement sounds simple. Place rooms on a grid without overlapping. The problem is doing this efficiently while producing interesting layouts that are not too spread out or too clustered. My first implementation from Cursor was a simple random placement with overlap rejection. It worked but produced layouts that felt sparse and often failed to place all rooms within the grid bounds. The second implementation tried a BSP approach but produced rooms that were too similar in size. The third implementation, which Claude designed after I described the previous two failures, was a random walk placement algorithm where each new room is placed adjacent to an existing room with some randomness in position. This approach naturally produced connected dungeon layouts without needing a separate corridor generation step for adjacency. Getting this to produce consistently good layouts took a full week of iteration. The AI tools could suggest algorithms and implement code but the subjective quality bar for what felt like a good dungeon required dozens of generated examples and manual judgment.
The Solvability Check That Muse Chat Helped Design
// DungeonSolvabilityChecker.cs
// Flood fill from start room to verify all required rooms are reachable
// Designed with Claude, implemented with Cursor, Unity 6 API verified with Muse Chat
using System.Collections.Generic;
using UnityEngine;
public class DungeonSolvabilityChecker
{
// Returns true if all required room types are reachable from start
public bool IsDungeonSolvable(List<Room> rooms, Room startRoom, RoomType[] requiredTypes)
{
if (rooms == null || rooms.Count == 0 || startRoom == null)
return false;
// Flood fill to find all rooms reachable from start
var visited = new HashSet<Room>();
var queue = new Queue<Room>();
queue.Enqueue(startRoom);
visited.Add(startRoom);
while (queue.Count > 0)
{
var current = queue.Dequeue();
foreach (var connected in current.ConnectedRooms)
{
if (!visited.Contains(connected))
{
visited.Add(connected);
queue.Enqueue(connected);
}
}
}
// Check that every required room type exists in the reachable set
foreach (var requiredType in requiredTypes)
{
bool typeFound = false;
foreach (var room in visited)
{
if (room.RoomType == requiredType)
{
typeFound = true;
break;
}
}
if (!typeFound)
{
Debug.Log($"Required room type {requiredType} not reachable from start.");
return false;
}
}
return true;
}
}
// Usage in DungeonGenerator.cs
// After generating a dungeon:
// var checker = new DungeonSolvabilityChecker();
// var required = new[] { RoomType.Boss, RoomType.Exit };
// if (!checker.IsDungeonSolvable(rooms, startRoom, required))
// {
// RegenerateDungeon(); // Try again with different seed
// }Mistakes in Five Weeks of Procedural Generation
- Not setting a random seed for debugging: early in development every generated dungeon was different so reproducing a specific bug required me to describe the conditions rather than reproduce the exact layout. Added a seed system immediately after realising this. Now I log the seed and can reproduce any generated dungeon exactly.
- Building the generator in one large class: the first DungeonGenerator.cs was 800 lines doing room placement, corridor generation, tile painting, enemy spawning, and solvability checking. Refactored into separate classes with Cursor help in week three. The refactored version was easier to debug because each system could be tested independently.
- Expecting Claude to produce a complete working algorithm: Claude designed correct algorithms but the implementations required iteration. Procedural generation has subjective quality criteria that cannot be expressed in code requirements. The algorithm that sounds correct in a design session needs to be run hundreds of times and evaluated visually. No AI tool can do this evaluation.
- Not testing performance until week four: the dungeon generator worked correctly in week two but I had not measured how long it took to generate. At week four the generator was taking 2.4 seconds on mid-range hardware, unacceptable for a roguelite that regenerates on every death. Optimised to 0.3 seconds by caching prefab references and using object pooling for room instances.
Final Thoughts
Five weeks to a working procedural dungeon generator that creates complete playable levels in 0.3 seconds. The AI tools compressed the algorithm research, data structure implementation, and corridor generation significantly. The room placement algorithm took a full week regardless of AI assistance because the quality criteria were subjective and required many iterations to get right. Procedural generation is one domain where AI tools help with the implementation but cannot substitute for the player experience evaluation that determines whether the generated content is actually interesting.