← 返回首页

45 度地图:真实坐标怎么换算成格子坐标

2026-09-27 · 开发日志 · 算法

我们项目里的地图是斜 45 度视角的,也就是常说的等距(isometric)地图: 屏幕上看到的每一个「格子」其实是一个扁菱形。策划配表、剧情触发、刷怪点用的都是真实世界坐标, 而寻路、碰撞、视野裁剪要的却是格子坐标。这两者之间隔着一次 45 度旋转, 第一次看那段转换代码的时候我是懵的,后来把映射关系老老实实列成方程才顺过来。

先约定几个参数

那个看着有点怪的公式

通用写法是这样:

gridX = 0.5 * ( y / (格子高度 >> 1) + x / (格子宽度 >> 1) ) − 横向格子总数 / 2
gridY = 0.5 * ( y / (格子高度 >> 1) − x / (格子宽度 >> 1) ) + 纵向格子总数 / 2

把上面的参数代进去,就是配表里最常见的那一版:

x: ( 0.5 * ( (D1 / 25) + (C1 / 50) ) ) − 100
y: ( 0.5 * ( (D1 / 25) − (C1 / 50) ) ) + 100

这里的 D1 是真实坐标的 y,C1 是真实坐标的 x; 25 是 50 >> 1,50 是 100 >> 1, 两个 100 是 200 格的一半。也就是说,这个公式里没有一个数字是拍脑袋来的, 全都能从格子尺寸和地图格数推出来。

为什么长这样

第一步:把真实坐标除以半格。 令 u = x / (W / 2)、v = y / (H / 2), 代入参数就是 u = x / 50、v = y / 25。 这一步的意义是把像素刻度换掉——在等距地图里,沿着格子轴走一格,世界坐标正好变化「半个格宽 + 半个格高」, 所以除以半格之后,u、v 就变成了以格子为单位的量。

第二步:把「沿两条格子轴各走了多少格」换成「行列号」。 格子坐标的两条轴在世界空间里是斜的,一格一格的走法对应的是「行 + 列」的和与差,于是有:

u = (gridX − gridY) + 横向格子总数
v = gridX + gridY

后面那个「+ 横向格子总数」是地图偏移量:格子地图的左下角在世界坐标里并不在原点, 要先把这个偏移补回来,否则算出来的行列号会整体偏掉半张图。

第三步:解这个小方程组。 把上面两式相减、相加,就能把 gridX、gridY 单独解出来:

gridX − gridY = u − 200    →    gridX = ( u + v − 200 ) / 2
gridX + gridY = v            →    gridY = ( v − u + 200 ) / 2

整理一下就是开头那个公式:一个 0.5 来自除以 2, 一个 − 100(横向格数的一半)、一个 + 100(纵向格数的一半)来自那个偏移量。 所以公式里「一个减、一个加」不是笔误,而是行列号在坐标系里朝向不同导致的。

拿几个坐标验算一下

用 u = x / 50、v = y / 25 代入上面三步算一遍:

真实坐标 (x, y)uv格子坐标 (gridX, gridY)说明
(10000, 5000)200200(100, 100)地图正中心
(10000, 0)2000(0, 0)世界矩形下边中点
(20000, 5000)400200(200, 0)世界矩形右边中点
(10000, 10000)200400(200, 200)世界矩形上边中点
(0, 5000)0200(0, 200)世界矩形左边中点

这里有个我第一次没反应过来、后来才发现挺关键的点:格子地图是内接在世界矩形里的一个菱形。 世界矩形的范围是 x ∈ [0, 20000]、y ∈ [0, 10000], 而它的四个角算出来是 (−100, 100)、(100, −100)、 (100, 300)、(300, 100)——全都在格子地图外面。 反过来,格子地图的四个角,对应的正是世界矩形四条边的中点,也就是上面表里那四行。

所以配表的时候不能想当然地以为「世界坐标的原点就是地图左下角」。真实坐标 (0, 0) 落在格子地图之外,用它去取格子会直接越界。要按表里这个对应关系去摆东西。

反算:从格子回到真实坐标

拾取点击点、把格子里的配置还原成世界坐标时要用反算,直接把上面第二步的两个式子倒过来:

u = gridX − gridY + 横向格子总数
v = gridX + gridY
x = u * (格子宽度 >> 1)
y = v * (格子高度 >> 1)

拿 gridX = gridY = 100 试一下:u = 100 − 100 + 200 = 200、 v = 200,于是 x = 200 × 50 = 10000、y = 200 × 25 = 5000, 正好回到地图中心,和正算的结果对得上。

两个提醒

本文为个人开发笔记,公式与参数来自实际项目,示例数据做了简化处理。