cocos 新手引导之事件穿透
游戏中新手引导 一般都是通过蒙版然后突出某一位置,并配合相应动画来实现的。遮罩层有两个需求,一是可以挖个洞,二是这个洞事件可以穿透,
其他区域不能穿透。如果事件不能穿透,那就需要做很多工作来处理相应的响应。穿透之后实际点的就是那个位置,只需要处理遮罩部分应该有的行为
研究了cocos2dx 3.1 的事件系统,发现虽然不能原生支持,但我们可以简单扩展一下就能达到我们的目的
下边是源代码:
LayoutTouchBreak.h
class LayoutTouchBreak: public Layout { DECLARE_CLASS_GUI_INFO public: LayoutTouchBreak(); LayoutTouchBreak(Layout* widget); static LayoutTouchBreak* create(); static LayoutTouchBreak* createWithLayout( Layout* widget ); ~LayoutTouchBreak(); void setBreakArea( Rect& rect ); CC_CONSTRUCTOR_ACCESS: virtual bool init() override; protected: virtual bool onTouchBegan(Touch *touch, Event *unusedEvent) override; virtual void onTouchMoved(Touch *touch, Event *unusedEvent) override; virtual void onTouchEnded(Touch *touch, Event *unusedEvent) override; virtual void onTouchCancelled(Touch *touch, Event *unusedEvent) override; virtual Widget* createCloneInstance() override; private: //触摸是否在穿透区域内 bool touchInBreakArea(Touch *touch); // 触摸事件如果在这个矩形区域内,则可以穿透 继续传递下去 Rect _breakArea; };
LayoutTouchBreak.cpp
IMPLEMENT_CLASS_GUI_INFO(LayoutTouchBreak) LayoutTouchBreak::LayoutTouchBreak() { } LayoutTouchBreak::LayoutTouchBreak(Layout* widget) { copySpecialProperties(widget); } LayoutTouchBreak::~LayoutTouchBreak() { } LayoutTouchBreak* LayoutTouchBreak::create() { LayoutTouchBreak* layoutTouchBreak = new LayoutTouchBreak(); if (layoutTouchBreak && layoutTouchBreak->init()) { layoutTouchBreak->autorelease(); return layoutTouchBreak; } CC_SAFE_DELETE(layoutTouchBreak); return nullptr; } LayoutTouchBreak* LayoutTouchBreak::createWithLayout( Layout* widget ) { if (widget == nullptr) { return nullptr; } LayoutTouchBreak* l = create(); if (l) { l->copyProperties(widget); l->copySpecialProperties(widget); } return l; } Widget* LayoutTouchBreak::createCloneInstance() { return LayoutTouchBreak::create(); } void LayoutTouchBreak::setBreakArea(Rect& rect) { _breakArea = rect; } bool LayoutTouchBreak::onTouchBegan(Touch *touch, Event *unusedEvent) { bool hitted = Layout::onTouchBegan(touch, unusedEvent); if (touchInBreakArea(touch)) { _touchListener->setSwallowTouches(false); } else { _touchListener->setSwallowTouches(true); } return hitted; } void LayoutTouchBreak::onTouchMoved(Touch *touch, Event *unusedEvent) { Layout::onTouchMoved(touch, unusedEvent); if (touchInBreakArea(touch)) { _touchListener->setSwallowTouches(false); } else { _touchListener->setSwallowTouches(true); } } void LayoutTouchBreak::onTouchEnded(Touch *touch, Event *unusedEvent) { Layout::onTouchEnded(touch, unusedEvent); if (touchInBreakArea(touch)) { _touchListener->setSwallowTouches(false); } else { _touchListener->setSwallowTouches(true); } } void LayoutTouchBreak::onTouchCancelled(Touch *touch, Event *unusedEvent) { Layout::onTouchCancelled(touch, unusedEvent); if (touchInBreakArea(touch)) { _touchListener->setSwallowTouches(false); } else { _touchListener->setSwallowTouches(true); } } bool LayoutTouchBreak::init() { return Layout::init(); } bool LayoutTouchBreak::touchInBreakArea(Touch *touch) { auto touchPos = touch->getLocation(); Vec2 nsp = convertToNodeSpace(touchPos); if (_breakArea.containsPoint(nsp)) { return true; } return false; }
只要动态的根据 touch 的位置决定是否 吞并事件就好了