cocos2dx 开发成长之路 004

1、概述

游戏也好,程序也好,只有能与用户交互才有意义。手机上的交互大致可以分为两部分:点击和输入。其中点击更为重要,几乎是游戏中全部的交互。在Cocos2d-x 3.0中,更改了dispatch机制。同时加入了两种新的交互形式:listener 和touchEvent回调。加上先前版本中的点击函数回调,与重写layer层的touch消息响应,构成了一个相对完整的交互模式。先上一张Demo的图:

2、四种点击

1、函数回调

函数回调是最简单的响应形式,一直以来被用于MenuItem中的点击处理。在新版本中,此处发生了些小改变。我们可以看到在生成的程序中相关代码是这样的:

[cpp] view plaincopyprint?

  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表示这个函数有一个参数。当点击这个按钮时,会调用这个回调函数。

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

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

2、Layer的touch消息响应

     虽然重写了底层的dispatch,但对这层的使用影响并不大。我们同样需要重写:

[cpp] view plaincopyprint?

  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 bool onTouchesBegan(Touch* touch, Event  *event) override;
  8. virtual void onTouchesMoved(Touch* touch, Event  *event) override;
  9. virtual void onTouchesEnded(Touch* touch, Event  *event) override;
  10. virtual void onTouchesCancelled(Touch *touch, Event *event) override;

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

[cpp] view plaincopyprint?

  1. setTouchEnabled(true)。

此外有个小改动。对于单点触控响应,可以调用:

[cpp] view plaincopyprint?

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

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

3、TouchEvent响应

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

[cpp] view plaincopyprint?

  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("按下按钮");
  14. break;
  15. case TouchEventType::TOUCH_EVENT_MOVED:
  16. label = static_cast<LabelTTF*>(getChildByTag(11));
  17. label->setString("按下按钮移动");
  18. break;
  19. case TouchEventType::TOUCH_EVENT_ENDED:
  20. label = static_cast<LabelTTF*>(getChildByTag(11));
  21. label->setString("放开按钮");
  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提供一套自己制定的点击响应。但这样的实现仍然要写很多条件判断,没有能够控件化。可能我的理解有些偏差,欢迎讨论。

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

[cpp] view plaincopyprint?

  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);

其原理是在dispatcher中检查listener列表,例如myListener或加进来的其他listener。然后每个listener检查自己中的Item看能否达到检查条件,例如:mySprite1,mySprite2。然后执行相应的操作。但这样的话,当控件很多的时候,每一次事件都进行这种双链表的检查操作不知会不会影响些性能?

时间: 2024-08-06 14:22:49

cocos2dx 开发成长之路 004的相关文章

cocos2dx 开发成长之路 005

