# How to instantiate prefabs between 2 objects like a path

Hi,
I am trying to make a level generator using prefabs. I want to generate a path of prefabs between 2 objects.

However! These instantiated prefabs have fixed sizes, and need to connect with each other. Eventually the purpose is that the prefabs will be instantiated in a grid-like manner. And each time the path would be different.
A L shape towards the end position. Or just a “curvy” path towards the end position.
Of course the instantiated prefabs will be randomized each time as well. (but this is easy)

Attached an example:

I am not asking for an script, merely a push in the right direction. I honestly don’t know where to start.

This is the beginning of the “test” script what i came up with.

``````var startNode : Transform;
var endNode : Transform;
var nodes : Transform;

var startPosition : Vector3;
var endPosition : Vector3;

private var distance : float;
private var center : Vector3;

function Start()
{
startPosition = Vector3(0, 0, 0);
endPosition = Vector3(startPosition.x + 5 * 5, 0,startPosition.z + 5 * 6);

Instantiate(startNode, startPosition, Quaternion.identity);
Instantiate(endNode, endPosition, Quaternion.identity);

GeneratePath();
}

function GeneratePath()
{

}
``````

So the startNode and endNode will be instantiated(eventually at a random location). And between them the generated “path”. Of course the code that i have posted isn’t much. But like i said, i just don’t know where to start.

I really hope someone can help me!

Darryl

Use two FOR loops with an y and x incrementing. Add x and y to the spawn vector x and y. You can use certain conditions to determine if a tile is spawned on x or y, like a 2d array with bools or something like that.

Hey Fluzing, so i looked into a 2d array. Never heard of them before, and never used them before.
So i have to say, they are pretty hard to understand for me. However. I have a better start right now.

This is how the script looks right now. (still no actual path, but a working grid array with an start and a end cell)

``````public var gridX : int = 7;
public var gridZ : int = 7;

public var xSpacing : int = 5;
public var zSpacing : int = 5;
public var cellPrefab : GameObject;
public var startingCell : GameObject;
public var endCell : GameObject;

public var delay : float = 0.25;

public var gridArray : RoomCell[,];

private var startEndPositions : int = 6;
public var startPosition : int[];
public var endPosition : int[];

public class RoomCell
{
public var room : GameObject;
public var zone : String;
}

function Start()
{
gridArray = new RoomCell[gridX,gridZ];

startPosition = new int[2];
endPosition = new int[2];

StartEndPosition();
}

function StartEndPosition()
{
startEndPositions = 6;

switch(startEndPositions)
{
case 6:                    //Start position bottom row, end position top row
print ("6 : start bottom - end top");
startPosition[0] = Random.Range(0, gridX);
startPosition[1] = 0;
endPosition[0] = Random.Range(0, gridX);
endPosition[1] = gridZ-1;
break;
case 5:                    //Start position bottom row, end position top row
print("5 : start bottom - end top");
break;
case 4:                    //Start position top row, end position bottom row
print("4 : start top - end bottom");
break;
case 3:                    //Start position left collumn, end position top side
print("3 : start left - end top");
break;
case 2:                    //Start position bottom row, end position right collumn
print ("2 : start bottom - end right");
break;
case 1:                    //Start position left collumn, end position right collumn
print ("1 : start left - end right");
break;
default:                //Start position bottom row, end position top row
print ("default : start bottom - end top");
break;
}

GenerateGrid();
}

function GenerateGrid()
{
for(var x = 0; x < gridArray.GetLength(0); x++)
{
for(var z = 0; z < gridArray.GetLength(1); z++)
{
yield WaitForSeconds(delay);

GenerateCell(x, z);
}
}
}

function GenerateCell(x : int, z : int)
{
var cell : RoomCell = RoomCell();

cellLocation = Vector3(x * xSpacing, 0, z * zSpacing);

if(x == startPosition[0] && z == startPosition[1])
{
newCell = Instantiate(startingCell, cellLocation, Quaternion.identity);
}
else if(x == endPosition[0] && z == endPosition[1])
{
newCell = Instantiate(endCell, cellLocation, Quaternion.identity);
print("ENDCELL");
}
else
{
newCell = Instantiate(cellPrefab, cellLocation, Quaternion.identity);
}

newCell.name = "Cell: " + x + ", " + z;
newCell.transform.parent = transform;
}
``````

At first the end cell was not working, but got it to work luckily! Also i have to put more locations in the switch function, but i had to test it out first.

Here is a screenshot of the actual grid.

Now i have to find a way to instantiate the path form start to end position. And make it so, that the path cells can not overlap each other. So they have to check if the cell in the 2d array is taken or not.

Anyway thanks!

Cheers, Darryl

Well, thought of posting some progress over here, i recently switched to C#.

