Hello,
I'm programming a simple rougelike video game for fun. I'm running into a very difficult problem with my room generation code, specifically the part that deals with the maze-like hallway to connect the randomly placed rooms inside a dungeon, using the depth-first search method. The code I've written is kinda long and probably hard to read, but I seriously cannot figure out what is causing the issue so try to bear with me please.
Below is the header file for the Floor class, which generates the floor of the dungeon.
#ifndef FLOOR_H_
#define FLOOR_H_
#include <iostream>
#include <vector>
#include <algorithm>
#include "Cell.h"
class Floor {
private:
int attempts; //Amount of attempts it tries to place a room before giving up. More attempts = more cramped.
int maxdoor; //Maximum amount of doors on each room
int maxroom; //Maximum number of rooms. 0 for 999.
int maxheight, minheight;
int maxwidth, minwidth;
int maxbigroom;
std::vector<std::vector<Cell> > region; //A collection of regions. A region is a collection of cells (rooms & hallway)
std::vector<Cell> temp_region; //Used to fill the region.
std::vector<Cell> temp_maze;
std::vector<Cell> maze;
public:
Floor();
void init(int attempts, int maxdoor, int maxroom, int maxwidth, int minwidth, int maxheight, int minheight, int maxbigroom);
void gen(Cell cell[120][60], SDL_Texture* tex);
bool check_walls(Cell cell[120][60], int* x, int* y);
};
#endif
The main thing that is important in this header is the temp_maze vector, which is used to keep track of the current section of the maze that has been carved out, so that when the maze hits a dead end it can back track. is the Cell is a class that represents a cell in the 2D grid that the player can move on. For the issue of this post, just think of each Cell as having an X integer, a Y integer, and a Bool to keep track of whether or not the cell is opened up.
Below is the part of the gen function that deals with the hallway generation.
//Hallway Generation
int cur_x, cur_y; //Current cell being tested
bool time_to_break;
for (int i = 1; i < 119; i++) {
for (int j = 1; j < 59; j++) {
if (cell[i][j].return_blockade() == true
&& cell[i + 1][j].return_blockade() == true
&& cell[i][j + 1].return_blockade() == true
&& cell[i - 1][j].return_blockade() == true
&& cell[i][j - 1].return_blockade() == true) { //Start of a path
cur_x = i;
cur_y = j;
while (true) {
cell[cur_x][cur_y].set_bloc(false); //Opens up cell
cell[cur_x][cur_y].set_tex(tex);
cell[cur_x][cur_y].set_default_tex(tex);
temp_maze.push_back(cell[cur_x][cur_y]);
if (check_walls(cell, &cur_x, &cur_y) == false) {
std::cout << "Entering nospace" << std::endl;
std::cout << "Size of k: " << temp_maze.size()
<< std::endl;
for (int k = temp_maze.size() - 1; k > -1; k--) {
int xte = temp_maze[k].return_rect().x / 15;
int yte = temp_maze[k].return_rect().y / 15;
std::cout << "k: " << k << std::endl;
std::cout << "rect_x: "<< temp_maze[k].return_rect().x<< " rect_y : "<< temp_maze[k].return_rect().y<< std::endl;
std::cout << "x_te: " << xte << " y_te: " << yte << std::endl;
if (check_walls(cell, &xte, &yte) == true) {
cur_x = xte;
cur_y = yte;
std::cout << "Exiting nospace via newblock"
<< std::endl;
break;
}
if (k == 0) {
time_to_break = true;
std::cout << "Exiting nospace via noviableblock"
<< std::endl;
break;
}
}
}
if (time_to_break == true) {
time_to_break = false;
temp_maze.clear();
break;
}
}
}
}
}
The broad idea is that, starting from the top-left cell, we scroll through them until we find a cell that is not blocked, nor has any neighbors that are blocked. Than we open that cell up, add it to the temp_maze vector, and check whether it has any viable neighbors. If it does, it moves cur_y and cur_x to that new cell and repeats. If it doesn't have any viable neighbors, than it goes through the temp_maze vector until either it finds a cell that has viable neighbors, or it reaches the end of the vector. This is accomplished with the check_walls function.
bool Floor::check_walls(Cell cell[120][60], int* x, int* y) {
int ori_x = *x;
int ori_y = *y;
std::cout << "Entering checkwalls with x: " << ori_x << " y: " << ori_y
<< std::endl;
if (cell[ori_x][ori_y].return_blockade() == true) {
std::cout << "Checkwalls returns false due to being blocked"
<< std::endl;
return false;
}
while (true) {
*x = ori_x;
*y = ori_y;
bool upblock, rightblock, downblock, leftblock;
int sidecount = 0;
int dir = rand() % 4;
if (dir == 0) {
*y = (*y) - 1;
} else if (dir == 1) {
*x = (*x) - 1;
} else if (dir == 2) {
*y = (*y) + 1;
} else if (dir == 3) {
*x = (*x) + 1;
}
if (*x <= 0 || *y <= 0) {
sidecount = 8;
dir = 5;
*x = ori_x;
*y = ori_y;
}
if (cell[*x + 1][*y].return_blockade() == false) {
sidecount++;
}
if (cell[*x - 1][*y].return_blockade() == false) {
sidecount++;
}
if (cell[*x][*y + 1].return_blockade() == false) {
sidecount++;
}
if (cell[*x][*y - 1].return_blockade() == false) {
sidecount++;
}
if (sidecount <= 1) {
std::cout << "Checkwalls returns true" << std::endl;
return true;
} else {
if (dir == 0) {
upblock = true;
} else if (dir == 1) {
leftblock = true;
} else if (dir == 2) {
downblock = true;
} else if (dir == 3) {
rightblock = true;
}
}
if (upblock == true && leftblock == true && downblock == true
&& rightblock == true) {
*x = ori_x;
*y = ori_y;
std::cout << "Checkwalls returns false" << std::endl;
return false;
}
}
}
The basic idea here is that if one of the neighbors are available, than it moves x & y to that cell and return true, and if there are none, than return false.
The problem is that when I run this the temp_maze function seems to get filled with the same cell, and time_to_break never gets set to true, as the vector seems to never end. Once again I understand this is kind of a lot but I have looked at this for a couple days now and have no idea what i am doing wrong, so any help would be very much appreciated.