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 的位置决定是否 吞并事件就好了

原文地址:https://www.cnblogs.com/dou-ya/p/4290745.html