我正在做一个等距游戏,我希望能够通过鼠标位置确定所选的图块。
我已经在使用常规磁贴之前完成了此操作,但是等轴测更加复杂。尽管我的代码看起来并不愉快,但我之前对此进行了许多尝试,并且取得了一定程度的成功。而且我想,任何看到该代码的人都会以为自己只是在“挥舞它”或“强行施加它”。
我以前的尝试看起来像这样。
public static Vector2 ToIsometric( int x , int y )
{
float selectedTileX = ( y * 32.0f ) + ( x * 16.0f );
float selectedTileY = ( y * 16.0f / 2 ) - ( x * 16.0f / 2 );
return new Vector2 ( selectedTileX , selectedTileY );
}
其中X和Y表示鼠标在屏幕上的位置。 16.0f表示每个图块的高度,32.0f表示每个图块的宽度。下图不使用这些值,但希望能帮助解释我确定鼠标悬停的锯齿状等距图块的索引的目标。
自问这个问题以来很长时间了,但是没有得到答复,所以我将尝试提出解决方案。
[我知道您没有使用
JavaScript
,但是在这种情况下,您的问题与进行该计算所需的数学有关,并且由于SO提供了良好的JavaScript
摘录,因此该语言非常适合查看计算结果结果。
检查此代码段,它是一个基本的图块网格,并且根据鼠标坐标选择了图块(我将使用此代码段作为基础来向您展示最终的计算):
const tileSize = 40;
const divs = document.querySelectorAll('.container div');
const tiles = Array.prototype.reduce.call(divs, (a, t) => {
a[t.dataset.row] = a[t.dataset.row] || [];
a[t.dataset.row][t.dataset.col] = t;
return a;
}, []);
const unselect = () => divs.forEach(d => d.style.background = '');
const select = (row, col) => tiles[row] && tiles[row][col] && (tiles[row][col].style.background = 'red');
document.addEventListener('mousemove', (e) => {
const row = Math.floor(e.pageY / tileSize);
const col = Math.floor(e.pageX / tileSize);
unselect();
select(row, col);
});
body {
margin: 0;
padding: 0;
}
.container {
border: 1px solid black;
display: flex;
flex-wrap: wrap;
height: 120px;
width: 120px;
}
.container * {
background: white;
border: 1px solid black;
box-sizing: border-box;
height: 40px;
width: 40px;
}
<div class="container">
<div data-row="0" data-col="0"></div>
<div data-row="0" data-col="1"></div>
<div data-row="0" data-col="2"></div>
<div data-row="1" data-col="0"></div>
<div data-row="1" data-col="1"></div>
<div data-row="1" data-col="2"></div>
<div data-row="2" data-col="0"></div>
<div data-row="2" data-col="1"></div>
<div data-row="2" data-col="2"></div>
</div>
进入计算之前,请看一下我前一段时间写的this post,因此您可以看到等轴测投影中涉及的所有数学。如您所见,在等轴测投影中,将a
作为投影前图块的宽度和高度,等轴测图块的宽度等于√3 * a
,而高度等于a
。
首先,让我们尝试做与您想做的相反的事情:给出一个等距点,让我们尝试将其转换为屏幕上的实际x
和y
坐标。看下一张图片:
可以确定几件事:
Ix
和Iy
)中,点a{1, 1}
点b{2, 2}
与屏幕上的y
位置相同。因此,在Ix
和Iy
相等的情况下,屏幕上的y
坐标保持不变。Ix
坐标减小y
坐标,而Iy
坐标增大它们。x
的b{2, 2}
位置是点x
的a{1, 1}
位置的两倍。Ix
和Iy
坐标总是增加x
坐标。因此,利用所有这些信息,让我们尝试创建一个从Ix
和Iy
到x
和y
的转换公式:
x = (Ix + Iy) * √3 / 2
y = (Ix - Iy) / 2
因此,以该公式为起点,我们可以尝试做相反的事情:具有x
和y
坐标,尝试计算等轴测坐标(Ix
和Iy
:]
x = (Ix + Iy) * √3 / 2
2 * x = (Ix + Iy) * √3
2 * x / √3 = Ix + Iy
Ix = 2 * x / √3 - Iy
另一方面:
y = (Ix - Iy) / 2
2 * y = Ix - Iy
Iy = Ix - 2 * y
所以,可以说:
Ix = 2 * x / √3 - Iy
Ix = 2 * x / √3 - (Ix - 2 * y)
Ix = 2 * x / √3 - Ix + 2 * y
2 * Ix = 2 * x / √3 + 2 * y
Ix = x / √3 + y
所以,我们使用相同的代码片段实时查看这些计算,但是这次是等轴测模式下的图块:
在下一个代码段中,等轴测坐标在
60px
坐标中向下移动y
以使整个图形在屏幕上可见,因此需要从结果中减去该数量。
const tileSize = 40;
const divs = document.querySelectorAll('.container div');
const translationY = 60;
const sqrt3 = Math.sqrt(3);
const tiles = Array.prototype.reduce.call(divs, (a, t) => {
a[t.dataset.row] = a[t.dataset.row] || [];
a[t.dataset.row][t.dataset.col] = t;
return a;
}, []);
const unselect = () => divs.forEach(d => d.style.background = '');
const select = (row, col) => tiles[row] && tiles[row][col] && (tiles[row][col].style.background = 'red');
document.addEventListener('mousemove', (e) => {
const x = e.pageX;
const y = e.pageY;
const Ix = x / sqrt3 + y - translationY;
const Iy = Ix - 2 * (y - translationY);
const row = Math.floor(Ix / tileSize);
const col = Math.floor(Iy / tileSize);
unselect();
select(row, col);
});
body {
margin: 0;
padding: 0;
}
.container {
border: 1px solid black;
display: flex;
flex-wrap: wrap;
height: 120px;
transform: translateX(40px) rotate(-60deg) skewY(30deg) scaleX(.866025);
width: 120px;
}
.container * {
background: white;
border: 1px solid black;
box-sizing: border-box;
height: 40px;
width: 40px;
}
<div class="container">
<div data-row="0" data-col="0"></div>
<div data-row="0" data-col="1"></div>
<div data-row="0" data-col="2"></div>
<div data-row="1" data-col="0"></div>
<div data-row="1" data-col="1"></div>
<div data-row="1" data-col="2"></div>
<div data-row="2" data-col="0"></div>
<div data-row="2" data-col="1"></div>
<div data-row="2" data-col="2"></div>
</div>