绘制等距墙

时间:2013-01-23 20:42:01

标签: java math isometric

我在等距墙上遇到了一些麻烦。

我正在使用从前到后的渲染方法绘制等距地砖,它工作正常。我还将我的地砖正确排列在一个漂亮的网格中。代码(这似乎是等距地板绘图的标准)如下:

for(int x = 0; x < 6; x++){
    for(int y  = 3; y >=0 ; y--){

        int xCo = (y+x)*(tileWidth/2);
        int yCo = (x-y)*(tileHeight/2);
        tile.draw(g, xCo, yCo);
    }            
}

这是一个不错的小地板:

multiple floor tiles

网格由此图块构成:

A single tile

不幸的是,当我对墙壁使用相同的逻辑时,一切都是正确的。

for(int x = 0; x < 6; x++){
    for(int y  = 3; y >= 0 ; y--){

        int xCo = (y+x)*(wallWidth()/2);
        int yCo = (x-y)*(wallHeight()/2);
        walls.draw(g, xCo, yCo);    
}
}

我正在使用它作为我的墙砖:

Single wall tile

(这是谷歌图片搜索的占位符,但它应该可以正常工作)

这是我得到的结果:

Multiple wall tiles

我的墙壁的渲染顺序显然是正确的,更近的墙壁渲染在更远的墙壁上,这是我想要的,但定位也是非常不正确的,我不知道我应该如何纠正没有使用像素值。

作为参考,我确实使用硬编码像素值进行了试验,因为我发现从一个墙的右角到下一个墙的右角,变化恰好是(200,-100)像素。当我为我的渲染循环帐户

int xCo = (x+y)*200;
int yCo = (y-x)*-100;

它工作正常,但这不是一个可行的解决方案,因为它不允许任何多功能性。

所以,寻找关于如何使我的等距墙排列的建议。我做错了什么?

谢谢!

3 个答案:

答案 0 :(得分:2)

您不能简单地使用相同的墙壁和地板绘图代码,因为墙壁和地板不在同一平面内:地板是平的(水平的),而墙壁是垂直的。所以你必须以不同的方式绘制它们。

您在地板盒中的x和y坐标就瓷砖的位置而言意味着“左/右”和“前/后”。对于砖块,左侧和右侧仍然有意义,但我们想要向上和向下替换向上和向下以反映垂直方向。所以我们的“y”有了新的含义。

现在,在数学中,y轴通常指向上方,而在2D计算机图形中则指向下方。您可以选择 - 下面的代码假设它指向上方,以便y = 0表示“在楼层”。

让我们开始考虑订单。您发布的示例砖是用于墙(左上端)的墙。由于砖的黑色部分(墙的深度),我们必须确保我们首先绘制更右边的砖块,以便左侧的黑色深度将被更接近的砖块覆盖。同样的论点适用于墙顶部的黑色,我们必须首先绘制下部砖块。

如果我们坚持前面讨论的x和y方向(x从左到右,y从下到上),这意味着我们必须在负方向上运行两个for循环:< / p>

    for (int y = 3; y >= 0; y--) {
        for (int x = 5; x >= 0; x--) {
            ...
        }
    }

现在的主要问题是,我们必须相对于其他砖块来抵消每块砖的绘制。让我们一个一个方向,从x方向开始。

让我们想象彼此相邻的两块砖:

two bricks horizontally

两者的左边有黑色深度部分可见,但右边的部分不应显示。因此,我们不能简单地将正确的图像偏移到PNG的整个宽度。事实上,假设砖块与地砖对齐,墙壁实际前部的宽度应与瓷砖宽度的一半相同。

int xCo = x * tileWidth / 2;

左边的黑墙深度不应该被忽略,因为我们可能想要将每个砖稍微向左偏移,以便墙的前角的x坐标与地砖对齐,而不是后角的x坐标。

现在,每块砖的y坐标有点棘手,因为它不仅取决于砖块,还取决于x坐标:越往右越高,我们应该绘制。但是让我们暂时忽略x方向并尝试简单地绘制一列砖:

