Manderin87
Manderin87

Reputation: 56

Roguelike FOV problem

I am working on a college compsci project and I would like some help with a field of view algorithm. I works mostly, but in some situations the algorithm sees through walls and hilights walls the player should not be able to see.

void cMap::los(int x0, int y0, int radius)
{ //Does line of sight from any particular tile

for(int x = 0; x < m_Height; x++) {
    for(int y = 0; y < m_Width; y++) {
        getTile(x,y)->setVisible(false);
    }
}

double  xdif = 0;
double  ydif = 0;
bool    visible = false;
float   dist = 0;

for (int x = MAX(x0 - radius,0); x < MIN(x0 + radius, m_Height); x++) {      //Loops through x values within view radius
    for (int y = MAX(y0 - radius,0); y < MIN(y0 + radius, m_Width); y++) {         //Loops through y values within view radius

        xdif = pow( (double) x - x0, 2);
        ydif = pow( (double) y - y0, 2);

        dist = (float) sqrt(xdif + ydif); //Gets the distance between the two points

        if (dist <= radius) {               //If the tile is within view distance,
            visible = line(x0, y0, x, y);       //check if it can be seen.

            if (visible) {                          //If it can be seen,
                getTile(x,y)->setVisible(true);        //Mark that tile as viewable
            }
        }
    }   
}
}

bool cMap::line(int x0,int y0,int x1,int y1)
{
bool steep = abs(y1-y0) > abs(x1-x0);

if (steep) {
    swap(x0, y0);
    swap(x1, y1);
}

if (x0 > x1) {
    swap(x0,x1);
    swap(y0,y1);
}

  int deltax = x1-x0;
  int deltay = abs(y1-y0);
  int error = deltax/2;
  int ystep;
  int y = y0;

  if (y0 < y1)
     ystep = 1;
  else
     ystep = -1;

  for (int x = x0; x < x1; x++) {

      if ( steep && getTile(y,x)->isBlocked()) {
          getTile(y,x)->setVisible(true);
          getTile(y,x)->setDiscovered(true);
        return false;
      } else if (!steep && getTile(x,y)->isBlocked()) {
          getTile(x,y)->setVisible(true);
          getTile(x,y)->setDiscovered(true);
        return false;
      }

     error -= deltay;

     if (error < 0) {
        y = y + ystep;
        error = error + deltax;
     }

  }

  return true;
}

If anyone could help me make the first blocked tiles visible but stops the rest, I would appreciate it.

thanks, Manderin87

Upvotes: 3

Views: 2112

Answers (1)

mingos
mingos

Reputation: 24532

You seem to be attempting to create a raycasting algorithm. I assume you have knowledge of how Bresenham's lines work, so I'll cut to the chase.

Instead of checking the visibility of each cell in the potential field of view, you only need to launch Bresenham lines from the FOV centre towards each cell at the very perimetre of the potential FOV area (the square you loop through). At each step of the Bresenham line, you check the cell status. The pseudocode for each ray would go like this:

while (current_cell != destination) {
    current_cell.visible = true;
    if (current_cell.opaque) break;
    else current_cell = current_cell.next();
}

Please remember that raycasting produces tons of artifacts and you might also need postprocessing after you have calculated your field of view.

Some useful resources:

Upvotes: 2

Related Questions