cocos2dx触屏事件详解 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

cocos2dx触屏事件详解

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:49


版本: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,触摸事宜已经实现了,可以根据本身的须要,写一些逻辑了。


相关案例查看更多