如何高效查找鼠标当前所处六边形网格(hex grid)对应瓦片
六边形网格鼠标悬停瓦片定位优化方案
1. 低成本快速优化:移除开平方计算
你当前的距离计算中sqrt运算开销很高,但比较两个距离的大小关系时,直接比较平方和的结果完全等价,不需要开根号。修改后效率能提升30%~50%,且完全不需要改动原有逻辑:
def get_squared_distance(x1, y1, x2, y2): return (x2 - x1)**2 + (y2 - y1)**2 def find_nearest_hex(pos): min_val = float('inf') index = 0 px, py = pos for i, (x, y) in enumerate(CENTER_LIST): dist_sq = get_squared_distance(px, py, x, y) if dist_sq < min_val: min_val = dist_sq index = i return index
同时用enumerate简化遍历逻辑,用float('inf')替代硬编码的10000阈值,避免大地图场景下的边界错误。
小提示:如果你的地图瓦片总数少于1000块,优化后的遍历方案已经完全可以满足60帧的交互要求,不需要额外做更复杂的优化。
2. 最高效方案:像素坐标直接映射六边形坐标(O(1)复杂度,无需遍历)
只要你的六边形网格是规则排列的,不管是点顶对齐还是边顶对齐,都可以通过数学公式直接把屏幕像素坐标转换成对应的六边形网格坐标,完全不需要遍历所有瓦片。
核心逻辑:
- 提前确定你的六边形参数:外接圆半径、排列方向、网格原点坐标
- 输入鼠标像素坐标,通过轴向坐标转换+立方取整算法得到对应六边形的网格坐标
- 生成瓦片时预先存储「六边形网格坐标:CENTER_LIST索引」的映射表,直接查表就能得到索引
边顶对齐六边形的坐标转换示例如下(需要根据你实际的网格参数调整):
# 预先定义你的六边形参数,根据实际尺寸修改 HEX_SIZE = 32 # 六边形外接圆半径 VERTICAL_SPACING = HEX_SIZE * 1.5 HORIZONTAL_SPACING = HEX_SIZE * (3**0.5) # 生成瓦片时同步创建的坐标映射表,示例格式:hex_index_map[(轴向坐标q, 轴向坐标r)] = 列表索引 hex_index_map = {} def pixel_to_hex(pos): px, py = pos # 计算原始浮点轴向坐标 q = (px * 2/3) / HEX_SIZE r = (-px / 3 + py * (3**0.5)/3) / HEX_SIZE # 立方取整修正坐标 x, z = q, r y = -x - z rx, ry, rz = round(x), round(y), round(z) x_diff, y_diff, z_diff = abs(rx - x), abs(ry - y), abs(rz - z) if x_diff > y_diff and x_diff > z_diff: rx = -ry - rz elif y_diff > z_diff: ry = -rx - rz else: rz = -rx - ry # 直接查表返回索引 return hex_index_map[(rx, rz)]
该方案就算地图有几万块瓦片也不会有性能损耗,是规则六边形网格的最优实现。
3. 不规则网格方案:空间分区
如果你的六边形网格是不规则排列的(比如有空洞、手动摆放的异形地图),没法用坐标直接映射,可以用空间分区减少每次遍历的数量:
- 把整个地图划分为固定大小的网格块,块大小设置为2~3倍的六边形宽度,保证目标瓦片肯定在当前块+相邻8个块的范围内
- 每个块只存储落在块内的六边形索引
- 每次先计算鼠标落在哪个块里,只遍历这个块和相邻块的六边形即可,不需要遍历全地图
内容的提问来源于stack exchange,提问作者Dakota
相关产品推荐
相关产品推荐