Deleted the old script, redid the whole thing. Still finding it quite hard. Right now i have two 2D arrays. One int and one GameObject.

The int is for initializing the level data: 0 = empty, 1 = occupied, 2 = startingroom etc.(right now just 3 of them)

The GameObject will be used for the actual rooms. I have an function working which checks adjacent cells.
But doesn’t do anything at the moment, just for testing.

I am trying to figure out to choose a random direction to instantiate the next cell. Now this is giving me a hard time.
The idea is, to call the adjacent cell function and check if there is an open space, if there is. Then set it to 1, and instantiate cell on that place. Anyway here is the script at the moment:

``````using UnityEngine;
using System.Collections;

public class LevelGenerator : MonoBehaviour
{
public int width = 15;            //Width of the level grid
public int length = 15;            //Length of the level grid

public int iterations = 5;        //How many iterations are instantiated

public int[,] levelArray;        //A 2D array of ints, managing level data

public float delay = 0.3f;        //Float handling a delay between each instantiate of GameObject

public GameObject cellPrefab;
private GameObject[,] cells;    //A 2D array of GameObjects representing cells

private Direction direction;    //Controlling the enum: Direction
private const int count = 4;    //Int to declare the amount of choices in the enum: Direction

public GameObject lastRoom;

public enum Direction            //Enum for deciding which direction to take
{
up,
down,
left,
right
}

void Awake()
{
levelArray = new int[width,length];
cells = new GameObject[width,length];

direction = (Direction)Random.Range(0,count);

print("Direction: " + direction);

for(int x = 0; x < width; x++)
{
for(int z = 0; z < length; z++)
{
if(x == Random.Range (0,width) && z == Random.Range(0,length))
{
levelArray[x,z] = 2;
}
else
{
levelArray[x,z] = 0;
}
}
}

//StartCoroutine(Generate());
}

//public IEnumerator Generate()
//{

//    while(iterations > 0)
//    {
//        yield return new WaitForSeconds(delay);
//
//        if(lastRoom == null)
//        {
//            print("IEnumerator");
//            CreateCell(Random.Range(0,width),Random.Range(0,length));
//        }
//        else
//        {
//
//            iterations -= 1;
//        }
//    }
//}

void CreateCell(int x, int z)
{
Vector3 cellPosition = new Vector3(x * 5, 0, z * 5);

if(levelArray[x,z] == 2)
{
cells[x,z] = (GameObject) Instantiate(cellPrefab, cellPosition,Quaternion.identity);
cells[x,z].name = ("Starting Cell: " + x + ", " + z);
cells[x,z].transform.parent = transform;
}
else if(levelArray[x,z] == 1)
{
cells[x,z] = (GameObject) Instantiate(cellPrefab, cellPosition,Quaternion.identity);
cells[x,z].name = ("Cell: " + x + ", " + z);
cells[x,z].transform.parent = transform;
}

lastRoom = cells[x,z];
}

{
for(int x = _x - 1; x < _x + 2; x++)
{
for(int z = _z -1; x < _z + 2; z++)
{
if(x == _x && z == _z)
{
print("Our current cell");
continue;
}
else if(x <= 0 || x >= width || z <= 0 || z >= length)
{
print("Out of array index");
continue;
}
else if(x > _x && z == _z)
{

}
else if(x < _x && z == _z)
{

}
else if(x == _x && z > _z)
{

}
else if(x == _x && z < _z)
{

}
}
}
NextDirection(_x, _z);
}

void NextDirection(int x, int z)
{

switch(direction)
{
case Direction.up:
print("UP");
break;

case Direction.down:
print("DOWN");
break;

case Direction.right:
print("RIGHT");
break;

case Direction.left:
print("LEFT");
break;

default:
print("NOTHING");
break;
}

}
}
``````

If you guys have any ideas or tips, it will be extremely helpful!

Cheers,
Darryl

You could write an ant algorithm, basically an “ant” (position in code on the 2D grid, starts at your starting point) crawls along your grid, in the general direction of the endPoint, and chooses random left or right turns (using an error calculation to determine if it can turn the way it wants, e.g if the angle would be too far from the endPoint). Then by the time the ant reaches the endPoint the algorithm is finished. And your path is created! Hope this helps.

EDIT: Also just a suggestion, but how you intialise your 2D arrays, and you check while the for loops are running for random positions. A better idea would be to first initialize the 2D array all zeroes, and then choose two sets of random coordinates when the for loops finish, and place your start and end points, you’ll be guaranteed to have a start and end, and only one of each. Hope this helps!

I’m not sure if this would help but why dont you just try adding a empty GameObject on each cell that has a reference to the gameobject you want to spawn and just make it spawn randomly when u want throught a timer or such? that or u can always get a random number based on the cell position where the player is and the end and get the cell at position (randx, randy)

