wechat-miniprogram / minigame-canvas-engine

轻量级canvas2d渲染引擎,开放数据域开发解决方案。
https://wechat-miniprogram.github.io/minigame-canvas-engine/
MIT License
274 stars 64 forks source link

在pad上渲染位置和实际的点击区域存在很大的偏差 #40

Closed cj841192685 closed 3 months ago

cj841192685 commented 3 months ago

image 渲染位置是上面的红框,在pad上显示没问题,但实际的点击区域是下面的大红框,与渲染的点击范围偏差很大

cj841192685 commented 3 months ago

image 注册点击事件的函数是这个,不太清楚这是什么原因造成的,看到的话麻烦帮忙查一下问题

cj841192685 commented 3 months ago

会不会是跟我们游戏两侧的黑边有关系,实际计算触摸位置的缩放因为有黑边的原因给放大了

yuanzm commented 3 months ago

你把Layout.updateViewPort的值打出来看看

yuanzm commented 3 months ago

核心是跨引擎的事件处理,因此这个接口传的值一定要是对的 https://wechat-miniprogram.github.io/minigame-canvas-engine/api/api.html#updateviewport

cj841192685 commented 3 months ago

image 传入的值是这个,这个是cocos SubContextView _updateSubContextView函数计算出来的值,我们这边没有改动

yuanzm commented 3 months ago

cocos什么版本,印象中之前有开发者反馈cocos有bug,算出来的这个值不对,实际上你看,这值显然不对,应该是相对屏幕的坐标系,y为负数都到屏幕外去了,你搜下cocos社区看看

cj841192685 commented 3 months ago

cocos creator 3.8.3最新版本,我今天也看了论坛上说的https://forum.cocos.org/t/topic/137103 也尝试过使用论坛上的方式解决问题,但依旧没解决

cj841192685 commented 3 months ago

引擎里边是这么写的


    private _updateSubContextView (): void {
        if (!this._openDataContext) {
            return;
        }

        // update subContextView size
        // use SHOW_ALL policy to adapt subContextView
        const nodeTrans = this.node.getComponent(UITransform) as UITransform;
        const contentTrans = this._content.getComponent(UITransform) as UITransform;

        const scaleX = nodeTrans.width / contentTrans.width;
        const scaleY = nodeTrans.height / contentTrans.height;
        const scale = scaleX > scaleY ? scaleY : scaleX;
        contentTrans.width *= scale;
        contentTrans.height *= scale;

        // update viewport in subContextView
        const viewportRect = view.getViewportRect();
        const box = contentTrans.getBoundingBoxToWorld();
        const visibleSize = view.getVisibleSize();
        const dpr = screenAdapter.devicePixelRatio;

        // TODO: the visibleSize need to be the size of Canvas node where the content node is.
        const x = (viewportRect.width * (box.x / visibleSize.width) + viewportRect.x) / dpr;
        const y = (viewportRect.height * (box.y / visibleSize.height) + viewportRect.y) / dpr;
        const width = viewportRect.width * (box.width / visibleSize.width) / dpr;
        const height = viewportRect.height * (box.height / visibleSize.height) / dpr;

        this._openDataContext.postMessage({
            fromEngine: true,  // compatible deprecated property
            type: 'engine',
            event: 'viewport',
            x,
            y,
            width,
            height,
        });
    }
cj841192685 commented 3 months ago

查到问题了,实际上,cocos 引擎计算的没有问题,Layout对于触摸点计算的点击位置也没有问题,但问题在于,我们游戏为了做适配,如果屏幕高宽比低于1136 / 640 时,会给游戏两侧增加黑边,导致最终Layout计算的触摸位置出现了问题,实际上应该是低于游戏最低分辨率时,通过高度来计算缩放,并且计算x轴的时候增加上黑边的宽度,这样就没问题了 image image

cj841192685 commented 3 months ago

上回cocos引擎计算出来的y轴为负数,是因为,cocos 引擎中会根据宽度的缩放,计算出一个适合这个游戏分辨率高度的高度,此时,这个高度超出了屏幕的高度,所以得到box的左上角Y轴为负数,而Layout引擎中,也是根据宽度的缩放计算触摸点的缩放值,所以最后得到的触摸点位置有问题

cj841192685 commented 3 months ago

最终修改就是这个,如果说低于游戏最低支持分辨率的设备,根据高度的缩放,计算实际的宽度,x轴,传给viewport,而大于等于最低分辨率的设备,则使用引擎自己的计算方式计算结果

yuanzm commented 3 months ago

你是手动改了Layout里面的逻辑来兼容的?这其实不太对的,这里最根本的问题在于,如果开放数据域也是cocos,主域和开放数据域都是一个坐标系,不管什么缩放策略,渲染位置和点击位置肯定能对上。

Layout 提供updateViewPort就是为了避免这个问题,因为Layout并不知道主域是什么引擎,可能是cocos、Laya、Unity等等,但只需要Layout知道自己最终被渲染到屏幕上的位置就可以了。

所以最关键的还是传给updateViewPort的值是对的,不要在里面去做兼容逻辑。

cj841192685 commented 3 months ago

嗯,改了一下,现在是在游戏中做计算宽高以及坐标,但如果以后需要以高度计算缩放,这种该怎么处理