求基于鼠标位置的Canvas游戏Tilemap缩放数学公式
基于鼠标位置锚定的Tilemap缩放实现方案
我正好做过类似的功能,这其实是锚点缩放的经典应用——核心目标就是让鼠标指向的地图位置,在缩放前后始终停留在屏幕的同一位置,而不是单纯粗暴地增减缩放值和偏移量。咱们一步步拆解逻辑:
核心数学逻辑步骤
先明确几个关键变量:
currentScale:Tilemap当前的缩放比例(x/y方向一致的话用一个值就行)mouseScreenX/mouseScreenY:鼠标在屏幕上的坐标tilemapPosX/tilemapPosY:Tilemap当前的左上角偏移像素位置newScale:缩放后的目标比例(比如滚轮向上放大1.1倍,向下缩小到0.9倍)
把屏幕鼠标坐标转成Tilemap本地原始坐标
这个坐标是Tilemap未缩放、无偏移时,鼠标对应的真实位置,公式是:localMouseX = (mouseScreenX - tilemapPosX) / currentScale localMouseY = (mouseScreenY - tilemapPosY) / currentScale简单说就是:先把鼠标相对于Tilemap左上角的像素距离,除以当前缩放比例,得到未缩放时的原始位置。
计算缩放后的新偏移量
缩放后要保证localMouseX * newScale + 新偏移量 = mouseScreenX,变形后得到:newTilemapPosX = mouseScreenX - localMouseX * newScale newTilemapPosY = mouseScreenY - localMouseY * newScale这一步就是让鼠标指向的原始位置,在新缩放比例下,刚好落在屏幕的鼠标坐标处。
应用新的缩放和偏移
把计算出的newScale和newTilemapPosX/Y赋值给Tilemap对应属性即可。
适配你的RPG Maker代码实现
结合你给出的代码,修改后的wheel_函数可以这样写(适配RPG Maker的坐标单位逻辑):
const SM_S = SceneManager._scene; const tilemap = SM_S._spriteset._tilemap; const zoomSpeed = 1.1; // 每次滚轮的缩放倍数,比加减0.05更平滑自然 const minZoom = 0.3; // 最小缩放比例 const maxZoom = 3; // 最大缩放比例 function wheel_(event) { event.preventDefault(); // 阻止页面默认滚动行为 const currentScale = tilemap.scale.x; let newScale = currentScale; // 确定缩放方向与目标比例 if (event.wheelDeltaY > 0) { newScale = Math.min(currentScale * zoomSpeed, maxZoom); } else { newScale = Math.max(currentScale / zoomSpeed, minZoom); } if (newScale === currentScale) return; // 达到缩放边界就停止处理 // 获取鼠标屏幕坐标(RPG Maker内置方法) const mouseScreenX = Input.mouseX(); const mouseScreenY = Input.mouseY(); // 把Tilemap的tile单位偏移转成像素单位 const tileWidth = $gameMap.tileWidth(); const tileHeight = $gameMap.tileHeight(); const tilemapPosX = $gameMap._displayX * tileWidth; const tilemapPosY = $gameMap._displayY * tileHeight; // 计算鼠标在Tilemap的原始本地坐标 const localMouseX = (mouseScreenX - tilemapPosX) / currentScale; const localMouseY = (mouseScreenY - tilemapPosY) / currentScale; // 计算新的像素偏移,再转成tile单位赋值给游戏地图 const newTilemapPosX = mouseScreenX - localMouseX * newScale; const newTilemapPosY = mouseScreenY - localMouseY * newScale; $gameMap._displayX = newTilemapPosX / tileWidth; $gameMap._displayY = newTilemapPosY / tileHeight; // 应用新缩放比例 tilemap.scale.x = newScale; tilemap.scale.y = newScale; }
额外注意点
- 用倍数缩放代替固定增减值,缩放体验更自然,也更容易控制边界
- RPG Maker里的
_displayX/Y是tile单位,必须和像素单位转换后再计算,不然会出现偏移错误 - 添加缩放边界限制,避免过度缩放导致显示异常
内容的提问来源于stack exchange,提问作者jon
相关产品推荐
相关产品推荐