Ex: player at position 2, end at position 5
cell[Random Range 2 to 5,Random Range 2 to 5].SpawnObjectMethodNameHere=herpderp

http://tinysubversions.com/spelunkyGen/
I am not sure if this is what you want, but this shows how Spelunky’s procedural level generation works. (Basically, making sure there’s a path from start to finish, and then filling the rest)

There is always a path already made, what he is trying to do is make it spawn a certain object on a “random” cell between the player and the end

I get that, that guide thing also talks about filling in the empty spaces, which include things like “A ladder between the start and the end” or so I believe.
I did not read it yet, I just remembered that article.

Well i finally have a working level generator!!! I took your advise(TwixEmma), in the Start() method i “generated” the grid.
Setting each type to 0. And later on when the actual level is being generated, switch accordingly.

I also looked at the link you(MrPriest) provided and it was a good read!

However i switched(again) from two 2D arrays to 1 2D array this time a 2D array of Classes where i will store all sorts of data.

Here is a screenshot how a level looks like once “completed”(it doesn’t have an end position yet, but thats easy to add)

Green is obvious the starting position. This is just a simple GUI fit to screen width and length screenshot.

However! I have an Adjacent room check in my script, which works. But i want to pass data to each room for example:

how many rooms is this room connected?
which directions is this room connected to? North, south, east, west?

The Adjacent room check is working, so i thought this would be easy to implement but i was wrong. If i use the Adjacent room check to add value to the room connections, it gives my wrong values ranging from 1 to 6(which would never be possible).

When i declare a room type on the given position and try to pass value on it then, it still gives me wrong values.

Here is the script:

``````using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MapGenerator : MonoBehaviour
{
public int width = 15;                //total width of the grid
public int length = 15;             //total length of the grid

public RoomID[,] mapArray;            //2d array of classes that holds everything

//PRIVATE VARIABLES

//level variables
public int level;                    //our current level we are on, this to determine difficulty and level size
public int rooms;                    //this variable will handle how many rooms have been built
public int iterations;                //how many rooms will be instantiated? This will randomize itself at the beginning

//current positions variables
private int curRoom;                //current room int which we use to get values of the Vector2 list below
private int curRoomPosX;            //these curRoomPosX and Z variables will keep track on which position we currently are
private int curRoomPosZ;            //this to determine our next position whith the newRoomPosX and Z variable
private Vector2[] roomPositions;    //list of Vector2 positions to determine where the next RANDOM room can be placed

//next position variables
private int newDirection;            //this variable will keep track which direction we want the next room to be set
private int newRoomPosX;            //this variable will set the next rooms position on the X axis
private int newRoomPosZ;            //this variable will set the next rooms position on the Z axis

private bool complete;                //level generating is completed

public float miniMapX;                //mini map width
public float miniMapZ;                //mini map height

public Texture2D startingRoom;
public Texture2D basicRoom;
public Texture2D empty;

private float iconX;                //icon width of each room
private float iconZ;                //icon height of each room

void Start()
{
mapArray = new RoomID[width, length];        //Assign the width and length value to the 2d Array grid
rooms = 0;                                    //just to be sure
iterations = Random.Range(5 + (level * 2), 7 + (level * 3));    //randomize iterations
roomPositions = new Vector2[iterations+1];    //set the roomPositions Vector2 array higher then iterations by 1

miniMapX = Screen.width;                    //for now set the mini map to cover the whole screen
miniMapZ = Screen.height;

iconX = (miniMapX/width);
iconZ = (miniMapZ/length);

//A 2 for loop, generating the grid and assigning basic values
for(int x = 0;x < width; x++)
{
for(int z = 0; z < length; z++)
{
mapArray[x,z] = new RoomID();        //create a RoomID instance in each cell on the grid
mapArray[x,z].xPos = x;                //passing the x value to the RoomID x position
mapArray[x,z].zPos = z;                //passing the z value to the RoomID z position
mapArray[x,z].type = 0;                //each starting cell is an empty room, so we set this to 0
}
}

Generate();                                    //calling the generate method for actual generating
}

void Generate()
{
//while rooms is equal or less then iterations, we start building rooms
while(rooms <= iterations)
{
if(rooms == 0)
{
roomPositions[rooms] = new Vector2(width/2,length/2);

mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].type = 2;
mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].id = rooms;

rooms++;
}
else
{
curRoom = Random.Range(0, rooms);                //grab random room in rooms so we know where to build next

curRoomPosX = (int)roomPositions[curRoom].x;    //set curRoomPosX to roomPositionsX value which we picked earlier
curRoomPosZ = (int)roomPositions[curRoom].y;    //set curRoomPosZ to roomPositionsY value which we picked earlier

newDirection = Random.Range(1,5);                //Randomly choose next direction each time we build a new room

if(newDirection == 1)        //NORTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ + 1;
}
else if(newDirection == 2)    //EAST
{
newRoomPosX = curRoomPosX + 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 3)    //SOUTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ - 1;
}
else if(newDirection == 4)    //WEST
{
newRoomPosX = curRoomPosX - 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 5)    //OUT OF RANGE
{
Debug.Log("Out of range!");
}

