转自: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. auto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png",
  4. CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
  5. void HelloWorld::menuCloseCallback(Object* pSender)
  6. {
  7. Director::getInstance()->end();
  8. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  9. exit(0);
  10. #endif
  11. }

当中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. virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
  8. virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
  9. virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
  10. 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. uiButton->addTouchEventListener(this,toucheventselector(HelloWorld::touchButton));
  5. //实现
  6. void HelloWorld::touchButton(Object* object,TouchEventType type)
  7. {
  8. LabelTTF* label;
  9. switch (type)
  10. {
  11. case TouchEventType::TOUCH_EVENT_BEGAN:
  12. label = static_cast<LabelTTF*>(getChildByTag(11));
  13. label->setString("按下button");
  14. break;
  15. case TouchEventType::TOUCH_EVENT_MOVED:
  16. label = static_cast<LabelTTF*>(getChildByTag(11));
  17. label->setString("按下button移动");
  18. break;
  19. case TouchEventType::TOUCH_EVENT_ENDED:
  20. label = static_cast<LabelTTF*>(getChildByTag(11));
  21. label->setString("放开button");
  22. break;
  23. case TouchEventType::TOUCH_EVENT_CANCELED:
  24. label = static_cast<LabelTTF*>(getChildByTag(11));
  25. label->setString("取消点击");
  26. break;
  27. default:
  28. break;
  29. }
  30. }

由于全部的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. myListener->setSwallowTouches(true);
  7. myListener->onTouchBegan = [=](Touch* touch,Event* event)
  8. {
  9. //some check
  10. if (pass)
  11. {
  12. return true;
  13. }
  14. return false;
  15. };
  16. myListener->onTouchMoved = [=](Touch* touch,Event* event)
  17. {
  18. //do something
  19. };
  20. myListener->onTouchEnded = [=](Touch* touch,Event* event)
  21. {
  22. //do something
  23. };
  24. dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite1);
  25. 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

关于cocos2d-x 3.0的点击交互处理的更多相关文章

  1. 高屋建瓴 cocos2d-x-3.0架构设计 Cocos2d (v.3.0) rendering pipeline roadmap(原文)

    Cocos2d (v.3.0) rendering pipeline roadmap Why (the vision) The way currently Cocos2d does rendering ...

  2. TextView + Spanned实现图文混排以及图片点击交互

    最近要实现图文混排的需求,webview过大,所以想到了用SpannableStringBuilder来实现. 不过参考了大量国内文章,大多数是教你如何实现图文混排,并没有提及图片点击交互的.有翻阅了 ...

  3. 微信小程序开发--模板(template)使用,数据加载,点击交互

    微信小程序视图层提供了 模板(template),可以在模板中定义代码片段,然后在不同的地方调用.结果在数据渲染那懵逼了.按照官网上对模板的说明和对数据的加载. 1.定义模板 使用name属性,作为模 ...

  4. WPF 3D Cube及点击交互

    在WPF中构建一个简单的立方体比较容易实现,可参考资料也比较众多.比较麻烦的是处理点击交互. 我在WPF中用两种方式实现了3DCube,效果图如下: 方式一: 最常见的3D内容构建模式,结构如下图. ...

  5. IOS 小组件(7):小组件点击交互

    引言   前面我们似乎掌握了实现一个小组件所需要的一切技能,默认情况下桌面点击小组件,也正常跳转到了App中.接下来我们一起来看看,小组件是怎么做到点击跳转到App的. 点击交互方式 点击Widget ...

  6. Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(八)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 回到Xcode中,新建一个EndLayer类,继承于CCNode ...

  7. Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(六)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在Xcode中打开MainScene.h文件,在接口中添加2个方 ...

  8. Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(四)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 现在打开MainScene.m文件,首先设置实例变量: @imp ...

  9. Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(一)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 首先说一下为什么要转换,这是为了后面的A*寻路算法做准备.由于在 ...

随机推荐

  1. 第五部分 linux系统管理员 开机流程 模组管理 与loader

    第五部分   linux系统管理员  开机流程  模组管理  与loader   开机流程分析 cmos保存电脑硬件的参数 bios 基本的输入输出系统  读取硬件的软件 MBR  master bo ...

  2. [uiautomator篇]recent

    def Recent(self): d = Device('9410519008004c22098b') displayWidth = int(d.info.get("displayWidt ...

  3. linux删除N天前的文件

    列出一天之前的文件的属性用下面的命令:find . ! -mtime -1 -print |xargs ls -lfind . -mtime +1 要删除文件的话用下面的命令:find . ! -mt ...

  4. hdu6071[最短路+解不等式] 2017多校4

    求出所有,从2走到x所需的花费在对 t = 2*min(d1,2, d2,3) 模运算下,  所有剩余系的最短路即可(把一个点拆成 t 个点, 每个点代表一种剩余系), 知道了所有剩余系就可以凑出答案 ...

  5. iOS学习笔记14-网络(三)WebView

    一.WebView WebView就是一个内嵌浏览器控件,在iOS中主要有两种WebView:UIWebView和WKWebView,UIWebView是iOS2之后开始使用,WKWebView是在i ...

  6. 洛谷P2351 [SDOi2012]吊灯 【数学】

    题目 Alice家里有一盏很大的吊灯.所谓吊灯,就是由很多个灯泡组成.只有一个灯泡是挂在天花板上的,剩下的灯泡都是挂在其他的灯泡上的.也就是说,整个吊灯实际上类似于[b]一棵树[/b].其中编号为 1 ...

  7. [luoguP3960] 列队(动态开点线段树)

    传送门 有splay的做法,有树状数组的做法... 最好理解的还是线段树的做法. 一开始我是这样想的,如果移动某一个人,只有当前行和最后一列会受到影响,感觉就像是个线段树,树状数组什么的. 然而接下来 ...

  8. 关于java读取文件IO流学习总结(二)

    今天网上随意逛了逛,某处看到关于文件的操作,描述的不错,加深了对于文件操作的理解,在此分享给大家.希望能够有所收获. java读取txt文件内容: 可以作如下理解: 1. 首先获得一个文件句柄.Fil ...

  9. 阐述struts2的执行流程。

    Struts 2框架本身大致可以分为3个部分:核心控制器FilterDispatcher.业务控制器Action和用户实现的企业业务逻辑组件. 核心控制器FilterDispatcher是Struts ...

  10. AtCoder Regular Contest 074F - Lotus Leaves

    $n \leq 300,m \leq 300$,$n*m$的格子里有起点有终点有空地有障碍,人会从起点选一个同行或同列空地跳过去,然后一直这样跳到终点.求至少删掉多少格子使得人跳不到终点. 首先S和T ...