六角网格(平顶)距离计算

时间:2014-07-15 18:59:30

标签: java simulation hexagonal-tiles

我一直致力于为我正在进行的模拟创建一个六边形(平顶)网格。我试图从指定的目标六边形中找出六边形之间的距离。

我大部分时间都使用的解决方案,除了目标六角形目标北部的每个奇数列向上移动了1.我知道这听起来很混乱,但我附上了一张图片来解释我的意思:

hexagonal game grid

正如大家们所见,目标六边形下方网格的下半部分和目标六边形上方的每一列都是正确的。我不明白为什么:S

这是Axial& amp;的解释。 Cube Co-ords。

http://www.redblobgames.com/grids/hexagons/#coordinates

以下是负责将Axial Co-ords转换为Cube Co-ords的代码。

public void setQR(int theQ, int theR){

    this.q = theQ;
    this.r = theR;

    this.x = this.q;
    this.z = this.r - (this.q - (this.q&1)) /2;
    this.y = -(this.x + this.z);
}

并且说明了制定距离的代码。

仅供参考,六边形是从CentrePoint(CPx,CPy)创建的。

    private double distance = 0;

public double workOutDistance(Hexagon hexagon, HexagonFood target){

    double targetX = target.getCPX();
    double targetY = target.getCPY();

    double hexagonX = hexagon.getCPX();
    double hexagonY = hexagon.getCPY();

    double deltaX = (targetX-hexagonX)*-1;
    double deltaY = (targetY-hexagonY)*-1;

    double deltaXRadius = (deltaX/(SimField.hexSize)/1.5);
    double deltaYApothem = (deltaY/(SimField.hexSize/1.155)/2);

    hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);


    ArrayList<Integer> coords = new ArrayList<>();

    coords.add(
    Math.abs(hexagon.getX() - target.getX())
    );

    coords.add(
    Math.abs(hexagon.getZ() - target.getZ())
    );

    coords.add(
    Math.abs(hexagon.getY() - target.getY())
    );

    System.out.println(coords);
    distance = Collections.max(coords);

    return distance;
}

任何人都可以告诉我为什么会这样吗?非常感谢。

编辑:

按照Tim的建议将Int改为Double后,我明白了。

http://i.stack.imgur.com/javZb.png

**

**

在尝试了给出的答案后,这个小小的调整解决了这个问题。

改变这个..

public void setQR(int theQ, int theR){

    this.q = theQ;
    this.r = theR;

    this.x = this.q;
    this.z = this.r - (this.q - (this.q&1)) /2;
    this.y = -(this.x + this.z);
}

到此..

public void setQR(int theQ, int theR){

    this.q = theQ;
    this.r = theR;

    this.x = this.q;
    if (this.r>0){
        this.z = this.r - (this.q - (this.q&1))/2;
    }
    else {
        this.z = this.r - (this.q + (this.q&1))/2;
    }
    this.y = -(this.x + this.z);
}

3 个答案:

答案 0 :(得分:3)

调用setQR()时,你将一个double转换为int;你确定你正在做你期望的事吗?双精度使用浮点数学,因此你期望为2.0的数字实际上可能是1.999999989,然后在转换为int时将其向下舍入为1.

我也对阅读this.z = this.r - (this.q - (this.q&1)) /2;的行持怀疑态度。当数字是奇数时你加1,这似乎是你遇到的失败案例;我确保这条线也在做你期望的事。

如果您没有使用调试器并检查值,则表明您做错了。

答案 1 :(得分:1)

你也可以对这个问题采取完全不同的方法。您知道两个六边形的X / Y(笛卡尔坐标)坐标,这意味着您可以获得相对于六边形空间原点的每个六边形的立方坐标。两个六边形之间的距离简单地是两个六边形的X,Y和Z立方坐标之间的差的绝对值的总和。 (也就是说,dist = |h2.X - h1.X| + |h2.Y - h1.Y| + |h2.Z - h1.Z|)因此,不是试图计算两个中心点之间的向量,然后将其转换为立方坐标,而是可以直接以立方坐标计算距离(就像你在这些方格中是正方形一样)笛卡尔坐标)...

尽管你采用这种方法,但我强烈建议您调试原始方法的内容。即使您最终丢弃了代码,调试的练习也可能会教会您将来能够应用的宝贵课程。

读者注意:“立方”坐标不是三维笛卡尔坐标,它们是六边形专用坐标系,OP为其提供了链接。

答案 2 :(得分:0)

计算(即从偏移到立方坐标的转换,以及立方坐标中距离的计算)似乎是正确的这一事实表明Tim对他的假设是正确的关于浮点错误。

您应该尝试更改行

hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);

从原始代码到

hexagon.setQR((int)Math.round(deltaXRadius), (int)Math.round(deltaYApothem));

在这种情况下可以解决问题。

如果不是......或者......在任何情况下,这里都是一个小例子,基本上和你做的一样,但作为一个MVCE ...

import java.awt.Point;

public class HexagonsTest
{
    public static void main(String[] args)
    {
        // Above and below
        test(8,6, 8,5,  1);
        test(8,6, 8,7,  1);

        // Left
        test(8,6, 7,5,  1);
        test(8,6, 7,6,  1);

        // Right
        test(8,6, 9,5,  1);
        test(8,6, 9,6,  1);

        // The first one that was wrong:
        test(8,6, 7,4,  2);
    }

    private static void test(int x0, int y0, int x1, int y1, int expected)
    {
        int distance = computeStepsDistance(x0, y0, x1, y1);
        System.out.println(
            "Distance of (" + x0 + "," + y0 + ") to " + 
            "(" + x1 + "," + y1 + ") is " + distance + 
            ", expected " + expected);
    }

    private static int computeStepsDistance(int x0, int y0, int x1, int y1)
    {
        Point cp0 = convertOffsetToCubeCoordinates(x0, y0, null);
        Point cp1 = convertOffsetToCubeCoordinates(x1, y1, null);
        int cx0 = cp0.x;
        int cy0 = cp0.y;
        int cz0 = -cx0-cy0;
        int cx1 = cp1.x;
        int cy1 = cp1.y;
        int cz1 = -cx1-cy1;
        int dx = Math.abs(cx0 - cx1); 
        int dy = Math.abs(cy0 - cy1); 
        int dz = Math.abs(cz0 - cz1); 
        return Math.max(dx, Math.max(dy, dz));
    }

    private static Point convertOffsetToCubeCoordinates(
        int ox, int oy, Point p) 
    {
        int cx = ox;
        int cz = oy - (ox - (ox&1)) / 2;
        int cy = -cx-cz;
        if (p == null)
        {
            p = new Point();
        }
        p.x = cx;
        p.y = cy;
        return p;
    }


}