//we just have to make sure that the new position is on the grid
if(newRoomPosX < width && newRoomPosX > 0 && newRoomPosZ < length && newRoomPosZ > 0)
{
if(mapArray[newRoomPosX, newRoomPosZ].type == 0)    //roomtype = 0, so space is available
{

{
//More then 1 adjacent rooms, which we try to avoid so we do not have 1 big square level
}
else
{
roomPositions[rooms] = new Vector2(newRoomPosX, newRoomPosZ);

mapArray[newRoomPosX,newRoomPosZ].type = 1;
mapArray[newRoomPosX,newRoomPosZ].id = rooms;    //set the RoomID.id equal to rooms

rooms++;
}
}
else
{
//Debug.Log("Cell already taken, searching for new space");
}
}
else
{
//Debug.Log("Out of the grid, searching for new space.");
}
}
}

if(rooms >= iterations)
{
complete = true;
}
}

//this is used to calculate how many adjacent rooms we have
//it does a 2 for loop where it looks around the current room position from -1 to +1
//in UP DOWN LEFT and RIGHT direction, then if the room type is NOT 0, we add 1 to the newRoomAdjacents
{

for(int _x = -1; _x < x + 2; _x++)
{
for(int _z = -1; _z < z + 2; _z++)
{
if(_x > 0 && _x < width && _z > 0 && _z < length)
{
if(_x == x && _z == z)
{
continue;
}
if(_x > x && _z == z && mapArray[_x,_z].type != 0)
{
//mapArray[_x,_z].connections ++;  <-----TRYING TO ADD CONNECTIONS
}
if(_x < x && _z == z && mapArray[_x,_z].type == 1)
{
}
if(_x == x && _z > z && mapArray[_x,_z].type != 0)
{
}
if(_x == x && _z < z && mapArray[_x,_z].type != 0)
{
}
}
}
}
}

void OnGUI()
{
if(complete)
{

GUI.BeginGroup(new Rect(2,2,miniMapX,miniMapZ));

for(int x = 0; x < width; x++)
{
for(int z = 0; z < length; z++)
{
if(mapArray[x,z].type == 2)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), startingRoom);
}
else if(mapArray[x,z].type == 1)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), basicRoom);

//GUI.Label(new Rect(x*iconX,z*iconZ,iconX-1,iconZ-1),"W: " + mapArray[x,z].wConnected);
}
else if(mapArray[x,z].type == 0)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-1,iconZ-1), empty);
}
}
}

GUI.EndGroup();

}
}
}
``````

And here is the RoomID Class:

``````using UnityEngine;
using System.Collections;

public class RoomID
{
public int type;            //0 = empty
//1 = basic room(which may contain enemies or not)
//2 = starting room
//3 = boss room
//4 = treasure room
//5 = shop

public int id;                //this rooms unique ID

public int intensity;        //for a basic, miniboss or boss room, how difficult it is(more enemies, stronger enemies)
public int connections;        //with how many rooms is this room connected

public bool nConnected;        //north connected
public bool sConnected;        //south connected
public bool eConnected;        //east connected
public bool wConnected;        //west connected

public int xPos;            //its X axis position on the grid
public int zPos;            //its Z axis position on the grid
}
``````

I hope anyone can help me!

Cheers,
Darryl

I remember solving that issue, @darryldonohoe . It blew my mind the first time

Make your nConnected, sConnected, eConnected and wConnected variables the same class that they are in. Then you will have a reference to every room a room is connected to and access to all of it’s data from the room you are in. What is currentRoom.nConnected.nConnected? The room 2 rooms north of yours!

This is useful for making grids that need to be connected for path finding. When making a class of nodes, you make an array of nodes inside it (the same class type) and those nodes represent the other nodes connected to this one.

Hey Tomnnn, the problem is, that the nConnected and so on are not working as they should be. They tend to turn true while it shouldn’t be possible. For example:

The W is wrong, it should say E. So they are not checking for their west side, but for their east side!

As you can see, the room on the most left, should have a true value, but it is false. As well as the room on the same row on the most right, should have it to false.

I thought it was a problem with the double for loop, but that was not the case.(or at least not that i can find)

So after the first problem(the actual generating), I have to look for a way to fix the new problem!

Cheers,
Darryl

Well finally found a way to make it sort of work, but it sometimes gives me errors, while most rooms are correct.
There are occasionally rooms which say that eastConnected or westConnected are false, while they should be true.

Anyway here is the code, let me know what you think. (any improvements or hopefully the solution)

