Cocos2d-x 触摸响应事件CCTouchDelegate

      刚开始接触Cocos2d-x,一边看书,一边看官方Demo的代码,在SpriteTest中,有个函数ccTouchesEnded(...)功能类似VC里面LeftButtonUp(...),刚开始以为这是自定义的函数实现,后来打开demo在屏幕上操作,发现这是个响应事件,然后去找基类,看有没有这个函数,然后就发现了这么个玩意。class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate{...};

void Sprite1::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
    CCSetIterator it;
    CCTouch* touch;

    for( it = touches->begin(); it != touches->end(); it++) 
    {
        touch = (CCTouch*)(*it);

        if(!touch)
            break;

        CCPoint location = touch->getLocation();
    
        addNewSpriteWithCoords( location );
    }
}


后面发现这个跟VC里面鼠标响应事件一个原理,就查询资料,继续加强对这个触摸类的理解和使用。

 

1.要想使得该布景层有这种触摸响应,要进行游戏交互,就得先在构造函数中 setTouchEnabled( true );

2.了解一下相关的几个类

    CCTouch:它封装了触摸点,可以通过locationInView函数返回一个CCPoint。
CCTouchDelegate:它是触摸事件委托,就是系统捕捉到触摸事件后交由它或者它的子类处理,所以我们在处理触屏事件时,必须得继承它。它封装了下面这些处理触屏事件的函数:

virtualboolcc<span style="color:#ff0000;">Touch</span>Began(CCTouch
 *pTouch, CCEvent *pEvent); 
virtualvoidccTouchMoved(CCTouch
 *pTouch, CCEvent *pEvent); 
virtualvoidccTouchEnded(CCTouch
 *pTouch, CCEvent *pEvent); 
virtualvoidccTouchCancelled(CCTouch
 *pTouch, CCEvent *pEvent);
virtualvoidcc<span style="color:#ff0000;">Touches</span>Began(CCSet
 *pTouches, CCEvent *pEvent); 
virtualvoidccTouchesMoved(CCSet
 *pTouches, CCEvent *pEvent); 
virtualvoidccTouchesEnded(CCSet
 *pTouches, CCEvent *pEvent); 
virtualvoidccTouchesCancelled(CCSet
 *pTouches, CCEvent *pEvent);


   ccTouchesCancelled和ccTouchCancelled函数很少用,在接到系统中断通知,需要取消触摸事件的时候才会调用此方法。如:应用长时间无响应、当前view从window上移除、触摸的时候来电话了等。

CCTargetedTouchDelegate和CCStandardTouchDelegate是CCTouchDelegate的子类,类结构图如下:

 

CCStandardTouchDelegate用于处理多点触摸;CCTargetedTouchDelegate用于处理单点触摸。

CCTouchDispatcher:实现触摸事件分发,它封装了下面这两个函数,可以把CCStandardTouchDelegate和CCTargetedTouchDelegate添加到分发列表中:

void addStandardDelegate(CCTouchDelegate *pDelegate, intnPriority);

void addTargetedDelegate(CCTouchDelegate *pDelegate, intnPriority,boolbSwallowsTouches);

CCTouchHandler:封装了CCTouchDelegate和其对应的优先级,优先级越高,分发的时候越容易获得事件处理权,CCStandardTouchHandler和CCTargetedTouchHandler是它的子类。

 

3.处理触屏事件时操作和执行的流程

 

用户自定义类继承CCTouchDelegate,重写触屏事件处理函数和registerWithTouchDispatcher函数,在init或者onEnter函数中调用registerWithTouchDispatcher函数,如:

(1.)定义类

class CCGameLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate
{
public:
    CCGameLayer();
    virtual ~CCGameLayer();
    bool init();

 
    CC_DEPRECATED_ATTRIBUTE static CCGameLayer *node(void);
    static CCGameLayer *create(void);

    virtual void onEnter();
    virtual void onExit();
    virtual void onEnterTransitionDidFinish();
    
    // default implements are used to call script callback if exist
    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

    // default implements are used to call script callback if exist
    virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
    virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
    virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
    virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
    
