/* * LsTouch.h */ #ifndef LSTOUCH_H_ #define LSTOUCH_H_ #include "cocos2d.h" USING_NS_CC; class LsTouchEvent; /** * 定义可触摸元素,用于统一管理 */ class LsTouch : public CCNode { public: LsTouch(); ~LsTouch(); CREATE_FUNC(LsTouch); virtual bool init(); // 设置显示项 void setDisplay(CCSprite* dis); void setEventId(int eventId); int getEventId(); /// 常规判断 bool selfCheck(CCTouch* ccTouch, LsTouchEvent* lsTe); private: // 判断当前的元素是否被点击 bool containsCCTouchPoint(CCTouch* ccTouch); bool isParentAllVisible(LsTouchEvent* lsTe); // 用户保存显示精灵的 tag static const int TAG_DISPLAY = 100; int m_iEventId; }; class LsTouchEvent { public: LsTouchEvent(); ~LsTouchEvent(); void addLsTouch(LsTouch* touch, int eventId); void removeLsTouch(LsTouch* touch); bool sendTouchMessage(CCTouch* ccTouch); // 返回优先级较高的可触摸对象 LsTouch* getPriorityTouch(LsTouch* a, LsTouch* b); virtual void touchEventAction(LsTouch* touch) = 0; private: CCArray* m_pLsTouches; }; #endif /* LSTOUCH_H_ */
/* * LsTouch.cpp * */ #include "LsTouch.h" LsTouch::LsTouch() { CCLog("LsTouch()"); m_iEventId = 0; } LsTouch::~LsTouch() { CCLog("LsTouch().~()"); } bool LsTouch::init() { if ( !Node::init() ) { return false; } return true; } void LsTouch::setDisplay(CCSprite* dis) { // 设置以前先清除,没有也无所谓 removeChildByTag(TAG_DISPLAY, true); addChild(dis, 0, TAG_DISPLAY); } void LsTouch::setEventId(int eventId) { m_iEventId = eventId; } int LsTouch::getEventId() { return m_iEventId; } bool LsTouch::selfCheck(CCTouch* ccTouch, LsTouchEvent* lsTe) { bool bRef = false; // 可点击项的检测,可扩展 do { // 是否经过点击位置检测 CC_BREAK_IF(!containsCCTouchPoint(ccTouch)); // 是否正在运行,排除可能存在已经从界面移除,可是并无释放的可能 CC_BREAK_IF(!isRunning()); // 判断是否隐藏 CC_BREAK_IF(!isVisible()); // 这里可能还须要判断内部显示项目是否隐藏 ///// 暂留 // 不只判断当前元素是否隐藏,还须要判断在它之上的元素直到事件处理层,是否存在隐藏 CC_BREAK_IF(!isParentAllVisible(lsTe)); bRef = true; } while (0); return bRef; } bool LsTouch::containsCCTouchPoint(CCTouch* ccTouch) { // 得到显示内容 CCNode* dis = getChildByTag(TAG_DISPLAY); CCSprite* sprite = dynamic_cast<CCSprite*>(dis); CCPoint point = sprite->convertTouchToNodeSpaceAR(ccTouch); CCSize s = sprite->getTexture()->getContentSize(); CCRect rect = CCRectMake(-s.width / 2, -s.height / 2, s.width, s.height); return rect.containsPoint(point); } bool LsTouch::isParentAllVisible(LsTouchEvent* lsTe) { bool bRef = true; // 向父类转型,以便获取地址比较对象,LsTouchEvent 的对象必须同时直接或者简介继承 CCNode CCNode* nLsTe = dynamic_cast<CCNode*>(lsTe); CCNode* parent = getParent(); do { // 若是遍历完毕,说明 LsTouch 再也不 LsTouchEvent 以内 if (!parent) { bRef = false; break; } // 若是 LsTouch 在 LsTouchEvent 以内,返回 true // 注意:若是想让LsTouchEvent 处理 不在其 CCNode 结构以内的元素,则取消此处判断 if (nLsTe == parent) { break; } if (!parent->isVisible()) { bRef = false; break; } parent = parent->getParent(); } while (1); return bRef; } LsTouchEvent::LsTouchEvent() { CCLog("LsTouchEvent()"); m_pLsTouches = CCArray::create(); m_pLsTouches->retain(); } LsTouchEvent::~LsTouchEvent() { CCLog("LsTouchEvent().~()"); m_pLsTouches->release(); } void LsTouchEvent::addLsTouch(LsTouch* touch, int eventId) { touch->setEventId(eventId); m_pLsTouches->addObject(touch); } void LsTouchEvent::removeLsTouch(LsTouch* touch) { m_pLsTouches->removeObject(touch, true); } bool LsTouchEvent::sendTouchMessage(CCTouch* ccTouch) { // 编写判断,集合中的哪一个元素级别高,就触发哪个 LsTouch* lsTouch = NULL; // 得到点击的点 CCObject* pObj = NULL; LsTouch* lt = NULL; CCARRAY_FOREACH(m_pLsTouches, pObj) { lt = dynamic_cast<LsTouch*>(pObj); if (lt) { if (lt->selfCheck(ccTouch, this)) { if (lsTouch == NULL) lsTouch = lt; else // 若是已存在符合条件元素,比较优先级 lsTouch = getPriorityTouch(lsTouch, lt); } } } // 比对最终只有一个元素触发 if (lsTouch){ touchEventAction(lsTouch); return true; } return false; } LsTouch* LsTouchEvent::getPriorityTouch(LsTouch* a, LsTouch* b) { // 触摸优先级经过 CCNode 树判断,也既是显示层次级别等因素 // 以当前元素为“根”向父类转型,以便获取地址比较对象,LsTouchEvent 的对象必须同时直接或者简介继承 CCNode CCNode* nLsTe = dynamic_cast<CCNode*>(this); // 共同的分枝 CCNode* allParent = NULL; // 寻找 a 与 b 共同的分枝 CCNode* nAParent = a; CCNode* nBParent = b; CCNode* nAChild = NULL; CCNode* nBChild = NULL; do { nAChild = nAParent; nAParent = nAParent->getParent(); if (!nAParent) break; nBParent = b; do { nBChild = nBParent; nBParent = nBParent->getParent(); if (!nBParent) break; if (nAParent == nBParent) { allParent = nAParent; break; } if (nBParent == nLsTe) { break; } } while (1); if (allParent) break; if (nAParent == nLsTe) { break; } } while (1); // 此处只须要判断 nAChild 和 nBChild 的优先级便可,默认返回 a if (!nAChild || !nBChild) return a; // 根据 ZOrder 判断,若是 ZOrder同样,根据索引位置判断 if ( nAChild->getZOrder() == nBChild->getZOrder() ) { return (allParent->getChildren().getIndex(nAChild)) > (allParent->getChildren().getIndex(nBChild)) ? a : b; } else { return nAChild->getZOrder() > nBChild->getZOrder() ? a : b; } }
调用例子:html
1. 继承
this
class HelloWorld : public cocos2d::Layer, public LsTouchEvent
2. 重写 touchEventAction:spa
void HelloWorld::touchEventAction(LsTouch* touch) { //touch->getEventId() 事件ID CCLog("touch event action id: %d", touch->getEventId()); }
3.调用code
//建立精灵 auto sprint1 = Sprite::create("CloseNormal.png"); //建立可触控对象 LsTouch* lt = LsTouch::create(); //设置可触控对象的位置 lt->setPosition(origin.x, origin.y); //把精灵绑定到可操控对象上,把精灵加入带可操控对象表 lt->setDisplay(sprint1); //把可触控对象加入到场景中 this->addChild(lt); //把可触控对象加入事件处理,当触屏绑定精灵时调用touchEventAction //并传达事件ID,根据区分ID 处理对应的事情 this->addLsTouch(lt, 120); //建立布景的 触摸监听 auto listener1 = EventListenerTouchOneByOne::create();//建立一个触摸监听 listener1->setSwallowTouches(true);//设置是否想下传递触摸 listener1->onTouchBegan = [ = ](Touch* touch, Event* event){ // 给事件类 发送消息 sendTouchMessage(touch); return true; }; _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
本文引用:http://blog.leafsoar.com/archives/2013/05-25.htmlorm