Random Maze Generation using Unity 3D

 

Ok, before we go into any details, this is easier to understand if you have some knowledge of programming and by knowledge I mean you can understand data types and what a code is trying to say.

Now, random maze generation. It sounds so complex, so difficult to do. It is until you actually put your head into it and realize how easy it is in the end. I mean, this project that I will present was done in an hour or so and most of the time was figuring out how to put around the walls and rotate them into place.

Now, to build this all you need is a plane saved as a prefab, that is what will be instantiated, a camera (because you need to render the world), a directional light (you do want to see your world, right?) and an empty game object (this will be the generator. What?! Just read on…). Just set up your scene by putting the game object somewhere and creating the plane. Mind you, the plane should have the following scale: 0.1 x, 1 y, 0.1 z . That is just based on the calculations that are present in the code but they will be quick to modify, as long as you scale it right. Regarding planes, if it is 0.1 in size, then the next adjacent one could be at 1.0F world points away. Not that bad, eh?

Now, set up the scene. Next, create the script that will generate the whole thing. My script uses the following global variables:

public bool[,] mapArray;
public GameObject wall;
public int maxHeight;
public int maxWidth;

mapArray is going to be your map. Wall is the prefab that will be instantiated everywhere and maxHeight and maxWidth are the sizes of the map. The only variable that needs to be instantiated is the mapArray using mapArray = new bool [maxWidth,maxHeight]. Generating what will be in the array is even easier. You just run a traversing method such as a for or a while and you go:

int k=Random.Range(0,2);
if(k<1)
mapArray[i,j]=false;
else
mapArray[i,j]=true;

This code generates a random value as an integer that could be either 0 or 1 ( that’s how range works, generates numbers from the first parameter until the second parameter -1) and if it is 0 then it generates a wall, otherwise it generates a floor. False is wall, true is floor.

In my code, I am running the generation from 1 to maximumSize-1, but that’s because I’m then running a code to put walls on the edges of the array, so as to wall off the whole map. This patch of code is just :

for(int i=0;i<maxWidth;i++){
mapArray[i,0]=false;
}

Afterwards comes the interesting part: we have to instantiate all those wonderful little planes. This happens within a traversing method, of course, such as a double for or a double while. For example: for(int i=0;i<maxWidth;i++) for(int j=0;j<maxHeight;j++)

Then, the best way to generate it is to just wall off the unwalkable tiles, or the “walls”  as we have defined them. Then, for each wall we have to look at the tiles around it, so if you want to look at the tile above, it would be if(mapArray[i-1,j]==true), looking at the tile below would be if(mapArray[i+1,j]==true). In each of these if’s we should instantiate the game object as follows:

GameObject w = Instantiate (wall,Vector3.zero,Quaternion.identity) as GameObject;

Vector3 nextPos = new Vector3(i+-0.5F,0.5F,j);
w.transform.parent=gameObject.transform;
w.transform.localPosition=nextPos;
Quaternion rot = Quaternion.Euler (0,0,90);
w.transform.rotation=rot;

the first line will instantiate. the second line will generate its position. Now watch it, I have put there i+-0.5F, that’s because it depends on which position you are checking. The same will be for the rotation Quaternion rot.
If you are checking at mapArray[i-1,j] then you should use Vector3 nextPos = new Vector3(i-0.5F,0.5F,j), otherwise have Vector3 nextPos = new Vector3(i+0.5F,0.5F,j). The same would go for Quaternion rot. If you are checking for i-1, you should have rot = Quaternion.Euler (0,0,90). Otherwise, have rot = Quaternion.Euler (0,0,270);

If you are checking at the edges you should account for it so that you are not overstepping, thus creating an index out of bounds exception. If you are at coordinate 0 just check above and if you are at the maximumSize-1 coordonate, just check below.

The same could can be modified and be used for the sides, or the j variable. The only difference is in modifying the z value in the position and in flipping the rotation values so that if it is to the left you use 270 for the rotation value and vice versa.

With that set and done you should be good to go. Your maze could look like one in the part below, just that it is incredibly big. The bigger you make it, the more time it would take. You could also modify the threshold for generating unwalkable tiles. I for example have switched them to public values so that I could modify them freely in the editor. This way I could make it so that 70% of all tiles are walls, or 32% are walls and so on. You could use maxSize instead of maxWidth or maxHeight. maxSize is useful if you want to make squared maps, while the others are good for rectangular maps.

But what I’ve given you here is the tip of the iceberg. You can go on and be crazy and make more awesome stuff, or even a wolfenstein remake, or even create rooms that you can randomly attach one to another. Go Crazy! You might just make a better thing than I did ;)

Maze

P.S. If you want the code or the project, just e-mail me.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>