The problem seems to be that for some reason the ApplyMaterial only goes to the target cell and does not even try to change the materials of the other cells accordingly. I want the solver to find a path from each point to the target point, and update the material of the walls to “rightArrow” and “leftArrow” and at the target point to put a special material at the top wall, but it never changes. Each wall in my case consists of walls – the inner and the outer, and the maze is generating correctly but the materials dont change. Here is my mazeSolver:
using System.Collections.Generic;
using UnityEngine;
public class MazeSolver : MonoBehaviour
{
public int mazeWidth = 5, mazeHeight = 5;
public MazeCell[,] maze;
public Vector2Int targetPoint;
public Material leftArrowMaterial;
public Material rightArrowMaterial;
public Material specialTopWallMaterial;
private MazeGenerator mazeGenerator;
private bool mazeGenerated = false;
void Start()
{
mazeGenerator = GetComponent<MazeGenerator>();
if (mazeGenerator != null)
{
// Subscribe to the MazeGenerationComplete event
mazeGenerator.MazeGenerationComplete += OnMazeGenerationComplete;
mazeGenerator.GenerateMaze(); // Start maze generation
}
else
{
Debug.LogError("MazeGenerator component not found!");
}
}
void OnMazeGenerationComplete()
{
maze = mazeGenerator.maze;
mazeGenerated = true;
Debug.Log("Maze generation complete. Starting pathfinding...");
CalculateShortestPath();
}
void CalculateShortestPath()
{
if (!mazeGenerated)
{
Debug.LogError("Maze is not generated yet!");
return;
}
Debug.Log("Calculating shortest path...");
Queue<Vector2Int> queue = new Queue<Vector2Int>();
Dictionary<Vector2Int, Vector2Int> previous = new Dictionary<Vector2Int, Vector2Int>();
bool[,] visited = new bool[mazeWidth, mazeHeight];
Vector2Int[] directions = { Vector2Int.left, Vector2Int.right, Vector2Int.up, Vector2Int.down };
queue.Enqueue(targetPoint);
visited[targetPoint.x, targetPoint.y] = true;
int iteration = 1;
while (queue.Count > 0)
{
Vector2Int current = queue.Dequeue();
foreach (Vector2Int direction in directions)
{
Vector2Int neighbor = current + direction;
if (IsValidCell(neighbor) && !visited[neighbor.x, neighbor.y] && !IsWallBetween(current, neighbor))
{
queue.Enqueue(neighbor);
visited[neighbor.x, neighbor.y] = true;
previous[neighbor] = current;
}
}
Debug.Log("Iteration " + iteration);
iteration++;
}
Debug.Log("Pathfinding complete. Updating maze with arrows...");
UpdateMazeWithArrows(previous);
}
bool IsValidCell(Vector2Int cell)
{
return cell.x >= 0 && cell.x < mazeWidth && cell.y >= 0 && cell.y < mazeHeight;
}
bool IsWallBetween(Vector2Int cell1, Vector2Int cell2)
{
if (cell1.x < cell2.x) return maze[cell1.x, cell1.y].rightWall;
if (cell1.x > cell2.x) return maze[cell2.x, cell2.y].rightWall;
if (cell1.y < cell2.y) return maze[cell1.x, cell1.y].topWall;
if (cell1.y > cell2.y) return maze[cell2.x, cell2.y].topWall;
return false;
}
void UpdateMazeWithArrows(Dictionary<Vector2Int, Vector2Int> previous)
{
if (!mazeGenerated)
{
Debug.LogError("Maze is not generated yet!");
return;
}
Debug.LogWarning("Updating maze with arrows...");
if (mazeWidth == 1 && mazeHeight == 1 && targetPoint == Vector2Int.zero)
{
Debug.Log("Maze is 1x1 with target at (0, 0). Applying special material to the single cell.");
// Apply special material to the single cell
ApplySpecialMaterialToTopWall(Vector2Int.zero);
return;
}
foreach (KeyValuePair<Vector2Int, Vector2Int> entry in previous)
{
Vector2Int from = entry.Key;
Vector2Int to = entry.Value;
// Ensure 'from' and 'to' are valid maze coordinates
if (IsValidCell(from) && IsValidCell(to))
{
// Apply arrows based on direction
if (to.x > from.x)
{
ApplyMaterialToWall(from, Direction.Right, rightArrowMaterial);
}
else if (to.x < from.x)
{
ApplyMaterialToWall(from, Direction.Left, leftArrowMaterial);
}
else if (to.y > from.y)
{
ApplyMaterialToWall(from, Direction.Up, rightArrowMaterial); // Assuming up arrow material same as right
}
else if (to.y < from.y)
{
ApplyMaterialToWall(from, Direction.Down, leftArrowMaterial); // Assuming down arrow material same as left
}
// Check if this is the target point
if (to == targetPoint)
{
Debug.Log("target point");
ApplySpecialMaterialToTopWall(targetPoint);
}
}
else
{
Debug.LogWarning("Invalid maze coordinates in previous dictionary: from=" + from + ", to=" + to);
}
}
}
void ApplySpecialMaterialToTopWall(Vector2Int cell)
{
MazeCell mazeCell = maze[cell.x, cell.y];
if (mazeCell.topWallObject != null)
{
Debug.Log("Applying special material to top wall of target cell");
mazeCell.topWallObject.GetComponent<Renderer>().material = specialTopWallMaterial;
}
else
{
Debug.LogWarning("topWallObject is null for the target cell");
}
}
void ApplyMaterialToWall(Vector2Int cell, Direction direction, Material material)
{
Debug.Log("Applying material to wall:" + material);
MazeCell mazeCell = maze[cell.x, cell.y];
Debug.Log("Cell.x,cell.y and direction is= " + cell.x + cell.y + direction);
switch (direction)
{
case Direction.Up:
if (mazeCell.topWallObject != null)
{
SetMaterialForWallObjects(mazeCell.topWallObject, material);
}
break;
case Direction.Down:
if (mazeCell.bottomWallObject != null)
{
SetMaterialForWallObjects(mazeCell.bottomWallObject, material);
}
break;
case Direction.Left:
if (mazeCell.leftWallObject != null)
{
SetMaterialForWallObjects(mazeCell.leftWallObject, material);
}
break;
case Direction.Right:
if (mazeCell.rightWallObject != null)
{
SetMaterialForWallObjects(mazeCell.rightWallObject, material);
}
break;
}
}
void SetMaterialForWallObjects(GameObject wallParent, Material material)
{
// Assuming the outer and inner walls are children of wallParent
foreach (Transform child in wallParent.transform)
{
Debug.Log("Applying material to wall in set for wall objects" + material);
Renderer renderer = child.GetComponent<Renderer>();
if (renderer != null)
{
renderer.material = material;
}
}
}
Dictionary<Vector2Int, Vector2Int> previous;
}
my mazeRenderer:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MazeRenderer : MonoBehaviour
{
public MazeCell[,] maze;
[SerializeField] MazeGenerator mazeGenerator;
[SerializeField] GameObject MazeCellPrefab;
public float CellSize = 1f;
private void Start()
{
// Get MazeGenerator component and subscribe to maze generation complete event
mazeGenerator = GetComponent<MazeGenerator>();
if (mazeGenerator != null)
{
mazeGenerator.MazeGenerationComplete += RenderMaze;
}
else
{
Debug.LogError("MazeGenerator component not found on the same GameObject.");
}
}
void RenderMaze()
{
// Ensure mazeGenerator and maze are not null
if (mazeGenerator == null || mazeGenerator.maze == null)
{
Debug.LogError("MazeGenerator or maze is null. Maze cannot be rendered.");
return;
}
maze = mazeGenerator.maze;
for (int x = 0; x < mazeGenerator.mazeWidth; x++)
{
for (int y = 0; y < mazeGenerator.mazeHeight; y++)
{
GameObject newCell = Instantiate(MazeCellPrefab, new Vector3((float)x * CellSize, 0f, (float)y * CellSize), Quaternion.identity, transform);
MazeCellObject mazeCell = newCell.GetComponent<MazeCellObject>();
bool top = maze[x, y].topWall;
bool left = maze[x, y].leftWall;
bool right = false;
bool bottom = false;
if (x == mazeGenerator.mazeWidth - 1) right = true;
if (y == 0) bottom = true;
mazeCell.Init(top, bottom, right, left);
}
}
}
}
and my mazeGenerator:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MazeGenerator : MonoBehaviour
{
public int mazeWidth = 10, mazeHeight = 10; // The dimensions of the maze
public int startX, startY; // The start position of the maze
public GameObject lightPrefab;
public GameObject vrCharacter; // Reference to the VR character
private MazeCell[,] _maze; // An array of maze cells
public MazeCell[,] maze
{
get { return _maze; }
private set { _maze = value; } // Private setter
}
Vector2Int currentCell; // Current cell position
// Event to notify when maze generation is complete
public event Action MazeGenerationComplete;
// Start is called before the first frame update
void Start()
{
// Disable directional light
GameObject directionalLight = GameObject.Find("Directional Light");
if (directionalLight != null)
{
directionalLight.SetActive(false);
}
// Set ambient light to dark
RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat;
RenderSettings.ambientLight = Color.black;
// Enable and configure fog
RenderSettings.fog = true;
RenderSettings.fogMode = FogMode.ExponentialSquared;
RenderSettings.fogColor = Color.black;
RenderSettings.fogDensity = 0.05f;
GenerateMaze();
}
public void GenerateMaze()
{
maze = new MazeCell[mazeWidth, mazeHeight];
for (int x = 0; x < mazeWidth; x++)
{
for (int y = 0; y < mazeHeight; y++)
{
maze[x, y] = new MazeCell(x, y);
if (x % 4 == 0 && y % 4 == 0)
{
Vector3 cellPosition = new Vector3(x, 0, y); // Adjust the y value as needed
Instantiate(lightPrefab, cellPosition, Quaternion.identity);
}
}
}
CarvePath(startX, startY);
// Select an edge cell as the target point and add the special cell
Vector2Int targetPoint = SelectEdgeCell();
PositionCharacterAtStart();
// Notify listeners (like MazeSolver) that maze generation is complete
if (MazeGenerationComplete != null)
{
MazeGenerationComplete.Invoke();
}
}
Vector2Int SelectEdgeCell()
{
List<Vector2Int> edgeCells = new List<Vector2Int>();
// Top row
for (int x = 0; x < mazeWidth; x++)
{
edgeCells.Add(new Vector2Int(x, mazeHeight - 1));
}
// Right column
for (int y = 1; y < mazeHeight - 1; y++)
{
edgeCells.Add(new Vector2Int(mazeWidth - 1, y));
}
// Select a random edge cell
int rndIndex = UnityEngine.Random.Range(0, edgeCells.Count);
return edgeCells[rndIndex];
}
/*void AddSpecialCell(int x, int y)
{
if (x < 0 || y < 0 || x > mazeWidth - 1 || y > mazeHeight - 1)
{
Debug.LogWarning("Special cell position is out of bounds");
return;
}
// Instantiate the special cell
GameObject specialCell = Instantiate(specialCellPrefab);
// Find the attach point in the special cell
Transform attachPoint = specialCell.transform.Find("AttachPoint");
if (attachPoint == null)
{
Debug.LogError("AttachPoint not found in special cell prefab");
return;
}
// Calculate the position of the special cell based on the attach point
Vector3 cellPosition = new Vector3(x, 0, y);
Vector3 offset = attachPoint.position - specialCell.transform.position;
specialCell.transform.position = cellPosition - offset;
// Remove the appropriate wall of the target cell to create an entrance
if (x == mazeWidth - 1) // Right edge
{
maze[x, y].leftWall = false; // The right wall is part of the next cell's left wall
}
else if (y == mazeHeight - 1) // Top edge
{
maze[x, y].topWall = false;
}
}*/
void PositionCharacterAtStart()
{
if (vrCharacter != null)
{
Vector3 startPosition = new Vector3(0, 1, 0); // Adjust the y value to place the character correctly on the ground
vrCharacter.transform.position = startPosition;
vrCharacter.transform.rotation = Quaternion.identity; // Reset rotation if needed
}
}
List<Direction> directions = new List<Direction>
{
Direction.Up, Direction.Down, Direction.Left, Direction.Right
};
List<Direction> GetRandomDirections()
{
// A copy of our directions list
List<Direction> dir = new List<Direction>(directions);
// A directions list to put our randomised directions into
List<Direction> rndDir = new List<Direction>();
while (dir.Count > 0)
{
int rnd = UnityEngine.Random.Range(0, dir.Count);
rndDir.Add(dir[rnd]);
dir.RemoveAt(rnd);
}
return rndDir;
}
bool IsCellValid(int x, int y)
{
// If the cell is outside the map or if it was already visited it will be considered invalid
if (x < 0 || y < 0 || x > mazeWidth - 1 || y > mazeHeight - 1 || maze[x, y].visited) return false;
else return true;
}
Vector2Int CheckNeighbours()
{
List<Direction> rndDir = GetRandomDirections();
for (int i = 0; i < rndDir.Count; i++)
{
Vector2Int neighbour = currentCell;
switch (rndDir[i])
{
case Direction.Up:
neighbour.y++;
break;
case Direction.Down:
neighbour.y--;
break;
case Direction.Right:
neighbour.x++;
break;
case Direction.Left:
neighbour.x--;
break;
}
if (IsCellValid(neighbour.x, neighbour.y)) return neighbour;
}
return currentCell;
}
void BreakWalls(Vector2Int primaryCell, Vector2Int secondaryCell)
{
if (primaryCell.x > secondaryCell.x) // Primary cell's left wall
{
maze[primaryCell.x, primaryCell.y].leftWall = false;
}
else if (primaryCell.x < secondaryCell.x) // Secondary cell's left wall
{
maze[secondaryCell.x, secondaryCell.y].leftWall = false;
}
else if (primaryCell.y < secondaryCell.y) // Primary cell's top wall
{
maze[primaryCell.x, primaryCell.y].topWall = false;
}
else if (primaryCell.y > secondaryCell.y) // Secondary cell's top wall
{
maze[secondaryCell.x, secondaryCell.y].topWall = false;
}
}
void CarvePath(int x, int y)
{
if (x < 0 || y < 0 || x > mazeWidth - 1 || y > mazeHeight - 1)
{
x = y = 0;
Debug.LogWarning("Starting position is out of bounds, defaulting to 0,0");
}
currentCell = new Vector2Int(x, y);
List<Vector2Int> path = new List<Vector2Int>();
bool deadEnd = false;
while (!deadEnd)
{
Vector2Int nextCell = CheckNeighbours();
if (nextCell == currentCell)
{
for (int i = path.Count - 1; i >= 0; i--)
{
currentCell = path[i];
path.RemoveAt(i);
nextCell = CheckNeighbours();
if (nextCell != currentCell)
{
break;
}
}
if (nextCell == currentCell)
{
deadEnd = true;
}
}
else
{
BreakWalls(currentCell, nextCell);
maze[currentCell.x, currentCell.y].visited = true;
currentCell = nextCell;
path.Add(currentCell);
}
}
}
}
public enum Direction
{
Up,
Down,
Left,
Right
}
public class MazeCell
{
public bool visited;
public int x, y;
public bool topWall;
public bool leftWall;
public bool rightWall;
public bool bottomWall;
public bool rightArrow;
public bool leftArrow;
// Reference to the wall GameObjects
public GameObject topWallObject;
public GameObject leftWallObject;
public GameObject rightWallObject;
public GameObject bottomWallObject;
public GameObject arrowObject;
// Return x,y as Vector2Int
public Vector2Int position
{
get
{
return new Vector2Int(x, y);
}
}
public MazeCell(int x, int y)
{
// The coordinates of this cell in the maze grid
this.x = x;
this.y = y;
visited = false;
topWall = leftWall = rightWall = bottomWall = true;
rightArrow = leftArrow = false;
}
}
Already checked that everything is applied correctly and I just dont get why doent it work.
Please help!