``````using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MapGenerator : MonoBehaviour
{
public int width = 15;                //total width of the grid
public int length = 15;             //total length of the grid

public RoomID[,] mapArray;            //2d array of classes that holds everything

//PRIVATE VARIABLES

//level variables
public int level;                    //our current level we are on, this to determine difficulty and level size
public int rooms;                    //this variable will handle how many rooms have been built
public int iterations;                //how many rooms will be instantiated? This will randomize itself at the beginning

//current positions variables
private int curRoom;                //current room int which we use to get values of the Vector2 list below
private int curRoomPosX;            //these curRoomPosX and Z variables will keep track on which position we currently are
private int curRoomPosZ;            //this to determine our next position whith the newRoomPosX and Z variable
private Vector2[] roomPositions;    //list of Vector2 positions to determine where the next RANDOM room can be placed

//next position variables
private int newDirection;            //this variable will keep track which direction we want the next room to be set
private int newRoomPosX;            //this variable will set the next rooms position on the X axis
private int newRoomPosZ;            //this variable will set the next rooms position on the Z axis

private bool complete;                //level generating is completed

public float miniMapX;                //mini map width
public float miniMapZ;                //mini map height

public Texture2D startingRoom;
public Texture2D basicRoom;
public Texture2D empty;

private float iconX;                //icon width of each room
private float iconZ;                //icon height of each room

void Start()
{
mapArray = new RoomID[width, length];        //Assign the width and length value to the 2d Array grid
rooms = 0;                                    //just to be sure
iterations = Random.Range(5 + (level * 2), 7 + (level * 3));    //randomize iterations
roomPositions = new Vector2[iterations+1];    //set the roomPositions Vector2 array higher then iterations by 1

miniMapX = Screen.width;                    //for now set the mini map to cover the whole screen
miniMapZ = Screen.height;

iconX = (miniMapX/width);
iconZ = (miniMapZ/length);

//A 2 for loop, generating the grid and assigning basic values
for(int x = 0;x < width; x++)
{
for(int z = 0; z < length; z++)
{
mapArray[x,z] = new RoomID();        //create a RoomID instance in each cell on the grid
mapArray[x,z].xPos = x;                //passing the x value to the RoomID x position
mapArray[x,z].zPos = z;                //passing the z value to the RoomID z position
mapArray[x,z].type = 0;                //each starting cell is an empty room, so we set this to 0
}
}

Generate();                                    //calling the generate method for actual generating
}

void Generate()
{
//while rooms is equal or less then iterations, we start building rooms
while(rooms <= iterations)
{
if(rooms == 0)
{
roomPositions[rooms] = new Vector2(width/2,length/2);

mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].type = 2;
mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].id = rooms;

rooms++;
}
else
{
curRoom = Random.Range(0, rooms);                //grab random room in rooms so we know where to build next

curRoomPosX = (int)roomPositions[curRoom].x;    //set curRoomPosX to roomPositionsX value which we picked earlier
curRoomPosZ = (int)roomPositions[curRoom].y;    //set curRoomPosZ to roomPositionsY value which we picked earlier

newDirection = Random.Range(1,5);                //Randomly choose next direction each time we build a new room

if(newDirection == 1)        //NORTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ + 1;
}
else if(newDirection == 2)    //EAST
{
newRoomPosX = curRoomPosX + 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 3)    //SOUTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ - 1;
}
else if(newDirection == 4)    //WEST
{
newRoomPosX = curRoomPosX - 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 5)    //OUT OF RANGE
{
Debug.Log("Out of range!");
}

//we just have to make sure that the new position is on the grid
if(newRoomPosX < width && newRoomPosX > 0 && newRoomPosZ < length && newRoomPosZ > 0)
{
if(mapArray[newRoomPosX, newRoomPosZ].type == 0)    //roomtype = 0, so space is available
{

{
//More then 1 adjacent rooms, which we try to avoid so we do not have 1 big square level
}
else
{
roomPositions[rooms] = new Vector2(newRoomPosX, newRoomPosZ);

mapArray[newRoomPosX,newRoomPosZ].type = 1;
mapArray[newRoomPosX,newRoomPosZ].id = rooms;    //set the RoomID.id equal to rooms

rooms++;
}
}
else
{
//Debug.Log("Cell already taken, searching for new space");
}
}
else
{
//Debug.Log("Out of the grid, searching for new space.");
}
}
}

if(rooms >= iterations)
{
complete = true;

for(int i = 0; i < iterations; i++)
{
//                             mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y].zPos);

if(mapArray[(int)roomPositions[i].x+1, (int)roomPositions[i].y].type != 0)
{
mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y].eConnected = true;
}
if(mapArray[(int)roomPositions[i].x-1, (int)roomPositions[i].y].type != 0)
{
mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y].wConnected = true;
}
if(mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y+1].type != 0)
{
mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y].nConnected = true;
}
if(mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y-1].type != 0)
{
mapArray[(int)roomPositions[i].x, (int)roomPositions[i].y].sConnected = true;
}
}
}
}

