转自: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. 16,re模块的常用方法

    ret =re.findall('\d+', 'eva123egon4yuan567') print(ret)#返回满足条件的结果 ,放在一个列表里. ret2 = re.search('\d+',' ...

  2. ajax原生post请求

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. POJ 1286 Necklace of Beads ——Burnside

    [题目分析] 题目大意:一个环有n个点,共染三种颜色.问 在旋转和对称的情况下有多少种本质不同的方案数. Burnside直接做. [代码] #include <cstdio> #incl ...

  4. bzoj1065【Noi2008】奥运物流

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1065 给一棵基环树,每个点i的权值=ci+k*∑son[i],修改至多m个点的父亲使1号点权值 ...

  5. C 语言中可以调用命令行指令的 system()函数

    C语言有一个system函数(在<stdlib.h>头中,C++则为<cstdlib>头),可以用来调用终端命令.原型如下: int system(const char *cm ...

  6. 观光公交(codevs 1139)

    题目描述 Description 风景迷人的小城 Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号 ...

  7. 创建微服务项目后,在谷歌、Safari等浏览器下无法访问的具体原因

    使用SpringBoot开发了一个项目,端口随机给指定了一个,如6666. 可是奇葩的现象出现了,当在谷歌浏览器地址栏中输入localhost:6666访问的时候,提示无法访问. 检查良久,发现代码也 ...

  8. Day 5 Linux之用户、群组和权限

    Linux之用户.群组和权限 一.各文件及内容对应含义 1./etc/passwd文件 功能:存储所有用户的相关信息,该文件也被称为用户信息数据库(Database). 含义:如下图所示. 2./et ...

  9. spring--路由

    @RestController: Spring4之后新加入的注解,原来返回json需要@ResponseBody和@Controller配合. 即@RestController是@ResponseBo ...

  10. 最小费用最大流粗解 poj2516

    最小费用最大流,一般解法如下: 在流量基础上,每条边还有权费用,即单位流量下的所需费用.在最大流量下,求最小费用.解法:在最大流算法基础上,每次按可行流增广改为每次用spfa按最小费用(用单位费用)增 ...