    virtual void didAccelerate(CCAcceleration* pAccelerationValue);
    virtual void registerWithTouchDispatcher(void);
};

(2.)registerWithTouchDispatcher函数实现

void CCGameLayer::registerWithTouchDispatcher() 
{ 
    cocos2d::CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this,
 0, true); 
}

(3.)在init或者OnEnter中调用

void CCGameLayer::onEnter()
{
    CCDirector* pDirector = CCDirector::sharedDirector();
    if (m_bIsTouchEnabled)
    {
        <span style="color:#ff0000;">this->registerWithTouchDispatcher();
</span>    }

    CCNode::onEnter();

    if (m_bIsAccelerometerEnabled)
    {
        pDirector->getAccelerometer()->setDelegate(this);
    }

    if (m_bIsKeypadEnabled)
    {
        pDirector->getKeypadDispatcher()->addDelegate(this);
    }
}

(4.)追踪解析

appdelegate.cpp

 CCDirector *pDirector = CCDirector::sharedDirector();
 pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

 CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();

跟进getFrameSize()函数,发现了:

LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

这下就明白了,其实最终接受处理跟VC一样,只不过cocos2d-x封装了以下,以下是WindowProc(...)的实现代码:

LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    BOOL bProcessed = FALSE;

    switch (message)
    {
    case <span style="color:#ff0000;">WM_LBUTTONDOWN</span>:
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */

        if (m_pDelegate && MK_LBUTTON == wParam)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            CCPoint tmp = ccp(pt.x, m_obScreenSize.height - pt.y);
            if (m_obViewPortRect.equals(CCRectZero) || m_obViewPortRect.containsPoint(tmp))
            {
                m_bCaptured = true;
                SetCapture(m_hWnd);
                int id = 0;
                handleTouchesBegin(1, &id, &pt.x, &pt.y);
            }
        }
        break;

    case WM_MOUSEMOVE:
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
        if (MK_LBUTTON == wParam && m_bCaptured)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            int id = 0;
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            handleTouchesMove(1, &id, &pt.x, &pt.y);
        }
        break;

    case WM_LBUTTONUP:
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
        if (m_bCaptured)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            int id = 0;
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            handleTouchesEnd(1, &id, &pt.x, &pt.y);

            ReleaseCapture();
            m_bCaptured = false;
        }
        break;
#if(_MSC_VER >= 1600)
    case <span style="color:#ff0000;">WM_TOUCH</span>:
  {
            BOOL bHandled = FALSE;
            UINT cInputs = LOWORD(wParam);
            PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
            if (pInputs)
            {
                if (s_pfGetTouchInputInfoFunction((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT)))
                {
                    for (UINT i=0; i < cInputs; i++)
                    {
                        TOUCHINPUT ti = pInputs[i];
                        POINT input;
                        input.x = TOUCH_COORD_TO_PIXEL(ti.x);
                        input.y = TOUCH_COORD_TO_PIXEL(ti.y);
                        ScreenToClient(m_hWnd, &input);
                        CCPoint pt(input.x, input.y);
                        CCPoint tmp = ccp(pt.x, m_obScreenSize.height - pt.y);
                        if (m_obViewPortRect.equals(CCRectZero) || m_obViewPortRect.containsPoint(tmp))
                        {
                            pt.x /= m_fFrameZoomFactor;
                            pt.y /= m_fFrameZoomFactor;

                            if (ti.dwFlags & TOUCHEVENTF_DOWN)
                                handleTouchesBegin(1, reinterpret_cast<int*>(&ti.dwID), &pt.x, &pt.y);
                            else if (ti.dwFlags & TOUCHEVENTF_MOVE)
                                handleTouchesMove(1, reinterpret_cast<int*>(&ti.dwID), &pt.x, &pt.y);
                            else if (ti.dwFlags & TOUCHEVENTF_UP)
                                handleTouchesEnd(1, reinterpret_cast<int*>(&ti.dwID), &pt.x, &pt.y);
                         }
                     }
                     bHandled = TRUE;
                 }
                 delete [] pInputs;
             }
             if (bHandled)
             {
                 s_pfCloseTouchInputHandleFunction((HTOUCHINPUT)lParam);
             }
  }
      break;
