应用数学计算锯齿状等距正方形的面积

问题描述 投票:0回答:1

我正在做一个等距游戏,我希望能够通过鼠标位置确定所选的图块。

我已经在使用常规磁贴之前完成了此操作,但是等轴测更加复杂。尽管我的代码看起来并不愉快,但我之前对此进行了许多尝试,并且取得了一定程度的成功。而且我想,任何看到该代码的人都会以为自己只是在“挥舞它”或“强行施加它”。

我以前的尝试看起来像这样。

    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表示每个图块的宽度。下图不使用这些值,但希望能帮助解释我确定鼠标悬停的锯齿状等距图块的索引的目标。

enter image description here

isometric orthogonal
1个回答
0
投票

自问这个问题以来很长时间了,但是没有得到答复,所以我将尝试提出解决方案。

[我知道您没有使用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

首先,让我们尝试做与您想做的相反的事情:给出一个等距点,让我们尝试将其转换为屏幕上的实际xy坐标。看下一张图片:

isometric projection

可以确定几件事:

  1. 在等轴测坐标(IxIy)中,点a{1, 1}b{2, 2}与屏幕上的y位置相同。因此,在IxIy相等的情况下,屏幕上的y坐标保持不变。
  2. [Ix坐标减小y坐标,而Iy坐标增大它们。
  3. xb{2, 2}位置是点xa{1, 1}位置的两倍。
  4. [IxIy坐标总是增加x坐标。

因此,利用所有这些信息,让我们尝试创建一个从IxIyxy的转换公式:

x = (Ix + Iy) * √3 / 2 
y = (Ix - Iy) / 2

因此,以该公式为起点,我们可以尝试做相反的事情:具有xy坐标,尝试计算等轴测坐标(IxIy:]

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>
© www.soinside.com 2019 - 2024. All rights reserved.