Procedural Generation Test
Engine | Unity
In this test, I wanted to try to polish up my skills with procedural generation. I found a great article on how The Binding Of Isaac did it, by boristhebrave. After finding this, I tried to make my own based upon the 6 key points in the algorithm:
- Find the neighbor space
- If there is already a neighbor in the space, stop
- If the neighbor has more than one filled neighbor, stop
- If we hit the max rooms, stop
- Random chance to stop
- Else, pass the neighbor to the queue of rooms to add
I started out by making some initial variables, constants, and setting up arrays
//the smaller these numbers are, the closer the rooms
float cellW = 10f, cellH = 10.05f;
float W = 1, H = 1;
//max size of room array, also used in Initalize
[SerializeField]
int[] rooms = new int[77];
//the queue of rooms to be checked
[SerializeField]
List<int> queue = new List<int>();
[SerializeField]
GameObject[] RoomsHolder = new GameObject[77];
[SerializeField]
int currentNumberRooms = 0;
[SerializeField]
int maxRooms;
//constants for each cardinal direction
const int UP = 10, DOWN = -10, LEFT = -1, RIGHT = 1;
//constant for the start of the rooms
const int STARTING_ROOM = 44;
int randNoUse;
public Sprite[] RoomTypes;
public GameObject RoomTemplate;
public GameObject Door;
//the bool to start the room generation
[SerializeField]
bool startedRoomGen = false, startedDoorGen = false;
After that I created an initialize function that sets resets each room in the array to 0. I call it in Start, along with creating an array of random rooms to stop generation at.
void Initialize()
{
//make each number in the array 0
for (int i = 0; i < rooms.Length; i++)
{
rooms[i] = 0;
}
}
private void Start()
{
startedRoomGen = true;
//Initialize our variables
Initialize();
randNoUse = Random.Range(1, rooms.Length);
//number of rooms in the map
maxRooms = Mathf.RoundToInt((Random.Range(2, 8) + 8) * 2.45f);
RoomCheck(STARTING_ROOM);
}
Next, in the update function, I check if there is a room in the queue. If there is, I grab the first item in the queue, and check it’s neighbors to see if they fit the above criteria. If they do, I create the room. Finally, no matter what, I remove the room from the queue.
if (startedRoomGen)
{
//if there is something in the queue
if (queue.Count > 0)
{
int roomToCheck = queue[0];
if (roomToCheck + UP < rooms.Length)
{
if (rooms[roomToCheck + UP] == 0)
{
RoomCheck(roomToCheck + UP);
}
}
if (roomToCheck + DOWN >= 0)
{
if (rooms[roomToCheck + DOWN] == 0)
{
RoomCheck(roomToCheck + DOWN);
}
}
if (roomToCheck + LEFT >= 0)
{
if (rooms[roomToCheck + LEFT] == 0)
{
RoomCheck(roomToCheck + LEFT);
}
}
if (roomToCheck + RIGHT < rooms.Length)
{
if (rooms[roomToCheck + RIGHT] == 0)
{
RoomCheck(roomToCheck + RIGHT);
}
}
MakeRoom(roomToCheck);
//remove the first item from the queue
queue.RemoveAt(0);
}
}
The RoomCheck function firstly check if there is a compatible neighbor. If there is, then it checks if the generator reached it’s room limit. Once it passes that check, there