游戲中新手引導 一般都是通過蒙版然后突出某一位置,並配合相應動畫來實現的。遮罩層有兩個需求,一是可以挖個洞,二是這個洞事件可以穿透,
其他區域不能穿透。如果事件不能穿透,那就需要做很多工作來處理相應的響應。穿透之后實際點的就是那個位置,只需要處理遮罩部分應該有的行為
研究了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 的位置決定是否 吞並事件就好了