#endif /* #if(_MSC_VER >= 1600) */
    case WM_SIZE:
        switch (wParam)
        {
        case SIZE_RESTORED:
            CCApplication::sharedApplication()->applicationWillEnterForeground();
            break;
        case SIZE_MINIMIZED:
            CCApplication::sharedApplication()->applicationDidEnterBackground();
            break;
        }
        break;
    case WM_KEYDOWN:
        if (wParam == VK_F1 || wParam == VK_F2)
        {
            CCDirector* pDirector = CCDirector::sharedDirector();
            if (GetKeyState(VK_LSHIFT) < 0 ||  GetKeyState(VK_RSHIFT) < 0 || GetKeyState(VK_SHIFT) < 0)
                pDirector->getKeypadDispatcher()->dispatchKeypadMSG(wParam == VK_F1 ? kTypeBackClicked : kTypeMenuClicked);
        }
        if ( m_lpfnAccelerometerKeyHook!=NULL )
        {
            (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
        }
        break;
    case WM_KEYUP:
        if ( m_lpfnAccelerometerKeyHook!=NULL )
        {
            (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
        }
        break;
    case WM_CHAR:
        {
            if (wParam < 0x20)
            {
                if (VK_BACK == wParam)
                {
                    CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
                }
                else if (VK_RETURN == wParam)
                {
                    CCIMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1);
                }
                else if (VK_TAB == wParam)
                {
                    // tab input
                }
                else if (VK_ESCAPE == wParam)
                {
                    // ESC input
                    //CCDirector::sharedDirector()->end();
                }
            }
            else if (wParam < 128)
            {
                // ascii char
                CCIMEDispatcher::sharedDispatcher()->dispatchInsertText((const char *)&wParam, 1);
            }
            else
            {
                char szUtf8[8] = {0};
                int nLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)&wParam, 1, szUtf8, sizeof(szUtf8), NULL, NULL);
                CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(szUtf8, nLen);
            }
            if ( m_lpfnAccelerometerKeyHook!=NULL )
            {
                (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
            }
        }
        break;
    case <span style="color:#ff0000;">WM_PAINT</span>:
        PAINTSTRUCT ps;
        BeginPaint(m_hWnd, &ps);
        EndPaint(m_hWnd, &ps);
        break;

    case <span style="color:#ff0000;">WM_CLOSE</span>:
        CCDirector::sharedDirector()->end();
        break;

    case <span style="color:#ff0000;">WM_DESTROY</span>:
        destroyGL();
        PostQuitMessage(0);
        break;

    default:
        if (m_wndproc)
        {
            
            m_wndproc(message, wParam, lParam, &bProcessed);
            if (bProcessed) break;
        }
        return DefWindowProc(m_hWnd, message, wParam, lParam);
    }

    if (m_wndproc && !bProcessed)
    {
        m_wndproc(message, wParam, lParam, &bProcessed);
    }
    return 0;
}


 

(5.)所以使用基本和VC中鼠标响应事件一样。

第一步.

class Sprite1 : public SpriteTestDemo
{
public:
    Sprite1();
    virtual std::string title();

    void addNewSpriteWithCoords(CCPoint p);
    <span style="color:#ff0000;">void ccTouchesEnded(CCSet* touches, CCEvent* event);
</span>};

第二步.【注意】

Sprite1::Sprite1()
{
    <span style="color:#ff0000;">setTouchEnabled( true );
</span>    
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    addNewSpriteWithCoords( ccp(s.width/2, s.height/2) );
    
}

第三步.

void Sprite1::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
    CCSetIterator it;
    CCTouch* touch;

    for( it = touches->begin(); it != touches->end(); it++) 
    {
        touch = (CCTouch*)(*it);

        if(!touch)
            break;

        CCPoint location = touch->getLocation();
    
        addNewSpriteWithCoords( location );
    }
}


【注意】:第二步中的setTouchEnabled( true );如果要放在init()里面的话,尽量放到结尾,放在开头不会响应事件。

【吞噬触屏问题解决办法】:http://blog.csdn.net/ganpengjin1/article/details/17396115 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值