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;
}
4

1 回答 1

4

首先,我注意到函数中有一些奇怪的东西。您实际上有三组坐标 - (xx, yy)、(xx2, yy2) 和 (player.x, player.y)。据我了解,算法是从A点到B点画一条线,然后看看这条线是否有任何瓷砖阻挡了访问。为此,您只需要两组坐标,因此您的错误可能就像将 (player.x, player.y) 替换为 (xx, yy) 一样简单。

其次,在 roguelike 中,你通常有基于图块的环境,其中三角是不必要的,甚至被认为是浪费的。由于您的所有图块都有整数位置,因此您绝对应该能够为像这样的关键低级实现拉出仅整数实现。

最后,由于您将输入坐标存储为整数,因此当角度的 sin 和 cos 小于 1 时,内部循环将无法按预期工作。具体来说,坐标变量不会存储部分平铺移动。在循环中放置一个打印语句以查看 (xx, yy) 的实际情况。

如果你想更快地测试你的,我从 Github 上提取了我的 roguelike 实现。当然,您必须根据您表示地图的方式更改它,并可能删除阻塞检查。

/**
 * 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;
}

该代码实现了 Bresenham 的画线算法,这是 roguelikes 中视线计算的常用方法。我还为我自己的目的返回沿线的点(然后您可以使用它以某种方式标记这些坐标 - 例如使用额外的照明参数)。这些信息很有价值,不应该在您费尽千辛万苦找到瓷砖是否可见之后就扔掉!

于 2014-05-01T01:44:01.040 回答