下载 App

手机端点击位置和特效位置对不上?一个坐标系不匹配的坑

05/1038 浏览开发心得

现象

在做一个点击类游戏时,点击金币会在点击位置弹出 “+100” 的飘字和金币粒子特效。
在 PC 上一切正常,点哪儿特效就出现在哪儿。
但到了手机上,飘字和金币图标总是偏移一段距离——你点左边,特效跑到更左边去了。

排查过程

先理清数据流。
点击事件从 UI 组件的 onPointerDown 回调拿到 event.x, event.y,然后一路传递:
UI onPointerDown(event.x, event.y)
  → GameManager.OnCoinClick(x, y)
    → CoinParticle.Spawn(x, y)      -- NanoVG 绘制金币粒子
    → FloatingText.Show(text, x, y)  -- NanoVG 绘制飘字
中间没有任何坐标转换,直接把 UI 事件的坐标原样传给了 NanoVG 渲染。
看起来很直觉,但问题就出在这里——这两套系统用的不是同一个坐标系。

根因:两套坐标系的换算不一致

UI 系统的事件坐标使用的是基准像素(Base Pixels)。这个值等于:UI 坐标 = 物理像素 / UI.scale
而 NanoVG 渲染使用的是系统逻辑像素,在 nvgBeginFrame 中定义:
local dpr = graphics:GetDPR()
local logW = graphics:GetWidth() / dpr
local logH = graphics:GetHeight() / dpr
nvgBeginFrame(vg_, logW, logH, dpr)
所以 NanoVG 的坐标等于:NanoVG 坐标 = 物理像素 / dpr
关键在于 UI.scale 和 dpr 不一定相等。
项目使用了 UI.Scale.DEFAULT(即 DPR_DENSITY_ADAPTIVE 模式),它的计算逻辑是:
UI.scale = dpr * densityFactor
其中 densityFactor 是一个根据屏幕短边动态调节的系数,在大屏(PC)上等于 1.0,在小屏(手机)上会缩小到 0.625~0.9 左右,目的是让小屏幕上的 UI 元素不要占满整个屏幕。

为什么 PC 上没问题

PC 上 dpr 通常是 1.0,densityFactor 也是 1.0,所以 UI.scale = 1.0 * 1.0 = 1.0。
两个坐标系的除数都是 1.0,结果完全一致。

为什么手机上出问题

假设一台手机 dpr = 3.0,densityFactor = 0.8,那么 UI.scale = 3.0 * 0.8 = 2.4。
你点击了屏幕上物理坐标 (720, 1200) 的位置:
• UI 事件给出的坐标:720 / 2.4 = 300
• NanoVG 期望的坐标:720 / 3.0 = 240
你把 300 传给了期望 240 的渲染系统,特效自然往右下方偏移了。
偏移量就是 densityFactor 带来的差异。

修复

知道了原因,修复就很简单——在把坐标传给 NanoVG 之前,做一次坐标转换:
NanoVG坐标 = UI坐标 × (UI.scale / dpr)
代入上面的例子验证:300 × (2.4 / 3.0) = 300 × 0.8 = 240,完全正确。
实际代码改动只有几行,加在 OnCoinClick 函数开头:
function
GM.OnCoinClick(x, y)
    -- UI 基准像素 → NanoVG 逻辑像素
    local UI = require("urhox-libs/UI")
    local uiScale = UI.GetScale() or 1
    local dpr = graphics:GetDPR()
    local scaleFactor = uiScale / dpr
    if x then x = x * scaleFactor end
    if y then y = y * scaleFactor end
    -- 后续逻辑不变...
end

总结

