加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2dx 3.2 解决触摸事件中两个按钮同时响应的问题

发布时间:2020-12-14 19:56:20 所属栏目:百科 来源:网络整理
导读:上篇触摸机制讲解中提到过存在两个按钮同时响应的问题。 问题描述 我们一般使用EventListenerTouchOneByOne注册触摸事件,但是这里的触摸消息是按顺序依次响应的,当你在屏幕中同时点击了两个按钮(A和B),彼此没有交集,触摸机制会依次触发两次触摸消息,

上篇触摸机制讲解中提到过存在两个按钮同时响应的问题。

问题描述

我们一般使用EventListenerTouchOneByOne注册触摸事件,但是这里的触摸消息是按顺序依次响应的,当你在屏幕中同时点击了两个按钮(A和B),彼此没有交集,触摸机制会依次触发两次触摸消息,一次按钮A的触摸消息,另一次按钮B的触摸消息。重要的是依次触发消息,每次触摸消息都会执行按钮A和按钮B的回调函数,根据回调函数里面的区域判断当前的触摸消息点击到了哪个按钮。这样按钮A和按钮B的回调函数会各执行两次,即使对每个按钮设置setSwallowTouches(true),也只对点击到按钮的那次触摸消息有作用。因为setSwallowTouches只在onTouchBegan返回true的时候才生效。假设按钮A的触摸优先级高,当处理按钮A的触摸消息时,区域判断返回true,触摸会被吞噬,按钮B不会被触发,但是处理按钮B的触摸消息时,按钮A的区域判断失败,setSwallowTouches不会执行,接着执行按钮B的回调函数。因此,两个按钮同时响应了。再提一点是,android上面是这样的,但是ios上,是不会同时响应两个按钮,这个可能跟操作系统有关吧。。

menu的实现方式

引擎中的Menu类已经对这种情况做了处理,可以参考一下如何下代码,具体思路是在触摸回调中加入一个状态的判定。开始处理一个触摸消息后,在执行onTouchBegan后,一直到onTouchEnd结束调用之前,禁用其他按钮的触摸。

bool Menu::onTouchBegan(Touch* touch,Event* event)
{
    if (_state != Menu::State::WAITING || ! _visible || !_enabled)
    {
        return false;
    }
    
    for (Node *c = this->_parent; c != nullptr; c = c->getParent())
    {
        if (c->isVisible() == false)
        {
            return false;
        }
    }
    
    _selectedItem = this->getItemForTouch(touch);
    if (_selectedItem)
    {
        _state = Menu::State::TRACKING_TOUCH;
        _selectedItem->selected();
        
        return true;
    }
    
    return false;
}

void Menu::onTouchEnded(Touch* touch,Event* event)
{
    CCASSERT(_state == Menu::State::TRACKING_TOUCH,"[Menu ccTouchEnded] -- invalid state");
    this->retain();
    if (_selectedItem)
    {
        _selectedItem->unselected();
        _selectedItem->activate();
    }
    _state = Menu::State::WAITING;
    this->release();
}
_state 变量就是为了防止按钮同时响应的状态变量,如果当前有按钮不是处在Menu::State::WAITING状态时,就说明有按钮正在响应,不处理当前的触摸消息。但是,这同样会引入一个问题,当一个scene的不同layer中有多个menu呢,那也会导致处于不同的menu的按钮同时响应。规避办法就要看开发者如何设计了,又或者一个scene共同一个menu。。

自定义按钮类的实现方式

项目中也有很多自定义按钮类的时候,一般会使用起来会比menu类更方便,更直接。自己封装的按钮类一般都会导致上述问题,尤其是当封装的按钮的种类过多时,要支持.9的,又要支持两张图片合成的,等等。所以这里提供一个解决思路,也是参照menu的实现方式。
自定义一个buttonManger单例类,用来做点击的状态判定,当有按钮在执行触摸期间,禁止其他按钮执行,包括menu类型的按钮。
class ButtonManager;
static ButtonManager* m_instance = nullptr;
class ButtonManager
{
public:
    ButtonManager();
    ~ButtonManager();
    
    static ButtonManager* getInstance()
    {
        if (!m_instance)
        {
            m_instance = new ButtonManager();
        }
        return m_instance;
    }
    
    static void release()
    {
        if (m_instance)
        {
            delete m_instance;
            m_instance = nullptr;
        }
    }

private:

	CC_SYNTHESIZE(bool,m_bIsClickEnable,IsClickEnable);
    
private:
    
    std::vector<WWButton*>  m_allButtons;
    
};
很简单的buttonManager类,都不需要cpp文件,根据m_bIsClickEnable变量来判断当前按钮状态即可。

使用方法

bool WWButton::onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
	if (!m_bEnable)
	{
		return false;
	}

	if (!ButtonManager::getInstance()->getIsClickEnable())
	{
		return false;
	}

	if (!containTouch(touch))
	{
		return false;
	}

	ButtonManager::getInstance()->setIsClickEnable(false);
    return true;
}

void WWButton::onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
    ButtonManager::getInstance()->setIsClickEnable(true);
}
WWButton是一个按钮基类,只要继承此类,扩展的子类都不用担心按钮同时响应的问题。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读