• 关于cocos2d-x 3.0的点击交互处理


    转自:http://blog.csdn.net/fansongy/article/details/12716671

    1、概述


        游戏也好,程序也好,仅仅有能与用户交互才有意义。手机上的交互大致能够分为两部分:点击和输入。当中点击更为重要,差点儿是游戏中所有的交互。在Cocos2d-x 3.0中。更改了dispatch机制。同一时候增加了两种新的交互形式:listener 和touchEvent回调。

    加上先前版本号中的点击函数回调,与重写layer层的touch消息响应,构成了一个相对完整的交互模式。

    先上一张Demo的图:




    2、四种点击


    1、函数回调

    函数回调是最简单的响应形式。一直以来被用于MenuItem中的点击处理。

    在新版本号中,此处发生了些小改变。我们能够看到在生成的程序中相关代码是这种:


    1. // a selector callback  
    2. void menuCloseCallback(Object* pSender);  
    3.   
    4. auto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png",  
    5.                         CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));  
    6.   
    7. void HelloWorld::menuCloseCallback(Object* pSender)  
    8. {  
    9.     Director::getInstance()->end();  
    10.   
    11. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
    12.     exit(0);  
    13. #endif  
    14. }  

        当中CC_CALLBACK_1宏是将函数与对象绑定在一起,1表示这个函数有一个參数。当点击这个button时,会调用这个回调函数。

        除了基于c++11的这个形式的改变,用法与先前同样。


    此种方式已经被舍弃,能够使用第四种方法做替代。

       2、Layer的touch消息响应

         尽管重写了底层的dispatch,但对这层的使用影响并不大。

    我们相同须要重写:

    1. //单点响应  
    2. virtual bool onTouchBegan(Touch* touch, Event  *event) override;  
    3. virtual void onTouchMoved(Touch* touch, Event  *event) override;  
    4. virtual void onTouchEnded(Touch* touch, Event  *event) override;  
    5. virtual void onTouchCancelled(Touch *touch, Event *event) override;  
    6.   
    7. //多点响应  
    8. virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
    9. virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
    10. virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
    11. virtual void onTouchesCancelled(const std::vector<Touch*>& touches, Event *unused_event);


        重写这些函数来对layer的点击做处理。当然。我们须要:

    1. setTouchEnabled(true)。  

     

       此外有个小修改。对于单点触控响应,能够调用:

      

    1. //设置为单点响应  
    2. setTouchMode(Touch::DispatchMode::ONE_BY_ONE);  
    3. //设置为多点响应(默认)  
    4. setTouchMode(Touch::DispatchMode::ALL_AT_ONCE);  

        进行设置,而不须要再用设置Delegate的方式来做了。


        3、TouchEvent响应

        这是新增加的响应方式。它主要是使用在UIWidget上的。能够将其看做是函数回调的一个扩展。为很多其它的响应处理提供可能。用法大致是:

    1. //声明  
    2. void touchButton(Object* object,TouchEventType type);  
    3.   
    4. //挂接到控件上  
    5. uiButton->addTouchEventListener(this,toucheventselector(HelloWorld::touchButton));  
    6.   
    7. //实现  
    8. void HelloWorld::touchButton(Object* object,TouchEventType type)  
    9. {  
    10.     LabelTTF* label;  
    11.     switch (type)  
    12.     {  
    13.     case TouchEventType::TOUCH_EVENT_BEGAN:  
    14.         label = static_cast<LabelTTF*>(getChildByTag(11));  
    15.         label->setString("按下button");  
    16.         break;  
    17.     case TouchEventType::TOUCH_EVENT_MOVED:  
    18.         label = static_cast<LabelTTF*>(getChildByTag(11));  
    19.         label->setString("按下button移动");  
    20.         break;  
    21.     case TouchEventType::TOUCH_EVENT_ENDED:  
    22.         label = static_cast<LabelTTF*>(getChildByTag(11));  
    23.         label->setString("放开button");  
    24.         break;  
    25.     case TouchEventType::TOUCH_EVENT_CANCELED:  
    26.         label = static_cast<LabelTTF*>(getChildByTag(11));  
    27.         label->setString("取消点击");  
    28.         break;  
    29.     default:  
    30.         break;  
    31.     }  
    32. }  

        由于全部的UIWidget都要加入到UILayer上。而UILayer通常作为UI的Widget都会在最上层,所以能够“基本上”觉得这样的使用方式会优先于其它方式处理点击消息。由于UILayer也会有层级的改变,比方它和MenuItem之间的关系。所以说“基本上”。


    4、Listener消息响应方式

        这样的实现也是新增加的。它更像是点击的一个层次过滤器。点击时,在listener队里中进行过滤。每个listener检查自己保存的touch消息响应是否会被触发。

    一层一层过滤,最后在到Layer的touch消息响应。

        我认为它的设计的初衷是为随意sprite提供一套自己制定的点击响应。但这种实现仍然要写非常多条件推断。没有可以控件化。可能我的理解有些偏差,欢迎讨论。

        它被设计成一个全局点击响应控制。详细的使用方法大致是这样:


    1. //auto dispatcher = EventDispatcher::getInstance();  
    2. //  auto myListener = EventListenerTouch::create(Touch::DispatchMode::ONE_BY_ONE);  
    3. auto dispatcher = Director::getInstance()->getEventDispatcher();  
    4. auto myListener = EventListenerTouchOneByOne::create();  
    5.   
    6. //假设不增加此句消息依然会向下传递  
    7. myListener->setSwallowTouches(true);  
    8.   
    9. myListener->onTouchBegan = [=](Touch* touch,Event* event)  
    10. {  
    11.     //some check  
    12.     if (pass)  
    13.     {  
    14.         return true;  
    15.     }  
    16.     return false;  
    17. };  
    18.   
    19. myListener->onTouchMoved = [=](Touch* touch,Event* event)  
    20. {  
    21.     //do something  
    22. };  
    23.   
    24. myListener->onTouchEnded = [=](Touch* touch,Event* event)  
    25. {  
    26.     //do something  
    27. };  
    28.   
    29. dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite1);  
    30. dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite2);  
      在这里相同会用到CC_CALLBACK_x函数。

        其原理是在dispatcher中检查listener列表,比如myListener或加进来的其它listener。然后每一个listener检查自己中的Item看是否能达到检查条件,比如:mySprite1,mySprite2。

    然后运行对应的操作。但这种话,当控件非常多的时候,每一次事件都进行这种双链表的检查操作不知会不会影响些性能?


    3、实例

        光说不练假把式,于是就动手写了一个上面的Demo:

        点击背景区域能够移动整个场景。点击蓝色小方块能够半透明移动它,点击蓝色button能够更改文字。显示状态。点击右下角button退出程序。

        项目配置可參照: 

    Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并载入CocoStudio导出文件

    4、总结

        依据不同的交互须要。选择不同的实现方式,会更有利于我们的维护和扩展,对应样例能够在以下下载。


        Demo下载:http://download.csdn.net/detail/fansongy/6399291 不要资源分,认为好劳烦点下 “顶” ~

       Demo For Beta2 下载:http://download.csdn.net/detail/fansongy/6892047


  • 相关阅读:
    gns3 接口说明 转
    Java二进制指令代码解析
    java大神RednaxelaFX
    深入理解Java虚拟机
    java环境变量设置
    openjdk
    JAVA call graphs JAVA调用图
    Java虚拟机原理图解
    JAVA --BYTECODE
    利用hsdis和JITWatch查看分析HotSpot JIT compiler生成的汇编代码
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7199689.html
Copyright © 2020-2023  润新知