2

I am making a roguelike game and I'm trying to implement the "Quick and Dirty" FOV technique into my game, but I'm having some issues. I'm almost certain it's in my function where the line calculation is done in which I have a x and y variable move along an angle between 2 points (the tile I'm checking and the player).

If you don't know what the "quick and dirty" FOV is, here is the link http://www.roguebasin.com/index.php?title=Quick_and_dirty_FOV/LOS

Code

  public static boolean lineOfSight( int xx, int yy, int xx2, int yy2) {
    float deltaX = xx - xx2;
    float deltaY = yy - yy2;
    float angle = (float) Math.atan2(deltaY,deltaX);
    int distance = distanceCheck(player.x,player.y,xx2,yy2);
    int counter = 0;
    while(counter < distance) {
        counter ++;
        xx += (int) (Math.sin(angle));
        yy += (int) (Math.cos(angle));
        if(map[xx][yy] == 1) {
            return false;
        } 
    }
    return true;
}
user1803551
  • 12,965
  • 5
  • 47
  • 74
Mark9135
  • 101
  • 11
  • What are your expected outputs vs real outputs? – Kon May 01 '14 at 00:25
  • what exactly do you mean? – Mark9135 May 01 '14 at 00:26
  • When you're testing your method, you must be passing it some values and expecting some output. What tests are you running, and what incorrect output are you getting. – Kon May 01 '14 at 00:29
  • im giving it my players x and y points and the tiles x and y points and either everything is visible in the area or a quarter of the circle is missing my best bet is im calculating my angle wrong..im just not sure what i am doing wrong – Mark9135 May 01 '14 at 00:31

1 Answers1

4

First off, I noticed there's some weird stuff going in the function. You actually have three sets of coordinates - (xx, yy), (xx2, yy2), and (player.x, player.y). As far as I understand, the algorithm is to draw a line from point A to point B, and then see if any of the tiles along the line are blocking access. For that, you only need two sets of coordinates, so maybe your bug is as simple as replacing (player.x, player.y) with (xx, yy).

Secondly, in a roguelike, you usually have tile-based environments where trigonometry is unnecessary, and even considered wasteful. Since all your tiles have integer locations, you should definitely be able to pull off an integer-only implementation for a critical, low-level implementation like this.

Lastly, since you're storing your input coordinates as integers, the inner loop won't work as expected when the sin and cos of the angle are less than one. Specifically, the coordinate variables won't store partial tile movements. Place a print statement inside the loop to see what really happens to (xx, yy).

I pulled the implementation I have for my roguelike off of Github, if you want to test yours more quickly. You'll have to change it for however you're representing maps, of course, and potentially remove the blocking check.

/**
 * Check if the point (x0, y0) can see point (x1, y1) by drawing a line
 * and testing for the "blocking" property at each new tile. Returns the
 * points on the line if it is, in fact, visible. Otherwise, returns an 
 * empty list (rather than null - Efficient Java, item #43).
 * 
 * http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
 */
public static List<Point> isVisible(GameMap map, int x0, int y0, int x1, int y1) {
    List<Point> line = new LinkedList<Point>();
    line.add(new Point(x0, y0));
    int dx = Math.abs(x1 - x0);
    int dy = Math.abs(y1 - y0);
    int sx = (x0 < x1) ? TILE_X : -TILE_X;
    int sy = (y0 < y1) ? TILE_Y : -TILE_Y;
    int err = dx - dy;
    int e2;

    while (!(x0 == x1 && y0 == y1)) {            
        if (map.isBlocked(x0, y0)) {
            line.clear();
            return line;
        }

        e2 = 2 * err;

        if (e2 > -dy) {
            err -= dy;
            x0 += sx;   
        }

        if (e2 < dx) {
            err += dx;
            y0 += sy;
        }

        line.add(new Point(x0, y0));
    }

    return line;
}

The code implements Bresenham's line drawing algorithm, a common approach to line-of-sight calculations in roguelikes. I also return the points along the line for my own purposes (you can then use it to mark those coordinates somehow - with additional lighting parameters for instance). This information is valuable and shouldn't be tossed away after you went through all the trouble to find if the tile was visible at all!

Misha
  • 909
  • 1
  • 7
  • 15