等距碰撞 - '钻石'形状检测

时间:2015-01-16 11:01:12

标签: c++ perspective isometric

我的项目暂时使用等距视角我在它们上方以网格格式显示坐标以进行调试。但是,当涉及到玩家的碰撞/网格锁定时,我有一个问题。

由于精灵绘图的性质,我的数学正在创造一些问题与三角形'角落空白区域的纹理。我认为问题类似于下面(蓝色是我认为我的瓷砖被检测的方式,而红色是理想的应该如何检测它们以便在瓷砖上进行准确的漫游运动:

Reference Screenshot

正如你所看到的,检查我所站立的瓷砖的布尔值(它将像素置于玩家脚的中心位置,玩家以后会成为汽车并根据运动方向拍摄像素)在几个场景中返回虚假和拒绝移动,以及让玩家在一些不应该被允许的地方移动。

我认为这是因为每个纹理的截止区域(我认为)被认为是网格区域的一部分,因此当玩家处于其中一个角落区域时,它并不是真正检查正确的区域,所以返回错误的结果。

我用于创建网格的代码是:

int VisualComponent::TileConversion(Tile* tileToConvert, bool xOrY)
{
    int X = (tileToConvert->x - tileToConvert->y) * 64; //change 64 to TILE_WIDTH_HALF
    int Y = (tileToConvert->x + tileToConvert->y) * 25;

    /*int X = (tileToConvert->x * 128 / 2) + (tileToConvert->y * 128 / 2) + 100;
    int Y = (tileToConvert->y * 50 / 2) - (tileToConvert->x * 50 / 2) + 100;*/
if (xOrY)
{
    return X;
}
else
{
    return Y;
}

}

并且用于检查玩家移动的代码是:

bool Clsentity::CheckMovementTile(int xpos, int ypos, ClsMapData* mapData) //check if the movement will end on a legitimate road tile UNOPTIMISED AS RUNS EVERY FRAME FOR EVERY TILE
{
    int x = xpos + 7; //get the center bottom pixel as this is more suitable than the first on an iso grid (more realistic 'foot' placement)
    int y = ypos + 45;

    int mapX = (x / 64 + y / 25) / 2; //64 is TILE-WIDTH HALF and 25 is TILE HEIGHT

    int mapY = (y / 25 - (x / 64)) / 2;

for (int i = 0; i < mapData->tilesList.size(); i++) //for each tile of the map
{
if (mapData->tilesList[i]->x == mapX && mapData->tilesList[i]->y == mapY) //if there is an existing tile that will be entered
{
if (mapData->tilesList[i]->movementTile)
{
    HAPI->DebugText(std::to_string(mapX) + " is the x and the y is " + std::to_string(mapY));
    return true;
}
}
}
return false;
}​

我有点坚持进步,直到在游戏循环方面修复了这个问题。如果有人认为他们要么知道这个问题,要么可以帮助它变得更好,我会很感激。另外参考,我的平铺纹理是128x64像素,并且将它们绘制到屏幕后面的数学将它们视为128x50(以便干净地链接在一起)。

1 个答案:

答案 0 :(得分:3)

不是为渲染和点击映射编写特定的例程,而是认真考虑将这些视为数据的两个视图,这些视图可以根据坐标空间的矩阵变换进行转换。您可以有两个坐标空间 - 一个是用于定位和逻辑的漂亮的矩形网格。另一个是用于显示和输入的等轴测视图。

如果你不熟悉线性代数,你需要花一点时间来绕过它,但一旦你这样做,它就会使一切变得微不足道。

那么,这是如何工作的?您的等轴测视图仅仅是沼泽标准网格视图的旋转,对吧?好吧,关闭。如果您从方形网格开始,等轴测视图也会更改尺寸。无论如何:我们可以做一个简单的坐标转换吗?

逻辑坐标系 - &gt;显示系统(例如用于渲染)

纹理点=&gt;旋转45度=&gt;按sqrt(2)缩放,因为45度旋转会将块的尺寸更改为sqrt(1 * 1 + 1 * 1)

显示系统 - &gt;逻辑坐标系(例如,用于将点击映射到逻辑空间)

点击point =&gt; descale by sqrt(2)to unsquish =&gt;未旋转45度

为什么?

如果你可以进行坐标转换,那么你将为你编写的其他一切处理一个漂亮的标准矩形网格,这将使你的任何其他逻辑更简单。您的计算不会涉及计算角度或斜率。例如。现在你的“我可以向下移动”逻辑更加简单。

为简单起见,假设你有64 x 64个瓷砖。现在,将屏幕空间单击转换为逻辑磁贴只需:

(int, int) whichTile(clickX, clickY) {
    logicalX, logicalY = transform(clickX, clickY)
    return (logicalX / 64, logicalY / 64)
}

你可以做一些检查,比如看看x0,y0和x1,y1是否在同一个磁贴上,在逻辑空间中通过简单的方式进行检查:

bool isSameTile(x0, y0,  x1, y1) {
  return floor(x0/64) == floor(x1/64) && floor(y0/64) == floor(y1/64)
}

一旦定义了变换并在逻辑空间中工作,一切都会变得简单得多。

http://en.wikipedia.org/wiki/Rotation_matrix

http://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation

http://www.alcove-games.com/advanced-tutorials/isometric-tile-picking/

如果您不想处理某些矩阵库,您可以非常直接地进行等效数学运算,但如果您通过这些转换将逻辑管理的关注点与显示/输入分开,我怀疑您会更容易时间。