我有一个类似国际象棋的网格系统,我想构建一个算法来获取给定图块周围给定范围内的正方形,假设距离应该以十字形方式计算(对角线计数 2)。
因此,假设圆是中心点,这里是一个示例图像:
我找到了这个解决方案(我正在使用 javascript):
function findRange(tile, range){
var tiles = [];
for(row = 0; row < rows; row++){
for(col = 0; col < cols; col++){
if( (Math.abs(row - tile.y) + Math.abs(col - tile.x)) <= range )
tiles.push([col,row]);
}
}
return tiles;
}
基本上,我遍历所有图块,然后将坐标的绝对值差之和与我的范围进行比较。我的意思是,它有效(令我惊讶);但是,由于某种原因,它感觉不对,感觉有点花哨,而且循环每个图块也可能不是最佳选择:虽然我正在使用小网格,我不认为循环这些是一项昂贵的操作.
从好的方面来说,代码真的很小。
我问了我的一个从事游戏开发的朋友想出一个解决这个问题的方法,他提出了这个建议(在 C++ 中):
Node *GetNodeAt(float x, float y)
{
float width = m_nodeSize * m_columns;
float height = m_nodeSize * m_rows;
if( x < 0.0f || y < 0.0f ||
x >= width || y >= height)
return nullptr;
int r = y/m_nodeSize;
int c = x/m_nodeSize;
int target = (m_columns*r + c);
return &m_nodesArray[target];
}
std::list<Node*> GetCrossArea(Node *origin, int range, bool addOriginNode)
{
std::list<Node*> area;
Node *n;
for(int k = range; k >= -range; k--)
{
n = GetNodeAt(origin->GetPosition().x + m_nodeSize * k, origin->GetPosition().y);
if(k == range || k == -range)
area.push_back(n);
else
{
if(n != origin)
area.push_back(n);
else if(addOriginNode)
area.push_back(n);
Node *nVert;
int verticalSteps = (range - abs(k));
for(int q = verticalSteps; q > 0; q--)
{
nVert = GetNodeAt(n->GetPosition().x, n->GetPosition().y + m_nodeSize * verticalSteps);
area.push_back(nVert);
nVert = GetNodeAt(n->GetPosition().x, n->GetPosition().y + (1 - m_nodeSize) * verticalSteps);
area.push_back(nVert);
verticalSteps--;
}
}
}
return area;
}
问题
有没有更好的算法来解决这个问题?如果不是,建议的解决方案中哪个更好?我的方法是否遗漏了一些完全明显的东西?