首页 > 其他 > 详细

cocos2dx触屏事件详解

时间:2015-01-04 15:19:32      阅读:258      评论:0      收藏:0      [点我收藏+]

版本:2.x

平台iso

先看mian.m文件

//创建一个iso应用

int retVal = UIApplicationMain(argc, argv, nil, @"AppController");

iOS系统会调用AppController 的 didFinishLaunchingWithOptions函数,里面做了一些创建界面的东西

该函数内部有如下代码;

cocos2d::CCApplication::sharedApplication()->run();

注:*.mm文件为object C与C++混编文件命名

AppController.mm文件上面对 AppDelegate创建一个对象,AppDelegate继承于CCApplication, cocos2d::CCApplication::sharedApplication()取得的就是该对象

static AppDelegate s_sharedApplication;

进入 CCApplication::run()函数

int CCApplication::run()

{

    if (applicationDidFinishLaunching()) 

    {

        [[CCDirectorCaller sharedDirectorCaller] startMainLoop];

    }

    return 0;

}

进入AppDelegate::applicationDidFinishLaunching 函数,省略部分代码

bool AppDelegate::applicationDidFinishLaunching()

{

    // initialize director

    CCDirector *pDirector = CCDirector::sharedDirector();

    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

进入setOpenGLView函数,

void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView)

{

        m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);//设置触摸代理 只是对CCEGLViewProtocol中 EGLTouchDelegate* m_pDelegate; 变量初始化

        m_pTouchDispatcher->setDispatchEvents(true);//设置接受派发事件

    }

}

CCDirector::init() 已经对cocos2dx引擎用到的变量进行了一些初始化

 m_pTouchDispatcher = new CCTouchDispatcher();

  m_pTouchDispatcher->init();


我们先回头看一下cocosdx是怎么从ios系统中取得触摸事件:

为了便于针对openGL ES的编程,苹果公司提供了派生于类UIView的类EAGLView来实现OpenGL的输出支持。

这样EAGLView.mm中得

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

就会接受到ios系统发送过来的触屏事件

里面分别调用了

cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesBegin(i, ids, xs, ys);

cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesMove(i, ids, xs, ys);

cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesEnd(i, ids, xs, ys);

cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesCancel(i, ids, xs, ys);

进入CCEGLViewProtocol 的这几个函数,里面分别调用了

m_pDelegate->touchesBegan(&set, NULL);

m_pDelegate->touchesMoved(&set, NULL);

m_pDelegate->touchesEnded(&set, NULL);

m_pDelegate->touchesCancelled(&set, NULL);

上面已经对m_pDelegate 进行了赋值 

m_pTouchDispatcher = new CCTouchDispatcher();

 m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);


这样CCTouchDispatcher 就能接受到ios系统发送过来的触屏事件了。

看一下 这几个函数 m_bDispatchEvents 上面已经对其设置为 true 然后这几个函数都会调用该类的touches函数

void CCTouchDispatcher::touchesBegan(CCSet *touches, CCEvent *pEvent)

{

    if (m_bDispatchEvents)

    {

        this->touches(touches, pEvent, CCTOUCHBEGAN);

    }

}


void CCTouchDispatcher::touchesMoved(CCSet *touches, CCEvent *pEvent)

{

    if (m_bDispatchEvents)

    {

        this->touches(touches, pEvent, CCTOUCHMOVED);

    }

}


void CCTouchDispatcher::touchesEnded(CCSet *touches, CCEvent *pEvent)

{

    if (m_bDispatchEvents)

    {

        this->touches(touches, pEvent, CCTOUCHENDED);

    }

}


void CCTouchDispatcher::touchesCancelled(CCSet *touches, CCEvent *pEvent)

{

    if (m_bDispatchEvents)

    {

        this->touches(touches, pEvent, CCTOUCHCANCELLED);

    }

}

我们来看下touches函数

void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)