two bricks vertically

同样,两块砖的y坐标之间的差值不是PNG的整个高度。与左/右情况不同的是,我们假设砖块与瓷砖对齐,这使得我们可以使用tileWidth作为delta-x,砖块可以具有任意高度。但是我们仍然可以从图像高度计算出实际的砖块高度,因为我们知道左侧的深度和顶部的深度必须排成一行。

如果我们看一下砖PNG右上角的小透明三角形,我们注意到它的宽度和高度的比例必须与地砖的宽度和高度的比率相同。这允许我们从上面计算的xoffset计算yoffset,并使用它来推断砖的实际高度:

int yoffset = xoffset * tileHeight / tileWidth;
int wallHeight = wallHeight() - tileHeight / 2 - yoffset;

请注意,这仅在PNG边界处没有空白空间的情况下才有效,并且由于舍入错误可能仍会失败。因此,如果需要,您可以在此处添加Math.ceil()(或简称+ 1)。

因此,对于简单的列,我们现在很高兴:我们可以简单地将y变量与上面的wallHeight相乘。但如前所述,砖的x位置也会影响y像素坐标。如果我们再看两张相邻的砖块再看第一张照片,我们需要将右边的砖块移动到与左边的砖块对齐多少?嗯,这个实际上很简单,因为它与地砖一样:瓷砖高度的一半!

所以我们都准备好了。如果我们将所有内容放在一起,我们最终会得到一些像这样的代码:

int xoffset = wallWidth() - tileWidth / 2;
int yoffset = xoffset * tileHeight / tileWidth;
int wallHeight = wallHeight() - tileHeight / 2 - yoffset;

for (int y = 3; y >= 0; y--) {
    for (int x = 5; x >= 0; x--) {

        int xCo = x * tileWidth / 2;
        int yCo = y * wallHeight - x * tileHeight / 2;

        walls.draw(g, xCo - xoffset, yCo - yoffset);
    }
}

(我假设wallWidth()和wallHeight()返回砖块PNG的宽度和高度。)

请注意,for循环之前的三个常量可以移出实际的绘图代码 - 它们仅依赖于图像属性和其他常量,并且不必在每次绘制墙时重新计算。

答案 1 :(得分:0)

如果你看一下形状像钻石的地砖,将它向上移动半个宽度并跨越一半长度,两个边缘将对齐。
墙面砖不是钻石,因此通过移动半宽和一半长度,您想要匹配的边缘将不会对齐。

给定u =移动距离 和v =向上移动的距离 和A等角度

v = u*tan(A)

在这种情况下,

u是图像正面的宽度。

如果墙面图像的面(纹理位)与地砖的边长相匹配,则给出

int offset = ?;// this is the width of the black stripe on the image.

for(int x = 0; x < 6; x++){
    for(int y  = 3; y >=0 ; y--){

        int xCo = ((y+x+1)*(tileWidth/2))-offset;
        int yCo = (x-y)*(tileHeight/2);
        wall.draw(g, xCo, yCo);
    }            
}

答案 2 :(得分:0)

在等距领域,你可以移动三个轴 - Z为上下,X和Y为'对​​角线'。

首先,让我们想象1个单位乘以1个单位等距立方体的像素表示,所有边都表示相同的长度:

Z轴上的像素高。 它的其他边缘也可以是A像素的长度,但旋转60度 - 所以它将是sin(30)* A像素高和cos(30)* X和Y方向上的像素长 - 又名,0.5 * A和sqrt (3)/ 2 * A。

因此,要在X,Y和Z中定位等距立方体大小的对象,我们必须通过以下内容在屏幕x和y上进行翻译:

y += Z*A
x += X*A/2 - Y*A/2
y += (X+Y)*A*sqrt(3)/2

只要我所做的假设成立,这应该有用。

编辑:顺便说一下,如果图像有深度,A必须硬编码,因此你无法从图像尺寸中自动提取A.