cocos2dx 3.x 自学笔记 <二> cocos2dx 中注册触摸事件touchEvent 2.x 与 3.x
2014-10-22 12:32
639 查看
转载请注明来自_鞋男blog :/article/7618209.html
cocos2.2.5还在编译依赖库,还是先看3.2的吧
环境:win8 + vs2013
时间有限 还是先说说这个把
但是有些函数没有加这个修饰,但是在编译的过程中也提示废弃,以后再深入研究。
注册监听:
之后,在_nodeListenersMap中建立 node(target)与关联的listener的映射
另一个种
第三
现在看看事件分发:
glview->pollEvents();
。。。。。。//物理事件传递
void EventDispatcher::dispatchEvent(Event* event){
void EventDispatcher::dispatchTouchEvent(EventTouch* event){
这里面干的是
对事件排序,按优先级。
得到各个TouchMode的Listeners:
然后进入那个lambda函数里执行注册过的touch系列函数了。执行完了还会在下一个循环删除这一事件
现在讲讲ccs 2.2.x ,一直在发布新版本,ccs现在完善了不少,我们就拿最新的来将好了,ccs 3.0x之前的版本大家都熟悉了,不熟悉,网上教程一大把,我这里略微补充下
类:CCTouchDispatcher
我们经常重写void CCLayer::registerWithTouchDispatcher(),然后调用上面的注册函数,
从上面代码可以看出如果我们改变m_eTouchMode就可以修改注册模式,完成这个使命的函数CCLayer::setTouchMode( ... )
但是一定要注意调用的顺序,我们都知道在layer切换的时候先是init(),然后onEnter(),onEnterTransitionDidFinish()
在CCDirect类中有这样的一代码可以看出
我们都知道registerWithTouchDispatch()是在CCLayer的onEnter里面调用,我们只需init()或者重写onEnter(){ setTouchMode(...) ,CCLayer::onEnter();},OK!
还有一点:
从CCTouchDispatcher的数据结构来看,主要是两个容器CCArray* m_pTargetedHandlers; CCArray* m_pStandardHandlers; m_bLocked
注册好了 就是分发了,主要算法都在 CCTouchDispatcher::touches(cocos2d::CCSet * pTouches, cocos2d::CCEvent * pEvent, unsigned int uIndex) ,分类处理
暂时就写到这了,若有错误,还请留言指出,谢谢
cocos2.2.5还在编译依赖库,还是先看3.2的吧
环境:win8 + vs2013
时间有限 还是先说说这个把
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) #define CC_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) #elif _MSC_VER >= 1400 //vs 2005 or higher #define CC_DEPRECATED_ATTRIBUTE __declspec(deprecated) #else #define CC_DEPRECATED_ATTRIBUTE #endif看不懂也没关系,主要是提醒大家 但凡函数加了
CC_DEPRECATED_ATTRIBUTE表示废弃了的意思,也只能在3.x中才能看到,想跟下去看看怎么实现,水平有限,跟不了。谁知道告诉我一声,先谢了。
但是有些函数没有加这个修饰,但是在编译的过程中也提示废弃,以后再深入研究。
CC_DEPRECATED_ATTRIBUTE virtual bool ccTouchBegan(Touch *pTouch, Event *pEvent) final {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); return false;}; CC_DEPRECATED_ATTRIBUTE virtual void ccTouchMoved(Touch *pTouch, Event *pEvent) final {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchEnded(Touch *pTouch, Event *pEvent) final {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchCancelled(Touch *pTouch, Event *pEvent) final {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchesBegan(__Set *pTouches, Event *pEvent) final {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchesMoved(__Set *pTouches, Event *pEvent) final {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchesEnded(__Set *pTouches, Event *pEvent) final {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} CC_DEPRECATED_ATTRIBUTE virtual void ccTouchesCancelled(__Set *pTouches, Event *pEvent) final {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}被废弃了,为什么被废弃了(还是可以用吧),下面会讲的
virtual bool onTouchBegan(Touch *touch, Event *unused_event); virtual void onTouchMoved(Touch *touch, Event *unused_event); virtual void onTouchEnded(Touch *touch, Event *unused_event); virtual void onTouchCancelled(Touch *touch, Event *unused_event); virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event); virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event); virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event); virtual void onTouchesCancelled(const std::vector<Touch*>&touches, Event *unused_event);
注册监听:
auto listener = EventListenerTouchOneByOne::create(); listener->onTouchBegan = CC_CALLBACK_2(MainLayer::onTouchBegan, this); listener->onTouchEnded = CC_CALLBACK_2(MainLayer::onTouchEnded, this); listener->onTouchMoved = CC_CALLBACK_2(MainLayer::onTouchMove, this);//其实这里也可以用lambda去写 listener->onTouchMoved = [](const std::vector<Touch*>&touches, Event *unused_event)->bool{ /* 函数体*/} _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);//默认优先级0 ,创建listener对象,根据listenerID映射listeners容器,将listener对象存入容器中
void EventDispatcher::addEventListener(EventListener* listener) { if (_inDispatch == 0) { forceAddEventListener(listener); } else { _toAddedListeners.push_back(listener); } listener->retain(); }
之后,在_nodeListenersMap中建立 node(target)与关联的listener的映射
void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener) { std::vector<EventListener*>* listeners = nullptr; auto found = _nodeListenersMap.find(node); if (found != _nodeListenersMap.end()) { listeners = found->second; } else { listeners = new std::vector<EventListener*>(); _nodeListenersMap.insert(std::make_pair(node, listeners)); } listeners->push_back(listener); }
另一个种
_eventDispatcher->addEventListenerWithFixedPriority(listener, Priority);// 我这里发现了个问题 void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority) { CCASSERT(listener, "Invalid parameters."); CCASSERT(!listener->isRegistered(), "The listener has been registered."); CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority."); if (!listener->checkAvailable()) return; listener->setAssociatedNode(nullptr); listener->setFixedPriority(fixedPriority); listener->setRegistered(true); listener->setPaused(false); addEventListener(listener); }//我 TM的超级郁闷 ,设置非0吧,assert了,设置〇吧,没有node ,甭的更厉害 //无奈之下注释了第三行,OK了 唉只能说 被白fuck了一个小时,还能说了什么呢此不绑定target,所以需要手动释放
_eventDispatcher->removeEventListener(listener),此处没有根据nonde
第三
_eventDispatcher->addCustomEventListener("custom", [](EventCustom*)->void{ log("a event");}); EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback) { EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);//在这里创建listener addEventListenerWithFixedPriority(listener, 1); return listener; }测试了下,编译过了,但是点击没有反应,知道这个意思就好了 以后在看了
现在看看事件分发:
glview->pollEvents();
。。。。。。//物理事件传递
class GLFWEventHandler { public: static void onGLFWError(int errorID, const char* errorDesc) { if (_view) _view->onGLFWError(errorID, errorDesc); } static void onGLFWMouseCallBack(GLFWwindow* window, int button, int action, int modify) { if (_view) _view->onGLFWMouseCallBack(window, button, action, modify); } static void onGLFWMouseMoveCallBack(GLFWwindow* window, double x, double y) { if (_view) _view->onGLFWMouseMoveCallBack(window, x, y); } static void onGLFWMouseScrollCallback(GLFWwindow* window, double x, double y) { if (_view) _view->onGLFWMouseScrollCallback(window, x, y); } static void onGLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (_view) _view->onGLFWKeyCallback(window, key, scancode, action, mods); } static void onGLFWCharCallback(GLFWwindow* window, unsigned int character) { if (_view) _view->onGLFWCharCallback(window, character); } static void onGLFWWindowPosCallback(GLFWwindow* windows, int x, int y) { if (_view) _view->onGLFWWindowPosCallback(windows, x, y); } static void onGLFWframebuffersize(GLFWwindow* window, int w, int h) { if (_view) _view->onGLFWframebuffersize(window, w, h); } static void onGLFWWindowSizeFunCallback(GLFWwindow *window, int width, int height) { if (_view) _view->onGLFWWindowSizeFunCallback(window, width, height); } static void setGLView(GLView* view) { _view = view; } private: static GLView* _view; };我是用鼠标点的 响应了鼠标的那个函数调用,根据鼠标事件调用了
void GLViewProtocol::handleTouchesEnd(int num, intptr_t ids[], float xs[], float ys[]) { handleTouchesOfEndOrCancel(EventTouch::EventCode::ENDED, num, ids, xs, ys); }接下来才到我们之前注册的事件TouchEvent
void EventDispatcher::dispatchEvent(Event* event){
void EventDispatcher::dispatchTouchEvent(EventTouch* event){
这里面干的是
对事件排序,按优先级。
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID); auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
得到各个TouchMode的Listeners:
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID); auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);就是各种超找匹配找出是否有注册的Event:
if (oneByOneListeners) { auto mutableTouchesIter = mutableTouches.begin(); auto touchesIter = originalTouches.begin(); for (; touchesIter != originalTouches.end(); ++touchesIter) { bool isSwallowed = false; auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l); // Skip if the listener was removed. if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); bool isClaimed = false; std::vector<Touch*>::iterator removedIter; EventTouch::EventCode eventCode = event->getEventCode(); if (eventCode == EventTouch::EventCode::BEGAN) { if (listener->onTouchBegan) { isClaimed = listener->onTouchBegan(*touchesIter, event); if (isClaimed && listener->_isRegistered) { listener->_claimedTouches.push_back(*touchesIter); } } } else if (listener->_claimedTouches.size() > 0 && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end())) { isClaimed = true; switch (eventCode) { case EventTouch::EventCode::MOVED: if (listener->onTouchMoved) { listener->onTouchMoved(*touchesIter, event); } break; case EventTouch::EventCode::ENDED: if (listener->onTouchEnded) { listener->onTouchEnded(*touchesIter, event); } if (listener->_isRegistered) { listener->_claimedTouches.erase(removedIter); } break; case EventTouch::EventCode::CANCELLED: if (listener->onTouchCancelled) { listener->onTouchCancelled(*touchesIter, event); } if (listener->_isRegistered) { listener->_claimedTouches.erase(removedIter); } break; default: CCASSERT(false, "The eventcode is invalid."); break; } } // If the event was stopped, return directly. if (event->isStopped()) { updateListeners(event); return true; } CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); if (isClaimed && listener->_isRegistered && listener->_needSwallow) { if (isNeedsMutableSet) { mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); isSwallowed = true; } return true; } return false; }; // dispatchEventToListeners(oneByOneListeners, onTouchEvent);//主要在这里 这里用了lambda,执行循序要搞清楚了 if (event->isStopped()) { return; } if (!isSwallowed) ++mutableTouchesIter; } }
void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)这个函数告诉我们了 若匹配到了不想下分发了
然后进入那个lambda函数里执行注册过的touch系列函数了。执行完了还会在下一个循环删除这一事件
现在讲讲ccs 2.2.x ,一直在发布新版本,ccs现在完善了不少,我们就拿最新的来将好了,ccs 3.0x之前的版本大家都熟悉了,不熟悉,网上教程一大把,我这里略微补充下
类:CCTouchDispatcher
void CCTouchDispatcher::addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority) { CCTouchHandler *pHandler = CCStandardTouchHandler::handlerWithDelegate(pDelegate, nPriority); if (! m_bLocked) { forceAddHandler(pHandler, m_pStandardHandlers); } else { /* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return. * Refer issue #752(cocos2d-x) */ if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate)) { ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate); return; } m_pHandlersToAdd->addObject(pHandler); m_bToAdd = true; } }
我们经常重写void CCLayer::registerWithTouchDispatcher(),然后调用上面的注册函数,
void CCLayer::registerWithTouchDispatcher() { CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher(); // Using LuaBindings if (m_pScriptTouchHandlerEntry) { if (m_pScriptTouchHandlerEntry->isMultiTouches()) { pDispatcher->addStandardDelegate(this, 0); LUALOG("[LUA] Add multi-touches event handler: %d", m_pScriptTouchHandlerEntry->getHandler()); } else { pDispatcher->addTargetedDelegate(this, m_pScriptTouchHandlerEntry->getPriority(), m_pScriptTouchHandlerEntry->getSwallowsTouches()); LUALOG("[LUA] Add touch event handler: %d", m_pScriptTouchHandlerEntry->getHandler()); } } else { if( m_eTouchMode == kCCTouchesAllAtOnce ) { pDispatcher->addStandardDelegate(this, 0); } else { pDispatcher->addTargetedDelegate(this, m_nTouchPriority, true); } } }
从上面代码可以看出如果我们改变m_eTouchMode就可以修改注册模式,完成这个使命的函数CCLayer::setTouchMode( ... )
但是一定要注意调用的顺序,我们都知道在layer切换的时候先是init(),然后onEnter(),onEnterTransitionDidFinish()
在CCDirect类中有这样的一代码可以看出
m_pRunningScene->onEnter(); m_pRunningScene->onEnterTransitionDidFinish();
我们都知道registerWithTouchDispatch()是在CCLayer的onEnter里面调用,我们只需init()或者重写onEnter(){ setTouchMode(...) ,CCLayer::onEnter();},OK!
还有一点:
void CCTouchDispatcher::addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority) { CCTouchHandler *pHandler = CCStandardTouchHandler::handlerWithDelegate(pDelegate, nPriority); if (! m_bLocked) { forceAddHandler(pHandler, m_pStandardHandlers); } else { /* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return. * Refer issue #752(cocos2d-x) */ if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate)) { ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate); return; } m_pHandlersToAdd->addObject(pHandler); m_bToAdd = true; } }从参数类型看,
class CC_DLL CCTouchDelegate { public: CCTouchDelegate() {} virtual ~CCTouchDelegate() { } virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); return false;}; // optional virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} // optional virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} };我们已经知道他们想干什么事情了。
protected: CCArray* m_pTargetedHandlers; CCArray* m_pStandardHandlers; bool m_bLocked; ... CCArray* m_pHandlersToAdd; struct _ccCArray *m_pHandlersToRemove; ...
从CCTouchDispatcher的数据结构来看,主要是两个容器CCArray* m_pTargetedHandlers; CCArray* m_pStandardHandlers; m_bLocked
m_pHandlersToAdd;m_pHandlersToRemove主要是同步安全机制
注册好了 就是分发了,主要算法都在 CCTouchDispatcher::touches(cocos2d::CCSet * pTouches, cocos2d::CCEvent * pEvent, unsigned int uIndex) ,分类处理
switch (sHelper.m_type) { case CCTOUCHBEGAN: pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent); break; case CCTOUCHMOVED: pHandler->getDelegate()->ccTouchesMoved(pMutableTouches, pEvent); break; case CCTOUCHENDED: pHandler->getDelegate()->ccTouchesEnded(pMutableTouches, pEvent); break; case CCTOUCHCANCELLED: pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent); break; }
暂时就写到这了,若有错误,还请留言指出,谢谢
相关文章推荐
- cocos2dx 3.x 自学笔记 <一> :cocos2dx 3.X 中的回调
- cocos2dx 3.x 自学笔记 <三> cocos2dx 2.x 3.x 内存管理机制
- cocos2dx 自学笔记 <四> 瓦片地图 Tiled Map 学习
- linux学习笔记:<二>vi常用命令
- hadoop学习笔记<二>----hadoop集群环境的配置
- Axel源码阅读笔记<二>
- cocos2d-x触摸事件addTouchEventListener在2.x和3.x的区别
- <div+css页面布局课堂笔记>7---登录和注册界面的实现
- 【javascript笔记】声明函数的三种方式<二>
- cocos2dx lua学习笔记 <一> quick 3.5定义本身C++类是必然lua
- cocos2d JS 自学笔记 <一> 初步接触cocos2d JS
- Cocos2d-x学习笔记(九)-------->Touch事件处理机制
- Windows学习笔记13——键盘相关<二>
- 【Java编程】Java学习笔记<二>
- <二>---RIL层代码分析---RIL_startEventLoop()->eventLoop()->ril_event_loop()
- Windows学习笔记10——图形基础<二>
- 黑马程序员自学笔记 Java基础<五>---> 多线程
- PostgreSQL学习笔记6之函数和操作符<二>
- 【转】Android笔记:触摸事件的分析与总结----Touch事件分发方法dispatchTouchEvent()源码分析
- Django 学习笔记<二>