这个 bug 的本质是:UI 事件系统和 NanoVG 渲染系统各自有一套从物理像素到逻辑像素的换算规则,当两者的缩放因子不同时,直接传递坐标就会产生偏移。
在只有一个 dpr 参与的简单场景(PC、或 scale 恰好等于 dpr)下,问题被掩盖了。
只有当引入了额外的密度适配因子(densityFactor),两个缩放因子产生差异时,偏移才会暴露出来。
记住一个原则:跨系统传递坐标时,永远要确认两边用的是同一个坐标系。
如果不是,就先转换,再传递。
猜你想搜
taptap 制造坐标系不匹配
01:29
官方阅,申请积分计划2,希望官方继续支持我完成这款游戏,截图
官方阅,申请积分计划2,希望官方继续支持我完成这款游戏,
视频内容只是一部分, 本游戏耗时3个月,目前完成进度百分之80, 是生存游戏,进入修仙界,走剧情找到宗门加入, 这时游戏才是真正开始, 提升实力境界后就可以变强,获取功法法术法宝, @视频内是游戏里挑战妖族入侵一种主流玩法,游戏就是围绕着这个来进行, 还有很多地方可以战斗,获得资源修炼变强,比如去藏书阁学习功法, 去法宝楼抽法宝,每一个宗门数十个法宝抽取 去修仙界探索,获得各自的资源,可能遇见妖兽
1 赞
3 回复
本地部署 AI 对接 TapMaker 指南 —— 以 CodeBuddy 为例V1.1截图
本地部署 AI 对接 TapMaker 指南 —— 以 CodeBuddy 为例V1.1
写在前面 大家好,我是橘猫,和你一样也是TapMaker的萌新玩家。在"全能神"天哥的悉心指导下,我顺利完成了本地开发环境的部署。经过这段时间的实战测试,已经成功打通了「本地开发 → 同步至TapMaker」的完整流程。 以下内容全部来自我的个人实操经验,旨在为同样在探索本地部署的朋友提供一个参考。每个人的电脑环境、网络情况、AI工具版本都不尽相同,文中的步骤仅供交流学习。如果你照着操作后遇到问题
25 赞
14 回复
【游戏上新】商业帝国大亨截图
【游戏上新】商业帝国大亨
无名小卒还是名扬天下。 从临时工到称霸宇宙。 只需点击屏幕,就能获得财富,利用财富购置产业,获取更多财富。
6 赞
4 回复
新人避坑指南第一期(核心必看)截图
新人避坑指南第一期(核心必看)
新手制作游戏项目三大避坑准则 一、前期地图规范要求 开启新项目之后,必须清晰交代需求:明确项目内容、运行环境、角色出生点位置,再交由助手制作第一张地图。 第一张地图禁止直接预览,先将生成内容存入素材库,核对样式是否符合自身预期。 核心判定方法:单独生成第一张地图预览图,第一张地图决定整体全局架构,UI、UX整体风格全部由它锁定。如果第一张地图的画面、UI、UX不符合自己的设想,立刻新建项目,不要在
9 赞
4 回复
别再烧积分了!从每次 2000 到每次 50 的血泪经验截图
别再烧积分了!从每次 2000 到每次 50 的血泪经验
适用场景:所有在用 TapTap Code 开发游戏的小白 难度:★☆☆☆☆ 背景最近群里总有人"炫耀"一次操作花了几千积分,说实话这不是值得高兴的事——这是在告诉所有人你的开发方式有根本性问题。我也走过这条弯路,所以来说说怎么改。 积分消耗的本质是什么积分 = AI 处理的 token 数量 = 你发给 AI 的内容 + AI 回给你的内容所以烧积分的本质只有两种: 你让 AI 做了大量无效/重
精华
64 赞
20 回复
2D 等轴测视角:完整理论截图
2D 等轴测视角:完整理论
2D 等轴测视角:完整理论 一、视角的本质 什么是等轴测 人站在高处斜着往下看地面,地面上的方格子不再是正方形,而变成了菱形。这就是等轴测的视觉本质。 俯视(正上方看下去): 等轴测(斜上方看下去): ┌──┬──┬──┐ ◇ ├──┼──┼──┤ ◇ ◇ ├──┼──┼──┤ ◇ ◇ ◇ └──┴──┴──┘ ◇ ◇ ◇ 正方形网格经过旋转 + 压缩,变成了菱形网格。 为什么是 2:1
6 赞
【UI教程】如何将已有的效果图应用为实际的UI界面截图
【UI教程】如何将已有的效果图应用为实际的UI界面
在经过了一些折腾和比较折磨的尝试后,我总算是摸清楚了嗒啦啦怎么把UI效果图转换为实际游戏中的UI组件,今天就给大家带来这部分的经验分享。 tips:1.本篇教程需要各位掌握最基本的ps使用,具体的操作部分我会大致讲解,但仍需各位自行学习ps的基本操作,部分可以由ai代劳的环节我会注明。 2.本篇教程需要在以我前两篇教程作为前置环节,请在阅读这两篇前置教程后再进行本篇教程内容的学习 在按照前
10 赞
4 回复
00:15
科研了一下嗒啦啦生成spine截图
科研了一下嗒啦啦生成spine
做图标动态或者转场动态这种图形类动画应该没问题,可以做到这个效果,人物动作的话不太行。 尝试做了可视化,引擎里没法实时更新创建骨骼,也用不了网格,还是得用spine软件。微调位置和动态效果幅度时间之类的可以 拆分建议自己做,复杂形状嗒啦啦有点拆不明白
23 赞
13 回复
[开发心得]让塔拉拉帮你的2D游戏做个动作编辑器(KEIS)截图
[开发心得]让塔拉拉帮你的2D游戏做个动作编辑器(KEIS)
先叠甲:笔者没有引擎开发经验,此处提供一个思路,希望我能抛砖引玉让大佬们发现更强的办法大家一起进步;(实在是可以优化的空间还很多,实则我积分告急了[表情_吐舌头]) 文字太多不想看的读者,文章底部有伪焚诀可以自取 正在用塔拉拉做一个武侠游戏,但觉得无法编辑动作对于武侠游戏多少是个硬伤, 如果绘制大量精灵图又无法角色通用,同时对于我的美术需求量也会暴涨; //提炼我的需求:各角色通用,且不会增加
精华
23 赞
5 回复
如何给自己游戏做一个简单的地图(基础版)截图
如何给自己游戏做一个简单的地图(基础版)
本教程适合完全没有经验、想做一张基础地图的开发者。大佬请绕路,这里只分享最简单实用的方法。 --- 第一步:收集瓦片素材 什么是瓦片素材? 瓦片就是一张张小格子图片,可以像拼积木一样拼成大地图。它们通常要求: · 图片是正方形(1:1 比例) · 四周边缘可以无缝衔接(左右、上下都能完美对齐) 怎么让AI生成瓦片? 直接发指令给AI(如塔拉拉或更高级的生图模型),参考下面这个例子: “给我生成一张
精华
20 赞
5 回复