//this is used to calculate how many adjacent rooms we have
//it does a 2 for loop where it looks around the current room position from -1 to +1
//in UP DOWN LEFT and RIGHT direction, then if the room type is NOT 0, we add 1 to the newRoomAdjacents
{
int curX = x;
int curZ = z;

for(int _x = -1; _x < x + 2; _x++)
{
for(int _z = -1; _z < z + 2; _z++)
{
if(_x > 0 && _x < width && _z > 0 && _z < length)
{
if(_x == x && _z == z)
{
continue;
}
if(_x > x && _z == z && mapArray[_x,_z].type != 0)
{
}
if(_x < x && _z == z && mapArray[_x,_z].type != 0)
{
}
if(_x == x && _z > z && mapArray[_x,_z].type != 0)
{
}
if(_x == x && _z < z && mapArray[_x,_z].type != 0)
{
}
}
}
}
}

void OnGUI()
{
if(complete)
{

GUI.BeginGroup(new Rect(2,2,miniMapX,miniMapZ));

for(int x = 0; x < width; x++)
{
for(int z = 0; z < length; z++)
{
if(mapArray[x,z].type == 2)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), startingRoom);
}
else if(mapArray[x,z].type == 1)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), basicRoom);

GUI.Label(new Rect(x*iconX,z*iconZ,iconX-1,iconZ-1),"East: " + mapArray[x,z].sConnected + " / West:" +
mapArray[x,z].wConnected + " type: " + mapArray[x,z].type);
}
else if(mapArray[x,z].type == 0)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-1,iconZ-1), empty);
}
}
}

GUI.EndGroup();

}
}
}
``````

Cheers,
Darryl

Well i finally got it to work! Here is a screenshot showing new icons. Each room knows of its neighbor(s) and with how many rooms it is connected to.

The next step is to generate a treasure room, boss room and after the boss room a shop.
I already have an idea how to do the boss and the shop. If you notice the script, i already did a “Manhattan distance” calculation for each cell. I will use this to change the farthest away cell (from the start) to a type 3(boss room type) and after that the shop cell would be easy.(mainly looping through the dungeon searching for the boss cell and instantiate at a random position next to the boss cell)

Anyway here is the screenshot!

And here is the code!

