[开发者心得] UI 开发必看:绝对坐标和本地坐标的转换指南

[复制链接]
10 |0
六安🐟片 发表于 3 小时前 | 显示全部楼层 |阅读模式
本帖最后由 六安🐟片 于 2024-11-27 13:06 编辑

如果有过UI开发经验的创作者可能会注意到,通过一些touch事件获取到的位置经常和屏幕中UI的位置对不上。
获取到的坐标是屏幕像素坐标,而屏幕中UI的坐标又是本地坐标,接着查文档又看到了绝对坐标。[猫猫惊恐!!]
一下出现了三个坐标,他们之间各自代表了什么含义?又是如何相互转换的?游戏开发中应该怎样使用?这篇文章会一次讲清楚。

电脑桌面空间和窗口空间
geometry.drawio.png
假设我们的电脑桌面大小是1920*1080的,上图中灰色的部分就代表我们的电脑桌面。
这时,打开口袋方舟客户端的窗口,这个窗口在桌面中,位置是(160,90),同样,在窗口最左上角的点,在桌面中位置也是(160,90)。但是,当我们看向窗口内部,以整个窗口为参考时,窗口最左上角的点坐标则是(0,0)。
同时,在电脑桌面上,窗口的大小是按桌面像素来算的,为1600x900,而在窗口中,窗口内部的大小又被定义为了1920x1080。
在这种情况下,我们可以将桌面的坐标系统看作绝对坐标系,将窗口的坐标系统看作本地坐标系。

绝对位置和本地位置的转换
在使用onRawTouchBegin()等手指触摸代理时,获取到的是桌面的绝对位置。因此,想要在游戏中使用的话,需要先转换成本地位置才可以使用。下面介绍了两种转换方法。


InputUtil.onRawTouchBegin().add((fingerIndex: number, position: Vector2) => {
                // position目前是桌面绝对位置
                console.log("onRawTouchBegin", fingerIndex, position);

                // 方法1 通过absoluteToViewport转换为本地位置
                let outViewportPosition = new Vector2();
                let outPixelPosition = new Vector2();
                absoluteToViewport(position, outPixelPosition, outViewportPosition);

                // 方法2 获取到视口的Geometry, 通过absoluteToLocal获取到本地坐标
                let viewportGeometry = getViewportWidgetGeometry();
                let localPos2 = absoluteToLocal(viewportGeometry, position);
                console.log("localPos1", outViewportPosition);

                console.log("localPos2", localPos2);
                console.log("localPixelPos", outPixelPosition);

            })


image.png
通过absoluteToViewport进行坐标转换的时候可以获得两个坐标,一个是本地坐标,另一个是像素坐标。本地坐标就是以视口左上角为原点,以视口分辨率为标准的坐标。而像素坐标则是以视口左上角为原点,以桌面分辨率为标准的。通常,可以直接在游戏逻辑中使用的是本地坐标。

另一个获取玩家Touch事件的方法,onTouchBegin()获取到的则是像素坐标。如果在游戏中使用的话,也需要用screenToViewport()做一次转换。
onTouchBegin()和onRawTouchBegin()的区别请参考InputUtil | API


InputUtil.onTouchBegin((index: number, location: Vector2, touchType: TouchInputType) => {
    console.log("onTouchBegin", index, location, touchType);
    const viewportPosition = screenToViewport(location);
    console.log("viewportPosition", viewportPosition);
})


什么是Geometry
上文中的代码在使用absoluteToLocal()时,需要传入一个Geometry对象作为参数。那么什么是Geometry呢,我们又该怎样获得Geometry呢?
Geometry是一个界面几何坐标信息。包含了对UI widget有用的数据,尤其是位置/大小变换的数据。每当UI对象的变换时,都会在Geometry下记录用于计算位置/大小变换的最新信息。
可以通过tickSpaceGeometry获取到最后一次用于驱动Widget Tick的几何信息。之后就可以使用Geometry对象来进行本地坐标,绝对坐标和屏幕像素坐标的空间变换。
下面的代码描述了已知视口本地坐标下的一个点,如何转换成绝对坐标和屏幕的像素坐标:

const rootGeometry = this.rootCanvas.tickSpaceGeometry;
const rootAbsPosition = rootGeometry.getAbsolutePosition();
// 转换成绝对坐标

const absPosition = localToAbsolute(rootGeometry, localPosition);
// 屏幕坐标是绝对坐标减去窗口的的绝对位置
const localPixelPosition = absPosition.clone().subtract(rootAbsPosition);


img_v3_02h1_9a8da280-4766-4e60-b720-6698f4e9214g.jpg
上面这个示例项目的截图中定义了五个点,视口的左上角,右下角,中心,左下某点,右上某点。并分别打印了每个点的绝对坐标,本地坐标和屏幕像素坐标。可以拖动窗口的变化来进一步理解不同坐标的含义。
👇同时打开4个客户端窗口
img_v3_02h1_9670a7f4-b65e-41bd-b653-b2abb05f7aag.jpg
👇在移动端开启游戏
img_v3_02h1_3e9d68a4-fba6-4967-8335-dcb7dca7d40g.jpg
示例项目
InputDemo.rar (1.19 MB, 下载次数: 0)
更多图片 小图 大图
组图打开中,请稍候......
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表