{

    CCAssert(uIndex >= 0 && uIndex < 4, "");


    CCSet *pMutableTouches;

    m_bLocked = true;


    // optimization to prevent a mutable copy when it is not necessary

     unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count();

     unsigned int uStandardHandlersCount = m_pStandardHandlers->count();

    bool bNeedsMutableSet = (uTargetedHandlersCount && uStandardHandlersCount);


    pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches);


    struct ccTouchHandlerHelperData sHelper = m_sHandlerHelperData[uIndex];

    //

    // process the target handlers 1st

    //单点触摸

    if (uTargetedHandlersCount > 0)

    {

        CCTouch *pTouch;

        CCSetIterator setIter;

        for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter)

        {

            pTouch = (CCTouch *)(*setIter);


            CCTargetedTouchHandler *pHandler = NULL;

            CCObject* pObj = NULL;

  //从CCTargetedTouchHandler的数组中取出单个CCTargetedTouchHandler对象

            CCARRAY_FOREACH(m_pTargetedHandlers, pObj)

            {

                pHandler = (CCTargetedTouchHandler *)(pObj);


                if (! pHandler)

                {

                   break;

                }


                bool bClaimed = false;

                if (uIndex == CCTOUCHBEGAN)

                {

//这里调用CCTargetedTouchHandler对象的ccTouchBegin方法,我们知道cocos2dx中layer为cocos2dx中接受触屏事件的最小单位

                    bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);

//如果ccTouchBegin 方法返回true 会把这个CCTargetedTouchHandler对象 加入到 处理 move end canceled 的数组中

//意思就是 如果ccTouchBegin 方法返回true  该CCTargetedTouchHandler对象  才会继续接受到 move end canceled 这三个事件

                    if (bClaimed)

                    {

                        pHandler->getClaimedTouches()->addObject(pTouch);

                    }

                } else

                if (pHandler->getClaimedTouches()->containsObject(pTouch))

                {

                    // moved ended canceled

                    bClaimed = true;


                    switch (sHelper.m_type)

                    {

                    case CCTOUCHMOVED:

                        pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent);

                        break;

                    case CCTOUCHENDED:

                        pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);

                        pHandler->getClaimedTouches()->removeObject(pTouch);

                        break;

                    case CCTOUCHCANCELLED:

                        pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);

                        pHandler->getClaimedTouches()->removeObject(pTouch);

                        break;

                    }

                }

//如果有CCTargetedTouchHandler对象  接受到这个触摸事件了 如果设置为吞并事件 不向下传递了 这里就会把 触屏事件删除

                if (bClaimed && pHandler->isSwallowsTouches())

                {

                    if (bNeedsMutableSet)

                    {

                        pMutableTouches->removeObject(pTouch);

                    }


                    break;

                }

            }

        }

    }


    //

    // process standard handlers 2nd

    //这里是多点触摸

    if (uStandardHandlersCount > 0 && pMutableTouches->count() > 0)

    {

        CCStandardTouchHandler *pHandler = NULL;

        CCObject* pObj = NULL;

        CCARRAY_FOREACH(m_pStandardHandlers, pObj)

        {

            pHandler = (CCStandardTouchHandler*)(pObj);


            if (! pHandler)

            {

                break;

            }


            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;

            }

        }

    }

   //多点触摸是否释放

    if (bNeedsMutableSet)

    {

        pMutableTouches->release();

    }


    //

    // Optimization. To prevent a [handlers copy] which is expensive

    // the add/removes/quit is done after the iterations

    //这以下没研究到底是干什么的 感兴趣可以自己看下

    m_bLocked = false;

    if (m_bToRemove)

    {

        m_bToRemove = false;

        for (unsigned int i = 0; i < m_pHandlersToRemove->num; ++i)

        {

            forceRemoveDelegate((CCTouchDelegate*)m_pHandlersToRemove->arr[i]);

        }

        ccCArrayRemoveAllValues(m_pHandlersToRemove);

    }


    if (m_bToAdd)

    {

        m_bToAdd = false;

        CCTouchHandler* pHandler = NULL;

        CCObject* pObj = NULL;

        CCARRAY_FOREACH(m_pHandlersToAdd, pObj)

         {

             pHandler = (CCTouchHandler*)pObj;

            if (! pHandler)

            {

                break;

            }


            if (dynamic_cast<CCTargetedTouchHandler*>(pHandler) != NULL)

            {                

                forceAddHandler(pHandler, m_pTargetedHandlers);

            }

            else

            {

                forceAddHandler(pHandler, m_pStandardHandlers);

            }

         }

 

         m_pHandlersToAdd->removeAllObjects();    

    }


    if (m_bToQuit)

    {

        m_bToQuit = false;

        forceRemoveAllDelegates();

    }

}