``````using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MapGenerator : MonoBehaviour
{
public int width = 15;                //total width of the grid
public int length = 15;             //total length of the grid

public RoomID[,] mapArray;            //2d array of classes that holds everything

//PRIVATE VARIABLES

//level variables
public int level;                    //our current level we are on, this to determine difficulty and level size
public int rooms;                    //this variable will handle how many rooms have been built
public int iterations;                //how many rooms will be instantiated? This will randomize itself at the beginning

//current positions variables
private int curRoom;                //current room int which we use to get values of the Vector2 list below
private int curRoomPosX;            //these curRoomPosX and Z variables will keep track on which position we currently are
private int curRoomPosZ;            //this to determine our next position whith the newRoomPosX and Z variable
private Vector2[] roomPositions;    //list of Vector2 positions to determine where the next RANDOM room can be placed

//next position variables
private int newDirection;            //this variable will keep track which direction we want the next room to be set
private int newRoomPosX;            //this variable will set the next rooms position on the X axis
private int newRoomPosZ;            //this variable will set the next rooms position on the Z axis

private bool complete;                //level generating is completed

public float miniMapX;                //mini map width
public float miniMapZ;                //mini map height

public Texture2D startingRoom;
public Texture2D basicRoom;
public Texture2D bossRoom;
public Texture2D empty;

public Texture2D north;
public Texture2D south;
public Texture2D west;
public Texture2D east;

public Texture2D ne;
public Texture2D nw;
public Texture2D ns;
public Texture2D sw;
public Texture2D se;
public Texture2D we;

public Texture2D nJunct;
public Texture2D sJunct;
public Texture2D wJunct;
public Texture2D eJunct;

public Texture2D cross;

private float iconX;                //icon width of each room
private float iconZ;                //icon height of each room

void Start()
{
mapArray = new RoomID[width, length];        //Assign the width and length value to the 2d Array grid
rooms = 0;                                    //just to be sure
iterations = Random.Range(5 + (level * 2), 7 + (level * 3));    //randomize iterations
roomPositions = new Vector2[iterations+1];    //set the roomPositions Vector2 array higher then iterations by 1

miniMapX = Screen.height;                    //for now set the mini map to cover the whole screen
miniMapZ = Screen.height;

iconX = (miniMapX/width);
iconZ = (miniMapZ/length);

//A 2 for loop, generating the grid and assigning basic values
for(int x = 0;x < width; x++)
{
for(int z = 0; z < length; z++)
{
mapArray[x,z] = new RoomID();        //create a RoomID instance in each cell on the grid
mapArray[x,z].xPos = x;                //passing the x value to the RoomID x position
mapArray[x,z].zPos = z;                //passing the z value to the RoomID z position
mapArray[x,z].type = 0;                //each starting cell is an empty room, so we set this to 0
}
}

Generate();                                    //calling the generate method for actual generating
}

void Generate()
{
//while rooms is equal or less then iterations, we start building rooms
while(rooms <= iterations)
{
if(rooms == 0)
{
roomPositions[rooms] = new Vector2(width/2,length/2);

mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].type = 2;
mapArray[(int)roomPositions[rooms].x,(int)roomPositions[rooms].y].id = rooms;

rooms++;
}
else
{
curRoom = Random.Range(0, rooms);                //grab random room in rooms so we know where to build next

curRoomPosX = (int)roomPositions[curRoom].x;    //set curRoomPosX to roomPositionsX value which we picked earlier
curRoomPosZ = (int)roomPositions[curRoom].y;    //set curRoomPosZ to roomPositionsY value which we picked earlier

newDirection = Random.Range(1,5);                //Randomly choose next direction each time we build a new room

if(newDirection == 1)        //NORTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ + 1;
}
else if(newDirection == 2)    //EAST
{
newRoomPosX = curRoomPosX + 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 3)    //SOUTH
{
newRoomPosX = curRoomPosX;
newRoomPosZ = curRoomPosZ - 1;
}
else if(newDirection == 4)    //WEST
{
newRoomPosX = curRoomPosX - 1;
newRoomPosZ = curRoomPosZ;
}
else if(newDirection == 5)    //OUT OF RANGE
{
Debug.Log("Out of range!");
}

//we just have to make sure that the new position is on the grid
if(newRoomPosX < width && newRoomPosX > 0 && newRoomPosZ < length && newRoomPosZ > 0)
{
if(mapArray[newRoomPosX, newRoomPosZ].type == 0)    //roomtype = 0, so space is available
{

{
//More then 1 adjacent rooms, which we try to avoid so we do not have 1 big square level
}
else
{
roomPositions[rooms] = new Vector2(newRoomPosX, newRoomPosZ);

mapArray[newRoomPosX,newRoomPosZ].type = 1;
mapArray[newRoomPosX,newRoomPosZ].id = rooms;    //set the RoomID.id equal to rooms

mapArray[newRoomPosX,newRoomPosZ].distance = (Mathf.Abs(newRoomPosX - (int)roomPositions[0].x) +
Mathf.Abs(newRoomPosZ - (int)roomPositions[0].y));

rooms++;
}
}
else
{
//Debug.Log("Cell already taken, searching for new space");
}
}
else
{
//Debug.Log("Out of the grid, searching for new space.");
}
}
}

if(rooms >= iterations)
{
complete = true;

int i = 0;
int j = 0;

while(i < width)
{
j = 0;
while(j < length)
{
if(mapArray[i,j].type != 0)
{
North(i,j);
South(i,j);
East(i,j);
West(i,j);

{
if(mapArray[i,j].nConnected)        //NORTH
{
mapArray[i,j].mini = north;
}
else if(mapArray[i,j].sConnected)    //SOUTH
{
mapArray[i,j].mini = south;
}
else if(mapArray[i,j].wConnected)    //WEST
{
mapArray[i,j].mini = west;
}
else if(mapArray[i,j].eConnected)    //EAST
{
mapArray[i,j].mini = east;
}
}
else if(mapArray[i,j].connections == 2)
{
//STRAIGHT
if(mapArray[i,j].nConnected && mapArray[i,j].sConnected)        //NORTH SOUTH
{
mapArray[i,j].mini = ns;
}
else if(mapArray[i,j].wConnected && mapArray[i,j].eConnected)    //WEST EAST
{
mapArray[i,j].mini = we;
}
//CORNERS
else if(mapArray[i,j].sConnected && mapArray[i,j].eConnected)    //SOUTH EAST
{
mapArray[i,j].mini = se;
}
else if(mapArray[i,j].sConnected && mapArray[i,j].wConnected)    //SOUTH WEST
{
mapArray[i,j].mini = sw;
}
else if(mapArray[i,j].nConnected && mapArray[i,j].wConnected)    //NORTH WEST
{
mapArray[i,j].mini = nw;
}
else if(mapArray[i,j].nConnected && mapArray[i,j].eConnected)    //NORTH EAST
{
mapArray[i,j].mini = ne;
}
}
else if(mapArray[i,j].connections == 3)    //T JUNCTIONS
{
if(mapArray[i,j].nConnected && mapArray[i,j].eConnected && mapArray[i,j].wConnected)        //NORTH T JUNCTION
{
mapArray[i,j].mini = nJunct;
}
else if(mapArray[i,j].nConnected && mapArray[i,j].eConnected && mapArray[i,j].sConnected)    //EAST T JUNCTION
{
mapArray[i,j].mini = eJunct;
}
else if(mapArray[i,j].sConnected && mapArray[i,j].wConnected && mapArray[i,j].eConnected)    //SOUTH T JUNCTION
{
mapArray[i,j].mini = sJunct;
}
else if(mapArray[i,j].sConnected && mapArray[i,j].wConnected && mapArray[i,j].nConnected)    //WEST T JUNCTION
{
mapArray[i,j].mini = wJunct;
}
}
else if(mapArray[i,j].connections == 4)    //CROSS
{
mapArray[i,j].mini = cross;
}
//if(mapArray[i,j].distance >= iterations/2 && mapArray[i,j].connections == 1)
//{

//}
}
j++;
}
i++;
}
}
}

