现在的位置: 首页 > 综合 > 正文

cocos2d-x 一道简单面试题,触摸事件的重新分发

2018年05月27日 ⁄ 综合 ⁄ 共 3669字 ⁄ 字号 评论关闭

转载请注明出处 http://blog.csdn.net/rct1985


前段时候换工作时,去触控科技面试,面试官问了这么一个问题。”当弹出一个新窗口时,如果屏蔽掉下面层的触摸事件?“
这个问题对于接触cocos2d引擎一段时间的同学来说,都不算难。当时我想到了两种解决方案,也是在之前项目中用到过的:

一、加一个屏蔽层,TouchMaskLayer, 它的写法差不多就是 
a. CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuTouchPriority, true);
b. ccTouchBegan 中 return true;
二、先把本层的触摸开关手动关掉,再加弹出层,实现方式差不多是 :
a. 本层实现 onControl() 和 lostControl(), 把本层触摸相关的对象(CCLayer, CCMenu CCEditbox,...)setTouchEnable(true/false), 
b.弹出新层之前,调用lostControl(), 新层关掉时回调onControl()

第一种写法简单粗暴,简单的逻辑可以直接这么用。它的问题是,如果弹出层上需要多点触摸的话,这是行不通的,因为多点触摸优先级没有TouchMaskLayer高,它将得不到事件。
第二种方法,是和三国塔防程序同事杨新宁,魏莱一起讨论而来的。这种方式我一直在用,除了麻烦一些外,没发现任何问题。其实这种方式也没想象中的麻烦,因为一个场景中可以有触摸事件的对象也就那几个。

我问他们有什么更好的方式时,捕鱼2主程汪东林(在些表示感谢)说了他们的做法,自己处理事件分发。我根据这个想法自己做了个弹出层的基类UpperLayer

//
//  UpperLayer.h
//  MythLeague
//
//  Created by raochongtao on 13-6-26.
//
//

/* 功能
 * 1. 弹出层的基类, 比下层拥有更高的优先级, 用于屏蔽下层,及本层外触摸事件
 * 2. 提供一个容量,及相应方法,用于装纳需要处理事件的对象 CCTouchDelegate*对象, 
 */


#ifndef __MythLeague__UpperLayer__
#define __MythLeague__UpperLayer__

#include "Global/Constants.h"
#include "CommonLayer/TouchLogicLayer.h"

class UpperLayer : public  TouchLogicLayer{
    
public:
    UpperLayer();
    virtual ~UpperLayer();
    
    bool init();
        
    void onEnter();
    void onExit();
    void registerWithTouchDispatcher();
    
    void appendToTouchDispatch(cocos2d::CCTouchDelegate* p_touchableObject);
    
#pragma mark 触摸相关
    //开始
    bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
    //移动
    void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
    //结束
    void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
    //点击home键或其它方式引起的取消
    void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
    
public:
    //cocos2d::CCArray* m_touchDispatchTable;
    std::vector<cocos2d::CCTouchDelegate*> m_touchDispatchTable;
    int m_iIndex;//m_iIndex-1为实际索引
};

#endif /* defined(__MythLeague__UpperLayer__) */

//
//  UpperLayer.cpp
//  MythLeague
//
//  Created by raochongtao on 13-6-26.
//
//

#include "UpperLayer.h"

using namespace cocos2d;

UpperLayer::UpperLayer(){
    
}
UpperLayer::~UpperLayer(){
    
    
}

bool UpperLayer::init(){
    bool l_bResult = true;
    do {
        if(!TouchLogicLayer::init()){
            l_bResult = false;
        }                
        
    } while (0);
    return l_bResult;
}

void UpperLayer::onEnter(){
    TouchLogicLayer::onEnter();
}
void UpperLayer::onExit(){
    TouchLogicLayer::onExit();
}

void UpperLayer::registerWithTouchDispatcher()
{
    cocos2d::CCDirector* pDirector = cocos2d::CCDirector::sharedDirector();
    pDirector->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority-1, true);
}

void UpperLayer::appendToTouchDispatch(CCTouchDelegate* p_touchableObject){
    //断言,p_touchableLayer是CCLayer*类型, (可以是继承)
    CCAssert(dynamic_cast<CCTouchDelegate*>(p_touchableObject) != NULL, "p_touchableLayer must be a layer");
    m_touchDispatchTable.push_back(p_touchableObject);
}

#pragma mark 触摸相关
//开始
bool UpperLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
    //super
    TouchLogicLayer::ccTouchBegan(pTouch, pEvent);
    
    m_iIndex = Common_Empty;
    CCTouchDelegate* l_touchAble = NULL;
    int l_iIndex = 0;
    for (; l_iIndex<m_touchDispatchTable.size(); l_iIndex++) {
        l_touchAble = m_touchDispatchTable[l_iIndex];
        if (l_touchAble && l_touchAble->ccTouchBegan(pTouch, pEvent))
        {
            m_iIndex = l_iIndex;
            break;
        }
    }    
    return true;
}

//移动
void UpperLayer::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
    //super
    TouchLogicLayer::ccTouchMoved(pTouch, pEvent);
    
    if (m_iIndex >= 0) {
        CCTouchDelegate* l_touchAble = m_touchDispatchTable[m_iIndex];
        l_touchAble->ccTouchMoved(pTouch, pEvent);
    }
}

//结束
void UpperLayer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
    //super
    TouchLogicLayer::ccTouchEnded(pTouch, pEvent);
    
    if (m_iIndex >= 0) {
        CCTouchDelegate* l_touchAbleLayer = m_touchDispatchTable[m_iIndex];
        l_touchAbleLayer->ccTouchEnded(pTouch, pEvent);
    }
}

//点击home键或其它方式引起的取消
void UpperLayer::ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
    
}

所有的弹出层,只要继承一下这个就可以,他的优点是事件分发由自己来控制,比较灵活

抱歉!评论已关闭.