获取Node节点在屏幕中真实的位置

先放代码

import { Node, screen, UITransform, view } from 'cc';

export function getNodeInScreenRect(node: Node) {
  const rect = node.getComponent(UITransform)!.getBoundingBoxToWorld();
  const dpi = screen.devicePixelRatio;
  const scaleX = view.getScaleX();
  const scaleY = view.getScaleY();
  const left = (rect.x * scaleX) / dpi;
  const top = (screen.windowSize.height - (rect.y + rect.height) * scaleY) / dpi;
  const width = (rect.width * scaleX) / dpi;
  const height = (rect.height * scaleY) / dpi;

  return { left, top, width, height };
}

调用示例

const rect = getNodeInScreenRect(this.rankNode);

wx.createUserInfoButton({
  type: 'text',
  text: '获取用户信息',
  style: {
    left: rect.left,
    top: rect.top,
    width: rect.width,
    height: rect.height,
    borderColor: '#ff0000',
    borderWidth: 2,
    backgroundColor: 'rgba(0,0,0,0)',
  },
}).onTap(ee => {
  console.log('ee: ', ee);
});

需求:在微信小游戏里需要获取用户信息就必须使用微信官方的方式创建按钮 wx.createUserInfoButton

创建按钮的时候需要传入按钮的坐标和大小,然后我就开始查找,怎么把Node节点的位置转换到屏幕的相对位置,在社区里查到了使用 camera.worldToScreen 的方式,但是发现了好多问题

  • onLoad 或 start 中调用获取到的位置不正确,打印出来的值巨大一看就不对

  • 然后看到有人说需要先调用 node.updateWorldTransform() 我试了下还是不行

  • 又继续翻论坛发现有人说要先调用 camera.update()或者在下一帧获取, 哎!这回可以了,获取到的值是对的了

  • 但是获取到的坐标是基于左下角的而且尺寸还是翻倍了应该是基于dpi放大了,然后我就在想怎么获取屏幕的原始大小和dpi,经过不断尝试终于找到 screen.devicePixelRatioscreen.windowSize

  • 接着计算元素的大小使用 UITransform.getBoundingBoxToWorld () 获取到的大小,尝试画了一下按钮发现尺寸不对突然想到,这个尺寸应该原始的设计尺寸,还需要乘上缩放比例 view.getScaleX()view.getScaleY()

  • 写到这我感觉不对啊,getBoundingBoxToWorld () 返回的不就是相对于世界的位置和尺寸吗,我直接用这个位置乘以设计图缩放比再除以dpi不就可以了

获取坐标不正确

const pos = find('Canvas/Camera')?.getComponent(Camera)?.worldToScreen(this.rankNode.getWorldPosition());
console.log('pos: ', pos); // pos:  Vec3 {x: 250770, y: 825042.4615384615, z: 0.5}

增加update可以获取正确位置

const camera = find('Canvas/Camera')?.getComponent(Camera)!;
camera.camera.update();
const pos = camera?.worldToScreen(this.rankNode.getWorldPosition());
console.log('pos: ', pos); // pos:  Vec3 {x: 667.68, y: 1015.5999999999999, z: 0.5}

小提示:

  • screen 要用从 cc 里引过来的,`import { screen } from ‘cc’;

  • web 全局本身有一个 screen 我在那查半天文档为什么我的 screen 和文档上不不一样

  • 获取dpi一定要用 screen.devicePixelRatio,不要使用原生的方式去获取dpi可能会不准

    当前显示设备的物理像素分辨率与 CSS 像素分辨率之比。 注意:出于性能考虑,引擎在一些平台会限制 DPR 的最高值,这个属性返回的是引擎限制后的 DPR。

如图所示,试了多个屏幕尺寸和dpi位置一点不差

image

3赞

代码可以在cocos的IDE里获得相应的位置吗?