bool North(int x, int z)
{
if(z == 0) return false;

if(mapArray[x,z-1].type != 0)
{
mapArray[x,z].nConnected = true;
mapArray[x,z].connections ++;
return true;
}

return false;
}
bool South(int x, int z)
{
if(z == length-1) return false;

if(mapArray[x,z+1].type != 0)
{
mapArray[x,z].sConnected = true;
mapArray[x,z].connections ++;
return true;
}
return false;
}
bool East(int x, int z)
{
if(x == width-1) return false;

if(mapArray[x+1,z].type != 0)
{
mapArray[x,z].eConnected = true;
mapArray[x,z].connections ++;
return true;
}
return false;
}
bool West(int x, int z)
{
if(x == 0) return false;

if(mapArray[x-1,z].type != 0)
{
mapArray[x,z].wConnected = true;
mapArray[x,z].connections ++;
return true;
}
return false;
}

//this is used to calculate how many adjacent rooms we have
//it does a 2 for loop where it looks around the current room position from -1 to +1
//in UP DOWN LEFT and RIGHT direction, then if the room type is NOT 0, we add 1 to the newRoomAdjacents
{
int curX = x;
int curZ = z;

for(int _x = -1; _x < x + 2; _x++)
{
for(int _z = -1; _z < z + 2; _z++)
{
if(_x > 0 && _x < width && _z > 0 && _z < length)
{
if(_x == x && _z == z)
{
continue;
}
if(_x > x && _z == z && mapArray[_x,_z].type != 0)
{
}
if(_x < x && _z == z && mapArray[_x,_z].type != 0)
{
}
if(_x == x && _z > z && mapArray[_x,_z].type != 0)
{
}
if(_x == x && _z < z && mapArray[_x,_z].type != 0)
{
}
}
}
}
}

void OnGUI()
{
if(complete)
{

GUI.BeginGroup(new Rect(miniMapX/2,0,miniMapX,miniMapZ));

for(int x = 0; x < width; x++)
{
for(int z = 0; z < length; z++)
{
if(mapArray[x,z].type == 2)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX,iconZ), mapArray[x,z].mini);

//GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), startingRoom);
}
else if(mapArray[x,z].type == 1)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX,iconZ), mapArray[x,z].mini);
//GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), basicRoom);

//GUI.Label(new Rect(x*iconX,z*iconZ,iconX-1,iconZ-1),"E: " + mapArray[x,z].eConnected + " / W:" +
//          mapArray[x,z].wConnected + " / S: " + mapArray[x,z].sConnected +
//          " / N: " + mapArray[x,z].nConnected + " / ID: " + mapArray[x,z].type);
}
else if(mapArray[x,z].type == 3)
{
//GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX-2,iconZ-2), bossRoom);
}
else if(mapArray[x,z].type == 0)
{
GUI.DrawTexture(new Rect(x*iconX,z*iconZ,iconX,iconZ), empty);
}
}
}

GUI.EndGroup();

}
}
}
``````

And the RoomID class:

``````using UnityEngine;
using System.Collections;

public class RoomID
{
public int type;            //0 = empty
//1 = basic room(which may contain enemies or not)
//2 = starting room
//3 = boss room
//4 = treasure room
//5 = shop

public int id;                //this rooms unique ID

public int intensity;        //for a basic, miniboss or boss room, how difficult it is(more enemies, stronger enemies)
public int connections;        //with how many rooms is this room connected

public bool nConnected;        //north connected
public bool sConnected;        //south connected
public bool eConnected;        //east connected
public bool wConnected;        //west connected

public int xPos;            //its X axis position on the grid
public int zPos;            //its Z axis position on the grid

public int distance;        //this rooms distance from the start

public Texture2D mini;
}
``````

Any tips or suggestions are always welcome!

Cheers,
Darryl