现在我们已经了解了 触屏事件的调用流程,我们来看一下 上面的 m_pTargetedHandlers 变量是怎么添加对象的

先来看一下 CCLayer函数中得 setTouchEnabled函数 有如下代码

void CCLayer::setTouchEnabled(bool enabled)

if (enabled)

{//ture   注册

   this->registerWithTouchDispatcher();

}

else

{

   // 传进来的是false删除

    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);

}        

看下这个函数

void CCLayer::registerWithTouchDispatcher()

{

    CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();


    // Using LuaBindings  用于lua的

    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);//把当前layer或layer的子类加入 //触摸优先级 //接受到触摸事件是否吞并 不向该优先级以下 传递

        }

    }

}

看下addTargetedDelegate函数 m_pTargetedHandlers 就是我们上文中 touchs函数中CCTouchHandler * 的数组

void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)

{    

    CCTouchHandler *pHandler = CCTargetedTouchHandler::handlerWithDelegate(pDelegate, nPriority, bSwallowsTouches);

    if (! m_bLocked)

    {

        forceAddHandler(pHandler, m_pTargetedHandlers);

    }

然后再看下forceAddHandler函数,该函数添加之前需要遍历一遍数组,把当前加入的CCTouchHandler* 按优先级加入到已有的CCTouchHandler* 数组中

从下面的代码中 我们知道 数组的排序是按 优先级 从小到大排列的   也就是说  设置的优先级 越小,就会最优先接受到触屏事件

void CCTouchDispatcher::forceAddHandler(CCTouchHandler *pHandler, CCArray *pArray)

{

    unsigned int u = 0;

    CCObject* pObj = NULL;

   //遍历数组

    CCARRAY_FOREACH(pArray, pObj)

     {

         CCTouchHandler *h = (CCTouchHandler *)pObj;

         if (h)

         {//比较优先级 设置插入的位置

             if (h->getPriority() < pHandler->getPriority())

             {

                 ++u;

             }

             if (h->getDelegate() == pHandler->getDelegate())

             {

                 CCAssert(0, "");

                 return;

             }

         }

     }

   //向该数组中 加入该CCTouchHandler *pHandler

    pArray->insertObject(pHandler, u);

}


现在触摸事件的流程,我们已经知道了,现在来实现我们自己的触摸函数

首先我们要继承CCLayer函数,重写接受触摸事件的个函数

class UILayer : public CCLayer

    {

    public:

        UILayer();

        ~UILayer();

    public:

        virtual bool init();

        virtual void onEnter();

        virtual void onExit();

        virtual void registerWithTouchDispatcher();

        virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);

        virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);

        virtual void ccTouchCancelled(CCTouch* touch, CCEvent* event);

        virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);

        CREATE_FUNC(UILayer);

    };

    UILayer::UILayer()

    {

    }

    

    UILayer::~UILayer()

    {

    }

    

    bool UILayer::init()

    {

        if ( !CCLayer::init() )

        {

            return false;

        }

        return true;

    }

    

    void UILayer::onEnter()

    {

        CCLayer::onEnter();

        setTouchEnabled(true);

    }

    

    void UILayer::onExit()

    {

        CCLayer::onExit();

    }


    void UILayer::registerWithTouchDispatcher()

    {

        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, ROR::TOUCH_UI_PRIORITY, true);//默认吞噬触摸事件

    }

    

    bool UILayer::ccTouchBegan(CCTouch* touch, CCEvent* event)

    {

CCLOG("ccTouchBegan");

        return true;

    }

    

    void UILayer::ccTouchEnded(CCTouch* touch, CCEvent* event)

    {

CCLOG("ccTouchEnded");

    }

    

    void UILayer::ccTouchCancelled(CCTouch* touch, CCEvent* event)

    {

CCLOG("ccTouchCancelled");

    }

    

    void UILayer::ccTouchMoved(CCTouch* touch, CCEvent* event)

    {

CCLOG("ccTouchMoved");   

    }

 

OK,触摸事件已经实现了,可以根据自己的需要,写一些逻辑了。








cocos2dx触屏事件详解

原文:http://blog.csdn.net/tutuboke/article/details/42388123

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!