Cocos Creator实现不规则区域点击

这篇具有很好参考价值的文章主要介绍了Cocos Creator实现不规则区域点击。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题背景

在CocosCreator中,点击图片透明区域依然触发节点的点击事件。但在web开发中,可以使用Inkscape、SvgPathEditor等矢量图编辑器转为SVG,或者直接从figma中导出SVG,然后监听不规则图形事件。

以地图边界高亮为例:html 类似地图的不规则图形事件处理

svg { height: 50vw; }
path { fill: #d3d3d3; transition: .6s fill; opacity: 0.6;}
path:hover { fill: #eee;opacity: 0.6; }

但Cocos Creator中Sprite目前支持的格式为jpg和png,未直接支持SVG。

方案调研

图像模板(image_stencil) mask

求助:如何控制只让图像遮罩的可视区域响应点击

图像模板可以根据设置的透明度阈值,只有当模板像素的 alpha 值大于该阈值时,才会绘制内容。
Cocos Creator实现不规则区域点击
但是该方式点击透明区域,依然会触发该节点的事件。

通过查看2.4.7版本 CCMask.js 的源码 ,可以看到在碰撞检测中,图像模板类型的mask的命中方式与矩形保持一致,只有椭圆才是单独检测,故该方式并不能解决问题。

_hitTest (cameraPt) {
    let node = this.node;
    let size = node.getContentSize(),
        w = size.width,
        h = size.height,
        testPt = _vec2_temp;
    
    node._updateWorldMatrix();
    // If scale is 0, it can't be hit.
    if (!Mat4.invert(_mat4_temp, node._worldMatrix)) {
        return false;
    }
    Vec2.transformMat4(testPt, cameraPt, _mat4_temp);
    testPt.x += node._anchorPoint.x * w;
    testPt.y += node._anchorPoint.y * h;

    let result = false;
    if (this.type === MaskType.RECT || this.type === MaskType.IMAGE_STENCIL) {
        result = testPt.x >= 0 && testPt.y >= 0 && testPt.x <= w && testPt.y <= h;
    }
    else if (this.type === MaskType.ELLIPSE) {
        let rx = w / 2, ry = h / 2;
        let px = testPt.x - 0.5 * w, py = testPt.y - 0.5 * h;
        result = px * px / (rx * rx) + py * py / (ry * ry) < 1;
    }
    if (this.inverted) {
        result = !result;
    }
    return result;
}

多边形mask

Creator | 编辑器中可操作顶点的多边形遮罩

【组件分享】使用Mask+Graphic魔改的多边形遮罩组件

[ Mask + PolygonCollider 简易自定义多边形遮罩制作 ]

沿着mask的思路,在论坛上找到了多边形mask的实现方式。大致都是在CCMask源码的基础上,增加多边形的节点添加和碰撞检测,其中一位作者实现的组件非常吸睛,github上共有400余Star,目前cocos商店已有该组件。感兴趣可阅读源码。

效果如下:
Cocos Creator实现不规则区域点击

比较有意思是其碰撞检测(点是否在多边形内),采用射线法判断。

  • 定义:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。

  • 具体步骤:将测试点的Y坐标与多边形的每一个点进行比较,会得到一个测试点所在的行与多边形边的交点的列表。在下图的这个例子中有8条边与测试点所在的行相交,而有6条边没有相交。如果测试点的两边点的个数都是奇数个则该测试点在多边形内,否则在多边形外。在这个例子中测试点的左边有5个交点,右边有三个交点,它们都是奇数,所以点在多边形内。
    Cocos Creator实现不规则区域点击

  • 算法实现:

isInPolygon(checkPoint: cc.Vec2, polygonPoints: cc.Vec2[]) {
    let counter = 0, i: number, xinters: number;
    let p1: cc.Vec2, p2: cc.Vec2;
    let pointCount = polygonPoints.length;
    p1 = polygonPoints[0];
 
    for (i = 1; i <= pointCount; i++) {
        p2 = polygonPoints[i % pointCount];
        if (
            checkPoint.x > Math.min(p1.x, p2.x) &&
            checkPoint.x <= Math.max(p1.x, p2.x)
        ) {
            if (checkPoint.y <= Math.max(p1.y, p2.y)) {
                if (p1.x != p2.x) {
                    xinters = (checkPoint.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
                    if (p1.y == p2.y || checkPoint.y <= xinters) {
                        counter++;
                    }
                }
            }
        }
        p1 = p2;
    }
    return (counter & 1) !== 0;
}

多边形mesh

多边形裁剪图片(非mask,使用mesh),新增 gizmo 支持

https://github.com/baiyuwubing/cocos-creator-examples/tree/master/meshTexture

2年前开发,已停止维护,使用不佳,节点关联顺序容易紊乱。根据作者的描述,可以解决mask过多带来性能影响。
Cocos Creator实现不规则区域点击

像素点计算

creator 2.4.8中获取像素信息

const getPixelData = (node: cc.Node, x: number, y: number) => {
  const pixelsData = getPixelsData(node);
  const startIndex =
    node.width * 4 * Math.floor(node.height - y) + 4 * Math.floor(x);
  const pixelData = pixelsData.slice(startIndex, startIndex + 4);
  return pixelData;
};

const isPixelTransparent = (node: cc.Node, x: number, y: number) => {
  const pixelData = getPixelData(node, x, y);
  return pixelData[3] === 0;
};

const getPixelsData = (node: cc.Node) => {
  if (!cc.isValid(node)) {
    return null;
  }

  // 节点宽度
  const width = Math.floor(node.width);
  const height = Math.floor(node.height);
  // 创建临时摄像机用于渲染目标节点
  const cameraNode = new cc.Node();
  cameraNode.parent = node;
  const camera = cameraNode.addComponent(cc.Camera);
  // eslint-disable-next-line no-bitwise
  camera.clearFlags |= cc.Camera.ClearFlags.COLOR;
  camera.backgroundColor = cc.color(0, 0, 0, 0);
  camera.zoomRatio = cc.winSize.height / height;
  // 将节点渲染到 RenderTexture中
  const renderTexture = new cc.RenderTexture();
  renderTexture.initWithSize(
    width,
    height,
    cc.RenderTexture.DepthStencilFormat.RB_FMT_S8
  );
  camera.targetTexture = renderTexture;
  camera.render(node);
  const pixelData = renderTexture.readPixels();

  return pixelData;
};

/** 点击事件是否合法,非透明像素 */
isValidTouch(e: cc.Event.EventTouch) {
  const touchLocation = e.touch.getLocation();
  /** 相对节点左下角的相对坐标,即图片内的坐标 */
  const locationInNode = this.node.convertToNodeSpaceAR(touchLocation);
  /** 非本节点内 透传 */
  if (!this.node.getBoundingBoxToWorld().contains(touchLocation)) {
    this.setSwallowTouches(false);
    return false;
  }

  const { anchorX, anchorY, width, height } = this.node;
  const x = locationInNode.x + anchorX * width;
  const y = -(locationInNode.y - anchorY * height);

  const isValid = !isPixelTransparent(this.node, x, y);

  this.setSwallowTouches(isValid);
  return isValid;
}

/** 设置是否阻止点击事件透传 */
setSwallowTouches(bool: boolean) {
  (this.node as any)._touchListener.setSwallowTouches(bool);
}

方案对比

方案 优点 缺点
图像模板mask - 适合图片快速裁剪渲染 - 不满足要求
多边形mask - 适用于多边形定制化裁剪 - 参考文章 [@]Mask组件多边形方案性影响手机Web性能。多边形mask使用过多,低端机性能下降严重(碰撞检测占主要原因)
- 手动描边
多边形mesh - 根据作者描述,比mask性能更优 - 手动描边
像素点计算 - 颗粒度精细,能精确到像素点
- 无需特殊处理图片
- 图片过大时,可能带来性能问题

可能的最佳实践?

在论坛中看到有个大佬在尝试svg拓展 Creator + SVG 解析渲染扩展组件 ,已上架cocos商店【价值80¥】文章来源地址https://www.toymoban.com/news/detail-457061.html

到了这里,关于Cocos Creator实现不规则区域点击的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt 不规则窗口,不规则按钮,不规划控件 不规则界面

    类似: Qt 实现 不规则样式设置,不是视觉欺骗,是真正的不规则 ,点击外面不会触发按钮的点击信号. 效果: 显示成一张图片中的图形,使用带有透明区域的png图片; 这里注意:  必须重新绘制,构造函数也一定要调用resize。 见视频,可见,点击到空白处,消失;可见实

    2024年02月09日
    浏览(34)
  • 图像中不规则物体的长轴与短轴:OpenCV实现指南

    1.首先,读取图像并将其转换为灰度图像。 2.进行图像预处理,包括使用高斯模糊和阈值化,以便更好地处理图像。 3.通过使用OpenCV的cv2.findContours()函数,找到图像中的所有轮廓。 4.遍历所有轮廓,如果轮廓点的数量大于等于5个,则将这个轮廓拟合为一个椭圆。 5.如果成功拟

    2024年02月15日
    浏览(34)
  • 浅谈OpenCV的多对象匹配图像的实现,以及如何匹配半透明控件,不规则图像

    OpenCV提供的templateMatch只负责将(相关性等)计算出来,并不会直接提供目标的对应坐标,一般来说我们直接遍历最高的相关度,就可以得到匹配度最高的坐标。但是这样一般只能得到一个坐标。 在实际操作中,我们可能需要匹配一个不规则的图像,把这个不规则的图像放进

    2024年02月10日
    浏览(40)
  • css不规则圆角矩形

    这个收集的css 效果是真的多 https://github.com/chokcoco/iCSS强烈推荐

    2024年02月20日
    浏览(32)
  • 不规则文件转JSON

    有时候,我们取出来的数据并不是一个规则的JSON文件,这个时候面对存库还是ES检索都是一个问题,所以我们就需要进行解析,然而用字符串分割是不现实的,我们需要一种快速的方法。 为了读取并转换这样的文件为JSON对象,您可以使用Jackson库。首先,您需要引入Jackson库的

    2024年02月14日
    浏览(27)
  • ArcGIS Pro如何制作不规则形状图例

    在默认的情况下,ArcGIS Pro生成的图例是标准的点、直线和矩形的,对于湖泊等要素而言,这样的表示方式不够直观,我们可以将其优化一下,制作不规则的线和面来代替原有图例,这里为大家介绍一下制作方法,希望能对你有所帮助。 在符号系统内,将水系的样式调整为我

    2024年02月12日
    浏览(31)
  • 折线的可视化及不规则柱体的绘制

    开发环境: Windows 11 家庭中文版 Microsoft Visual Studio Community 2019 VTK-9.3.0.rc0 vtk-example demo解决问题 : 1.绘制一条多段线(折现),并可视化这段折现;2.根据折现绘制一个不规则柱体 关键点 : vtkRotationalExtrusionFilter是Visualization Toolkit(VTK)中的一个过滤器,用于沿着输入曲线生成

    2024年01月25日
    浏览(30)
  • AD软件绘制不规则焊盘的器件封装

           网上有很多关于AD软件绘制不规则焊盘的帖子,搜了一些帖子看了一下,感觉不太对。严格意义上AD软件是不能绘制不规则的焊盘的,至少目前用的AD软件不支持。为什么这么说呢?    我提一个需求:假如我在PCB文件中需要随意的添加一个边长1mm的正三角形的焊盘。

    2023年04月08日
    浏览(35)
  • Open3D 不规则点云体积计算 (15)

    黑暗笼罩万物,我将是黑暗中最后的那道曙光,以雷霆,击碎黑暗!!! 点云往往是不规则的,利用别的包围盒方法获取的体积可能不太准确,如果希望获取更准确的体积,这里介绍一种基于体素划分的体积计算方法,随着体素分辨率设置的尺寸减小,其计算的体积准确率越

    2024年02月02日
    浏览(29)
  • c++多线程按行读取同一个每行长度不规则文件

    对于非常大的比如上百G的大文件读取,单线程读是非常非常慢的,需要考虑用多线程读,多个线程读同一个文件时不用加锁的,每个线程打开一个独立的文件句柄 先打开一个文件句柄,获取整个文件大小 file_size 确定要采用线程读取的部分大小 read_size 和多线程的个数 thread_num ,算出

    2024年03月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包