cocos2dx 3.0版本TableView拍生自ScrollView,常用来做滚动列表,有几种特殊用法,不知道大家用到过没 要求:1.滚动时不能选中TableCell,非滚动状态才能选中 很简单,在TableView的delegate函数中,通过isTouchMoved()函数来判断 [cpp] view plaincopy void WeaponSelectLayer::tableCellUnhighlight(cocos2d::extension::TableView* table, c

cocos2dx 开发成长之路 003

SpriteBuilder的使用, 创建SpriteBuilder Project,最好和类名一样,或者相关,一个project里面可以有多个file,每个file即是一个UI,这样可以提高UI的重用率, 1,首先创建Project,命名为DressOnEquip,在file菜单里选project settings,可以把默认缩放改为1X,别的都取消勾选 修改好这些设置,done 2,new a file folder,把你要添加的图片资源文件直接托到folder里面,记住,一定要托噢. 3,n

cocos2dx 开发成长之路 002

在多个layer的情况下,为了避免触摸事件穿透,我们要把触摸事件截取在当前层,具体做法如下 auto listener = EventListenerTouchOneByOne::create(); listener->setSwallowTouches(true); listener->onTouchBegan = CC_CALLBACK_2(MyLayer::onTouchBegan, this); _eventDispatcher->addEventListenerWithScen

cocos2dx 开发成长之路 001

1.响应按钮事件的创建过程中,如果按钮的响应事件是打开某个页面,也就是说创建一个新的页面,那么先要将此之前创建的同样的页面消除掉,这样避免玩家狂点按钮:如果按钮掉功能是请求服务器点话,请求之后可能会进行某些回调操作,那么有两种方法取设计用户体验,一,强制disable操作界面,直至回调完成之后在解除屏蔽:二,假装屏蔽,设置flag判断是否回调结束,如果回调未结束,则玩家点了按钮也不会产生新的请求.相比之下,第二种方式似乎更人性化,毕竟隐藏了对用户对拒绝警告,更加和谐的一种软屏蔽.当然,还会遇到某

cocos2dx 开发成长之路 006

场景单例, 做一个场景是公用的,可以在同一个scene上面更换layer class GameScene { public: static GameScene* getInstance(); virtual ~GameScene(); void loadPlayerAndStart(); void loadStageOpeningAnimation(int mapId, int areaId = 0); void setupPlayScreen(int mapId, bool isNormalS

大二女生web开发成长之路——讲述我从软妹子到女汉子的进阶过程

学习和实践前端一年时间,几乎天天在工作室和一群屌丝男程序员一起学习.开发.这种潜移默化的环境下,编码提高了,节操也细碎了. 一年前,娇滴滴的还是工作室里面小师妹一枚,软软的软件工程妹子,做不到人见人爱,但在这个据说男女比例8比1的学校中,仍是比较受欢迎群体——女生中的一员. 然而,    回想过去这一年,跟一帮大老爷们坐在一起讲蛋疼的笑话: 工作室聚餐中满怀“邪”意地企图把师兄们灌醉: 为了赶项目,可以经常和某位苦逼男一起debug到两三点,不亦乐乎: 男生唤我作欣姐,各种玩笑各种开,因为都不拿

2017年Java web开发工程师成长之路

详情请交流  QQ  709639943 00.2017年Java web开发工程师成长之路 00.R语言速成实战 00.R语言数据分析实战 00.Python+Django+Ansible Playbook自动化运维项目实战 00.Java深入微服务原理改造房产销售平台 00.Python3入门机器学习 经典算法与应用 00.老司机学python篇:第一季(基础速过.机器学习入门) 00.Python 从入门到精通 78节.2000多分钟.36小时的高质量.精品.1080P高清视频教程!包括标

从1.5k到18k, 一个程序员的5年成长之路

http://blog.csdn.net/lgg201/article/details/8637763 昨天收到了心仪企业的口头offer, 回首当初什么都不会开始学编程, 到现在恰好五年. 整天在社区晃悠, 看了不少的总结, 在这个时间点, 我也写一份自己的总结吧. 我一直在社区分享, 所以, 这篇总结也是本着一种分享的态度, 希望相比我还年轻的同学们, 可以从中找到一些让自己成长更快的文字. 先介绍下背景:1. 2008年3月开始学习编程, 目前2013年3月;2. 2009年6月计算机专业

菜鸟程序员的成长之路(三)——2014,逝去的半年,奋斗的半年

从3月份到现在,仅仅半年的时间让我扮演了两个完全不同的角色,从在校生一下变成了毕业生,作为毕业生不能再像在校生一样自由自在,无所顾忌,想怎样就怎样,肆无忌惮的生活,浪费时间.如果你想从容的面临未来的生活,就需要彻头彻尾的改变.多一份稳重,多一份责任,多一份担当. 鉴于LZ不太擅长写非技术博文,那就以碎碎念的形式,来回顾一下我的奋斗历程: 技术 3月份开始备战软考,软考准备了两个多月的时间,从看视频做笔记,再到大家一起讲课,复习,做试题巩固,整个过程至今历历在目.软考虽然不难,但是对于基础差的同学