I’m using unity3d version 6.0 (6000.0.51f1) and the ai navigation package version 2.0.8
I created a script that generate a maze and also bake the navmesh surface through code and also create another script that move the navmesh agent.
ok here are some screenshots to explain and show my settings.
first object in hierarchy is the Maze Manager that contains the MazeGeneratoe script and the navmeshsurface component.
all the baking is done inside the script. i can do the baking also in the editor manual but i do it also in the script.
you can see in the navmesh surface i set the Default Area to Walkable and the Include Layers to Default.
the next screenshot is showing the example of one of the Walls objects and show that in the inspector the layer is set to Obstacle. also the Wall prefab in the Assets the layer is set to Obstacle.
next i want to show the Floor object and show that it’s Static is set to true ! and the layer is Default.
also the floor prefab in the assets have the same settings , Static is true and layer is Default.
and if i bake now in the editor or in the script you can see the whole floor become blue walkable and the walls are not so you can see the maze path.
then i have an Agent gameobject with attached script that should make the agent moving through the maze path/'s.
no matter where the Agent start position is at , if at the entrance position of the maze or at any other position in the maze path the agent is moving always in diagonal and over walls.
you can see here where the Agent start and the entrance red marker object at the bottom when running the game.
the game start and the agent is start moving but instead moving to the exit marker the top left green object through the maze path/'s it’s moving the shortest way to this position all the time each time and stop there.
i put in the Agent in the script AgentNavigiation both objects the ExitMarker and Entrance marker but the agent always will move to that position in the screenshot and never will move through the maze baked path’s.
any ideas what is the problem ? and how to fix it , making the agent moving through the path from start to end ?
this is the script that move the Agent:
using UnityEngine;
using UnityEngine.AI;
public class AgentNavigation : MonoBehaviour
{
[SerializeField]
private Transform desiredDestination;
public Transform enterancePosition;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
transform.position = enterancePosition.position;
GetComponent<NavMeshAgent>().destination = desiredDestination.position;
}
}
this is the script that generate the maze and also baking:
a bit long but easy to understand and see.
using UnityEngine;
using Unity.AI.Navigation;
using System.Collections.Generic;
using UnityEngine.AI;
using Unity.AI.Navigation.Editor;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteAlways]
public class MazeGenerator : MonoBehaviour
{
[Header("Maze Size")]
public int width = 30;
public int height = 30;
[Header("Prefabs")]
public GameObject wallPrefab;
public GameObject floorPrefab;
public GameObject entranceMarkerPrefab;
public GameObject exitMarkerPrefab;
public GameObject deadEndMarkerPrefab;
[Header("Options")]
public bool generateEntranceAndExit = true;
public bool markDeadEnds = true;
private bool[,] maze;
private int[] directions = { 0, 1, 2, 3 };
private NavMeshSurface navMeshSurface;
private Vector2Int entrancePos;
private Vector2Int exitPos;
private void Awake()
{
navMeshSurface = GetComponent<NavMeshSurface>();
}
private void Start()
{
// Don't regenerate anything here to avoid duplication
}
public void GenerateAndBuildMaze()
{
#if UNITY_EDITOR
// Record undo for editor
Undo.RegisterFullObjectHierarchyUndo(gameObject, "Generate Maze");
#endif
ClearMaze();
ValidateMazeDimensions();
GenerateMaze();
BuildMaze();
if (navMeshSurface != null)
{
navMeshSurface.enabled = true;
navMeshSurface.BuildNavMesh();
}
}
public void ClearMaze()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
if (navMeshSurface != null)
{
// Only try to remove if data exists
if (navMeshSurface.navMeshData != null)
{
navMeshSurface.RemoveData();
navMeshSurface.enabled = false;
}
}
List<GameObject> toDestroy = new List<GameObject>();
foreach (Transform child in transform)
toDestroy.Add(child.gameObject);
foreach (GameObject go in toDestroy)
Object.DestroyImmediate(go);
return;
}
#endif
// Runtime: normal removal
if (navMeshSurface != null && navMeshSurface.navMeshData != null)
{
navMeshSurface.RemoveData();
navMeshSurface.enabled = false;
}
foreach (Transform child in transform)
Destroy(child.gameObject);
}
void ValidateMazeDimensions()
{
if (width % 2 == 0) { width += 1; Debug.LogWarning($"Maze width must be odd. Adjusted to: {width}"); }
if (height % 2 == 0) { height += 1; Debug.LogWarning($"Maze height must be odd. Adjusted to: {height}"); }
}
public void GenerateMaze()
{
maze = new bool[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
maze[x, y] = true;
int startX = 1, startY = 1;
maze[startX, startY] = false;
CarvePath(startX, startY);
EnsureFullCoverage(); // ✅ added to fix dead zones
if (generateEntranceAndExit)
AddRandomEntranceAndExit();
}
void EnsureFullCoverage()
{
for (int x = 1; x < width - 1; x += 2)
{
for (int y = 1; y < height - 1; y += 2)
{
if (maze[x, y])
{
maze[x, y] = false;
CarvePath(x, y);
}
}
}
}
void CarvePath(int x, int y)
{
ShuffleArray(directions);
foreach (int dir in directions)
{
int nx = x, ny = y;
switch (dir)
{
case 0: ny -= 2; break;
case 1: ny += 2; break;
case 2: nx -= 2; break;
case 3: nx += 2; break;
}
if (nx > 0 && nx < width - 1 && ny > 0 && ny < height - 1 && maze[nx, ny])
{
maze[nx, ny] = false;
maze[(x + nx) / 2, (y + ny) / 2] = false;
CarvePath(nx, ny);
}
}
}
void AddRandomEntranceAndExit()
{
List<Vector2Int> top = new();
List<Vector2Int> bottom = new();
List<Vector2Int> left = new();
List<Vector2Int> right = new();
for (int x = 1; x < width - 1; x += 2)
{
if (!maze[x, 1]) top.Add(new Vector2Int(x, 0));
if (!maze[x, height - 2]) bottom.Add(new Vector2Int(x, height - 1));
}
for (int y = 1; y < height - 1; y += 2)
{
if (!maze[1, y]) left.Add(new Vector2Int(0, y));
if (!maze[width - 2, y]) right.Add(new Vector2Int(width - 1, y));
}
List<List<Vector2Int>> walls = new() { top, bottom, left, right };
List<int> wallIndices = new() { 0, 1, 2, 3 };
ShuffleArray(wallIndices);
int entranceWall = wallIndices[0];
int exitWall = wallIndices[1];
if (walls[entranceWall].Count == 0 || walls[exitWall].Count == 0) return;
entrancePos = walls[entranceWall][Random.Range(0, walls[entranceWall].Count)];
exitPos = walls[exitWall][Random.Range(0, walls[exitWall].Count)];
maze[entrancePos.x, entrancePos.y] = false;
maze[exitPos.x, exitPos.y] = false;
Transform entranceExitParent = transform.Find("EntranceAndExit");
if (entranceExitParent == null)
{
GameObject fp = new GameObject("EntranceAndExit");
fp.transform.parent = transform;
entranceExitParent = fp.transform;
}
if (entranceMarkerPrefab)
{
GameObject entrance = Instantiate(entranceMarkerPrefab, new Vector3(entrancePos.x, 1, entrancePos.y), Quaternion.identity, entranceExitParent);
entrance.name = "Entrance";
}
if (exitMarkerPrefab)
{
GameObject exit = Instantiate(exitMarkerPrefab, new Vector3(exitPos.x, 1, exitPos.y), Quaternion.identity, entranceExitParent);
exit.name = "Exit";
}
}
public void BuildMaze()
{
// --- Create main category parents under the Maze root ---
Transform wallsParent = transform.Find("Walls");
if (wallsParent == null)
{
GameObject wp = new GameObject("Walls");
wp.transform.parent = transform;
wallsParent = wp.transform;
}
Transform floorsParent = transform.Find("Floors");
if (floorsParent == null)
{
GameObject fp = new GameObject("Floors");
fp.transform.parent = transform;
floorsParent = fp.transform;
}
Transform markersParent = transform.Find("Markers");
if (markersParent == null)
{
GameObject mp = new GameObject("Markers");
mp.transform.parent = transform;
markersParent = mp.transform;
}
// --- Create walls ---
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (maze[x, y])
{
GameObject go = Instantiate(wallPrefab, new Vector3(x, 1, y), Quaternion.identity, wallsParent);
go.name = $"Wall_{x}_{y}";
}
}
}
// --- Create floor ---
GameObject floor = Instantiate(
floorPrefab,
new Vector3(width / 2f, 0, height / 2f),
Quaternion.identity,
floorsParent
);
floor.transform.localScale = new Vector3(width / 10f, 1, height / 10f);
floor.name = "Floor";
// --- Mark dead ends if enabled ---
if (markDeadEnds)
{
MarkDeadEnds(markersParent);
}
}
void MarkDeadEnds(Transform markersParent)
{
for (int x = 1; x < width - 1; x++)
{
for (int y = 1; y < height - 1; y++)
{
if (!maze[x, y])
{
int openSides = 0;
if (!maze[x + 1, y]) openSides++;
if (!maze[x - 1, y]) openSides++;
if (!maze[x, y + 1]) openSides++;
if (!maze[x, y - 1]) openSides++;
if (openSides == 1 && deadEndMarkerPrefab != null)
{
GameObject marker = Instantiate(deadEndMarkerPrefab, new Vector3(x, 1, y), Quaternion.identity, markersParent);
marker.name = $"DeadEnd_{x}_{y}";
}
}
}
}
}
// Shuffle for arrays
void ShuffleArray(int[] array)
{
for (int i = array.Length - 1; i > 0; i--)
{
int rnd = Random.Range(0, i + 1);
int temp = array[i];
array[i] = array[rnd];
array[rnd] = temp;
}
}
// Shuffle for lists
void ShuffleArray(List<int> list)
{
for (int i = list.Count - 1; i > 0; i--)
{
int rnd = Random.Range(0, i + 1);
int temp = list[i];
list[i] = list[rnd];
list[rnd] = temp;
}
}
}





