前言

熟悉 Cocos2d 开发的应该都知道,在一个场景中如果有多个 Layer ,这些 Layer 一个一个的叠在上面,当我们点击 Layer 上的按钮的时候可以正常的触发对应的事件。

但是,当点击的位置所在的 Layer 没有事件要响应,这时候触摸事件就会传递到下面的 Layer ,这是我们所不希望的,在经过一番搜索之后,找到了一个不错的方案,分享一下。

事件传递机制

先来简单解一下事件传递机制,如下图所示,事件的传递是按照优先级来确定的

z-order 数值较大的先收到事件,也就是最上面的先收到事件,如果上面的节点不处理,就会往下层传递。

所以这里响应事件的顺序依次是 I -> H -> G -> F -> E -> D -> C -> B -> A

如果当前节点处理该事件,则事件传递结束。

解决 Layer 触摸穿透

根据上面的分析知道, Layer 之所以会导致事件穿透到下面 Layer 是因为上层的 Layer 在该位置没有响应事件的需要。

所以根据事件传递机制就会往下传,导致下面的 Layer 接收到事件,并且刚好这个位置有需要响应触摸事件的需求,所以就响应,最后导致莫名其妙的事情发生了。

既然知道了问题的原因就好办了,我们只需要在 Layer 中把没有消费的事件给消费掉,这样就不会传递到下层了。

我们在 Layer.init 中处理这个问题,代码如下

1
2
3
4
5
6
7
auto dispatcher = Director::getInstance()->getEventDispatcher();
auto listener = EventListenerTouchOneByOne::create(); // 穿件事件监听器
listener->onTouchBegan = [](Touch* touch, Event* event) -> bool {return true; }; // 需要返回true,消费掉事件,这样才不会往下传递
listener->onTouchMoved = [](Touch* touch, Event* event) {};
listener->onTouchEnded = [](Touch* touch, Event* event) {};
listener->setSwallowTouches(true); // 设置消费事件
dispatcher->addEventListenerWithSceneGraphPriority(listener, this); // 添加监听器

这时候运行再点击就不会穿透到下层了。

总结

Layer 中的点击事件默认会传递到下层,我们可以通过在 Layer 中设置监听器的方式,把没有响应的事件给消费掉,从而达到不传递事件到下层的目的。

参考

Visual Studio cocos2d-x 3.10 触摸 防穿透方案_Memoselect 的博客-CSDN博客