- Home /
NullReferenceException - Maze Generator Script
I keep getting a NullReferenceException on this C# script I'm writing to generate a maze.
Basically how it works is that I have a two-dimensional array of mazeCell objects (each of which contains four walls, and an isVisited member). I think the comments in the code are enough to explain it, but I'm getting this error on any of the four cases in the switch statement (in the line that says "if (tempCell.isVisited == true) // Check if target cell is visited or not").
Does anyone know why this is happening? This is my code: using UnityEngine; using System.Collections;
public class mazeCell
{
public bool isVisited;
public int topWall;
public int bottomWall;
public int rightWall;
public int leftWall;
public int heightCoordinate;
public int widthCoordinate;
public mazeCell()
{
isVisited = false;
topWall = 1;
bottomWall = 1;
rightWall = 1;
leftWall = 1;
}
}
public class mazeGenerateScript : MonoBehaviour
{
// Variables for the wall and position of the wall
public GameObject wallHorizontal;
public GameObject wallVertical;
public int xCoordinate = 0;
public int zCoordinate = 0;
// Master variables for the height and width of the entire maze
public static int height = 15;
public static int width = 20;
// An array of mazeCell objects
public mazeCell[,] mazeCellArray = new mazeCell[height + 1, width + 1];
// The stack that will hold all the visited mazeCell objects and control the backtracking
Stack cellStack = new Stack();
// Total number of cells and number of visited cells
int totalCells = height * width;
int visitedCells = 0;
// Use this for initialization
void Start()
{
// Create a new mazeCell object for each element in the mazeCell[,] array, and set the height and width coordinates accordingly
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
mazeCell tempCell = new mazeCell();
tempCell.heightCoordinate = i;
tempCell.widthCoordinate = j;
mazeCellArray[i, j] = tempCell;
}
}
// Create a random set of height and width coordinates for the starting cell
int startingHeight = Random.Range(0, height);
int startingWidth = Random.Range(0, width);
// Assign starting cell to the default instantiated mazeCell object at the random coordinates generated above
mazeCell currentCell = mazeCellArray[startingHeight, startingWidth];
// Loop that actually generates the maze
while (visitedCells < totalCells)
{
bool topVisited = false;
bool bottomVisited = false;
bool rightVisited = false;
bool leftVisited = false;
while (topVisited == false || bottomVisited == false || rightVisited == false || leftVisited == false)
{
int directionToTest = Random.Range(1, 4); // Creates a random number representing a direction. 1 for up, 2 for down, 3 for right, 4 for left
switch (directionToTest)
{
case 1: // Above current cell
if (currentCell.heightCoordinate - 1 < 0) // If out of range, set topVisited = true and continue looping (generating another random direction)
{
topVisited = true;
continue;
}
else // Not out of range
{
mazeCell tempCell = new mazeCell();
tempCell = mazeCellArray[currentCell.heightCoordinate - 1, currentCell.widthCoordinate]; // Set tempCell to the target cell (above)
if (tempCell.isVisited == true) // Check if target cell is visited or not
{
topVisited = true;
continue;
}
else // Target cell is not visited
{
currentCell.topWall = 0; // Break top wall of current cell
mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate] = currentCell; // Refresh current cell values in master array
tempCell.bottomWall = 0; // Break bottom wall of tempCell
tempCell.isVisited = true; // Set tempCell to visited
cellStack.Push(currentCell); // Push currentCell to the stack
currentCell = tempCell; // Set currentCell to tempCell
visitedCells++; // Increment the number of visited cells
break;
}
}
case 2: // Below current cell
if (currentCell.heightCoordinate + 1 > height) // If out of range, set bottomVisited = true and continue looping (generating another random direction)
{
bottomVisited = true;
continue;
}
else // Not out of range
{
mazeCell tempCell = new mazeCell();
tempCell = mazeCellArray[currentCell.heightCoordinate + 1, currentCell.widthCoordinate]; // Set tempCell to the target cell (below)
if (tempCell.isVisited == true) // Check if target cell is visited or not
{
bottomVisited = true;
continue;
}
else // Target cell is not visited
{
currentCell.bottomWall = 0; // Break bottom wall of current cell
mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate] = currentCell; // Refresh current cell values in master array
tempCell.topWall = 0; // Break top wall of tempCell
tempCell.isVisited = true; // Set tempCell to visited
cellStack.Push(currentCell); // Push currentCell to the stack
currentCell = tempCell; // Set currentCell to tempCell
visitedCells++; // Increment the number of visited cells
break;
}
}
case 3: // Right of current cell
if (currentCell.widthCoordinate + 1 > width) // If out of range, set rightVisited = true and continue looping (generating another random direction)
{
rightVisited = true;
continue;
}
else // Not out of range
{
mazeCell tempCell = new mazeCell();
tempCell = mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate + 1]; // Set tempCell to the target cell (right)
if (tempCell.isVisited == true) // Check if target cell is visited or not
{
rightVisited = true;
continue;
}
else // Target cell is not visited
{
currentCell.rightWall = 0; // Break right wall of current cell
mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate] = currentCell; // Refresh current cell values in master array
tempCell.leftWall = 0; // Break left wall of tempCell
tempCell.isVisited = true; // Set tempCell to visited
cellStack.Push(currentCell); // Push currentCell to the stack
currentCell = tempCell; // Set currentCell to tempCell
visitedCells++; // Increment the number of visited cells
break;
}
}
case 4: // Left of current cell
if (currentCell.widthCoordinate - 1 < 0) // If out of range, set leftVisited = true and continue looping (generating another random direction)
{
leftVisited = true;
continue;
}
else // Not out of range
{
mazeCell tempCell = new mazeCell();
tempCell = mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate - 1]; // Set tempCell to the target cell (above)
if (tempCell.isVisited == true) // Check if target cell is visited or not
{
leftVisited = true;
continue;
}
else // Target cell is not visited
{
currentCell.leftWall = 0; // Break left wall of current cell
mazeCellArray[currentCell.heightCoordinate, currentCell.widthCoordinate] = currentCell; // Refresh current cell values in master array
tempCell.rightWall = 0; // Break right wall of tempCell
tempCell.isVisited = true; // Set tempCell to visited
cellStack.Push(currentCell); // Push currentCell to the stack
currentCell = tempCell; // Set currentCell to tempCell
visitedCells++; // Increment the number of visited cells
break;
}
}
}
}
// If every surrounding cell is visited, backtrack along the stack
if (topVisited == true && bottomVisited == true && rightVisited == true && leftVisited == true)
currentCell = (mazeCell)cellStack.Pop();
}
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
mazeCell tempCell = new mazeCell();
tempCell = mazeCellArray[x, y];
if (tempCell.topWall == 0)
Instantiate(wallHorizontal, new Vector3(xCoordinate, 0, zCoordinate), Quaternion.identity);
if (tempCell.bottomWall == 0)
Instantiate(wallHorizontal, new Vector3(xCoordinate, 0, zCoordinate + 16), Quaternion.identity);
if (tempCell.leftWall == 0)
Instantiate(wallVertical, new Vector3(xCoordinate, 0, zCoordinate), Quaternion.identity);
if (tempCell.rightWall == 0)
Instantiate(wallVertical, new Vector3(xCoordinate + 16, 0, zCoordinate), Quaternion.identity);
xCoordinate = xCoordinate + 16;
}
zCoordinate = zCoordinate + 16;
}
}
// Update is called once per frame
void Update()
{
}
}
Answer by MarkFinn · Dec 26, 2012 at 05:00 AM
Your array mazeCellArray is 1 item higher and wider than height and width.
public mazeCell[,] mazeCellArray = new mazeCell[height + 1, width + 1];
When you populate it you only put in height by width mazeCells, so there is a row and column in the array which is empty.
// Create a new mazeCell object for each element in the mazeCell[,] array, and set the height and width coordinates accordingly
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
As soon as your builder loop hits one of the empty cells, it correctly enough has a null ref exception.
Just changed that (by removing the +1s), and now it's giving me an IndexOutOfRangeException on these lines (in each case block):
tempCell = mazeCellArray[currentCell.heightCoordinate - 1, currentCell.widthCoordinate]; // Set tempCell to the target cell (above)
It shouldn't be out of range though, because in the If statement right before that, I check whether it's out of range, and if it's out of range, it shouldn't even execute this line.
Remember, in all arrays the cells run from 0 to size_of_array - 1.
Change case 3: if to
if (currentCell.widthCoordinate + 1 >= width)
After which your code goes into an infinite loop (Unity Editor Freezes).
You need to rethink your end-of-loop conditions.
You're talking about the
while (topVisited == false || bottomVisited == false || rightVisited == false || leftVisited == false)
loop as being the infinite one, right? I can't really think of another way to create that one. I need the loop to cut out only if all four cells (in all four directions) are all visited, otherwise it has to execute the statements in the else block and then cut out of the loop. I'm not sure why it's looping infinitely, the continue statements should just go to the start of the loop and the break statements should end the while loop, right?
Sorry for asking so many questions, this is my first game with Unity, I wanted to do a random maze game to learn the engine.