Cocos2dx 3.2 节点之间相互通信与设置触摸吞噬的方法

  实际开发中,我们经常会遇到这样的情况。我们有一个层layer1,这个层包含一个menu层,menu1层里又包含了一个节点按钮button1。现在需要实现一个效果:点击button1弹出一个对话框,这个对话框里也包含一个menu2和一个按钮button2,点击button2能够关闭这个对话框。这个情况很普遍,在游戏ui中我们有大量的二级弹窗都需要用到这种效果(在这里我们不考虑直接在layer2里removefromparent,这样就不能达成学习目的了)。我们可以用三种方法实现这个效果,分别是:

  1、通过代理中转;

  2、通过parent指针获得父节点;

  3、使用NotificationCenter消息管理器发送和接收消息;

  我们一个一个的来探究它们的实现方式。

一、通过代理中转

  首先我们需要在layer1里新建一个代理类Delegate,这个代理类只含有一个public的纯虚函数stop()。然后我们让layer1继承自Delegate,再在layer1中实现这个stop函数,具体内容先空着,等会再写。接着layer2中加一条成员变量Delegate* example;然后我们回到layer1的按钮button1的回调函数里在createlayer2之后,将layer1的this指针赋给layer2的example。之后在layer2的button2的回调里调用example的stop函数。最后我们在layer1的stop函数里将layer2的对象remove掉。文字还是很难理解,我们还是直接上代码吧:

  这是layer1的头文件:

 1 #ifndef __LAYER1_H__
 2 #define __LAYER1_H__
 3
 4 #include "cocos2d.h"
 5 USING_NS_CC;
 6 class Delegate//代理类
 7 {
 8 public:
 9     virtual void stop() = 0;//纯虚函数
10 };
11 class layer1 :public Scene,public Delegate
12 {
13 public:
14     static Scene* scene();
15     CREATE_FUNC(layer1);
16     bool init();
17     void stop();//重写stop
18     void loadMenuItem();//加载按钮
19     void func();//按钮的回调
20     Layer* lay;//layer2的指针
21 };
22
23 #endif

  这是layer1的cpp文件:

 1 #include "layer1.h"
 2 #include "layer2.h"
 3 Scene* layer1::scene()
 4 {
 5     Scene* scene1 = Scene::create();
 6     Layer* layer = Layer::create();
 7     scene1->addChild(layer);
 8     return scene1;
 9 }
10 bool layer1::init()
11 {
12     Scene::init();
13     loadMenuItem();
14     Size size = Director::getInstance()->getWinSize();
15     Sprite* sprite = Sprite::create("HelloWorld.png");//背景
16     sprite->setPosition(size.width / 2, size.height / 2);
17     addChild(sprite);
18     return true;
19 }
20 void layer1::loadMenuItem()
21 {
22     MenuItem* item = MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_0(layer1::func, this));//按钮
23     item->setZOrder(100);
24     Menu* menu = Menu::create();
25     item->setPositionX(item->getPositionX() + 300);
26     menu->addChild(item);
27     addChild(menu,1);
28 }
29 void layer1::func()
30 {
31     layer2* layer = layer2::create();
32     layer->example = this;//将layer1的指针传进去
33     lay = layer;
34     addChild(lay);
35 }
36 void layer1::stop()
37 {
38     lay->removeFromParent();//将layer2删除释放
39 }

  这是layer2的头文件:

 1 #ifndef __LAYER2_H__
 2 #define __LAYER2_H__
 3 #include "cocos2d.h"
 4 #include "layer1.h"
 5 USING_NS_CC;
 6 class layer2:public Layer
 7 {
 8 public:
 9     CREATE_FUNC(layer2);
10     bool init();
11     void loadMenuItem();
12     Delegate* example;//存放layer1的指针

13    void func(); 14 }; 

15 #endif

  这是layer2的cpp文件:

 1 #include "layer2.h"
 2
 3 bool layer2::init()
 4 {
 5     Sprite* sprite = Sprite::create("background.png");
 6     Size size = Director::getInstance()->getWinSize();
 7     sprite->setPosition(size.width / 2, size.height / 2);
 8     addChild(sprite);
 9     loadMenuItem();
10     return true;
11 }
12 void layer2::loadMenuItem()
13 {
14     MenuItem* item = MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_0(layer2::func, this));
15     item->setZOrder(100);
16     item->setPositionY(item->getPositionY() + 20);
17     Menu* menu = Menu::create();
18     menu->addChild(item);
19     addChild(menu, 1);
20 }
21 void layer2::func()
22 {
23     example->stop();
24 }

  现在我们可以实现这个效果了,如下图:

  但是我发现了一个致命的bug。因为layer2的背景层比较小,并没有遮住layer1的button1按钮。问题来了:在layer2层弹出以后,我们依然可以点击layer1层的按钮,之后在点击button2就会崩溃。怎么解决这个bug呢?这就要说到3.x 版本的触摸事件分发机制了。在2.x版本中,我们想要处理触摸事件,需要重载相应的touch函数,那时为了处理这种bug,我们需要将一个层的优先级设到-130(因为menu也是一个层,而且优先级相当之高,有-128,数值越低优先级越高,为了不让menu先处理触摸事件,我们需要将拦截层的优先级设置的比menu高才行),然后在这个层的触摸函数里决定如何调用其他层的触摸函数,如此达到分发触摸事件的目的。

  然而3.x版本对触摸监听做出了重大改动,所有的触摸监听统一由事件分发器_eventDispatcher注册后处理。

  我的方法是这样的:我的原始层是layer1,对话框是layer2,我在layer2里注册了一个触摸监听,把它的优先级设为-130(这个触摸监听需要你自己在onExit函数里release),这样在对话框弹出来之后,这个触摸监

  听就会拦截所有的触摸信号,我在这个监听里面调用layer2的menu的touch函数,注意,当menu的touchbegan返回false的时候,我们不执行menu的touchend函数。这样就可以实现我们想要的效果了!

  接下来上代码!

  因为layer1的代码基本无改动,我就只贴layer2的代码了。

  头文件:

 1 #ifndef __LAYER2_H__
 2 #define __LAYER2_H__
 3 #include "cocos2d.h"
 4 #include "layer1.h"
 5 USING_NS_CC;
 6 class layer2:public Layer
 7 {
 8 public:
 9     CREATE_FUNC(layer2);
10     bool init();
11     void loadMenuItem();
12     Delegate* example;
13     void func();
14     Sprite* background;
15     EventListenerTouchOneByOne* _ev;//我们需要保存监听事件,因为它不受cocos自动管理,我们需要手动释放它
16     bool flag;
17     void onExit()
18     {
19         Layer::onExit();
20         _eventDispatcher->removeEventListener(_ev);//手动释放
21     }
22 };
23 #endif

  这是cpp文件:

122 #include "layer2.h"
123
124 bool layer2::init()
125 {
126     Sprite* sprite = Sprite::create("background.png");
127     Size size = Director::getInstance()->getWinSize();
128     sprite->setPosition(size.width / 2, size.height / 2);
129     background = sprite;
130     addChild(sprite);
131     loadMenuItem();
132     return true;
133 }
134 void layer2::loadMenuItem()
135 {
136     MenuItem* item = MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_0(layer2::func, this));
137     item->setPositionY(item->getPositionY() + 20);
138     Menu* menu = Menu::create();
139     menu->addChild(item);
140     addChild(menu, 1);
141     EventListenerTouchOneByOne* ev = EventListenerTouchOneByOne::create();//创建一个单点触摸监听事件
142     ev->setSwallowTouches(true);//这个函数用于设置触摸吞噬,如果两个精灵相重叠,那么触摸信号只会由优先级最高的处理,不会向下传递
143     ev->onTouchBegan = [=](Touch* touch,Event* ev){
144         flag = menu->onTouchBegan(touch, ev);//保存ontouchbegan的返回值,因为当flag为false的时候我们不需要执行ontouchend
145         return true;
146     };
147     ev->onTouchEnded = [=](Touch* touch,Event* ev){
148         if(!flag)
149         {
150             return;
151         }
152         menu->onTouchEnded(touch, ev);//调用menu的touchend函数
153     };
154     _ev = ev;
155     _eventDispatcher->addEventListenerWithFixedPriority(ev, -130);//注册并设置优先级
156 }
157 void layer2::func()
158 {
159     example->stop();
160 }

二、通过parent指针获得父节点

  这个就很简单了,直接强转:

1 void layer2::func()
2 {
3     layer1* layer = (layer1*)getParent();
4     //example->stop();
5     layer->lay->removeFromParent();
6 }

三、使用NotificationCenter消息管理器发送和接收消息

  这个也非常简单,首先你要在button2的回调里设置发送消息:

1 NotificationCenter::getInstance()->postNotification("xuan",NULL);

  接着在需要layer1的init函数里设置监听:

1     NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(layer1::stop),"xuan",NULL);

  在这里附上一篇博文的地址,详细的解释了NotificationCenter用法:http://blog.csdn.net/yangxuan0261/article/details/21793513

  好了,这篇博文到此结束!

  

Cocos2dx 3.2 节点之间相互通信与设置触摸吞噬的方法

时间: 2024-10-27 11:18:00

Cocos2dx 3.2 节点之间相互通信与设置触摸吞噬的方法的相关文章

android中fragment和activity之间相互通信

在用到fragment的时候,老是会遇到一个问题,就是fragment与activity之间的通信.下面就来记录一下activity和fragment之间 通过实现接口来互相通信的方法. 1. activity 向fragment发出通信,就这么写: private OnMainListener mainListener; // 绑定接口 @Override public void onAttachFragment(Fragmentfragment) { try { mainListener =

IPV4和IPV6之间相互通信

网络拓扑: R1:   ipv6 unicast-routing                                ===========开启ipv6 int f0/0   ip address 192.168.12.1 255.255.255.0    no shutdown    interface Loopback0     ipv6 address 2012:2012::1/64  ip route 192.168.23.0 255.255.255.0 192.168.12.

Android WebView js 与 java 之间相互通信

前面做手机浏览器,经常用到,js网页与Java之间的相互通信. 写个简单示例把. 1.Js 与Activity通讯 BrowserActivity.showSource("parameter"); 红:代表调用的类 蓝:代码表代用的方法名 黑:代表调用的参数 Js可以通过此方法,携带参数与Android通讯 在BrowserActivity.class里面 @JavascriptInterface  //这一句一定要加,否则调用不到 pubic  void howSource(Stri

相同VLAN在不同交换机之间相互通信

当两个统一网段的主机在不同交换机时,想要实现相互通信,就要使用VLAN.(两台交换机的VLAN设置要相同) 首先创建VLAN 12(1到1002之间选择),两个交换机VLAN要相同.把连接主机的端口加入到VLAN 12(代码如图2).然后要注意把两个交换机之间的各自的接口加入VLAN 12(如果想实现多个不同VLAN同时访问,可以打开TRUNK,如图3).这样就可以了

不同VLAN之间相互通信的两种方式

(单臂路由.三层交换) 试验环境:东郊二楼第三机房 试验设备:Catalyst 2950-24(SW3) Cisco 2611(R2) Catalyst 3750 SERIES (带两个SD接口,S8----SW-2L) 真机(PC5.PC6). 试验目的: 1.通过单臂路由实现不同VLAN之间的通信 2.通过三层交换路由功能实现不同VLAN之间的通信 网络拓扑图: 1.单臂路由实现不同VLAN互通试验网络拓扑图 2.三层交换实现不同VLAN互通实验网络拓扑图 实验步骤: 单臂路由实现不同VLA

部署邮件服务器之间相互通信

我们自己部署的邮件服务器系统,正常是不能与别的邮件服务器通信,我们搭建的邮件服务器只能跟自己内部的人员通信,这样就带来了很大的不便,那么今天我们将配置自己搭建的邮件服务器如何跟别的邮件服务器进行通信.我们先来了解需要用到的组件:SMTP连接器提供传递邮件到特定目的地的单向路径:用来发送和接收邮件.邮件服务器中至少有两个SMTP连接器 :SMTP发送连接器.SMTP接收连接器.邮件传输所需要的组件:根据一个简单的拓补图了解一下:大致实验步骤:? 打开两台安装的exchange服务器? 在双方的DN

vue组件父子之间相互通信案例

STM32W108无线射频模块两节点之间通信实例

本文基于802.15.4/ZigBee的SimpleMac协议栈编写程序,实现两个STM32W108无线节点之间的通信.节点分为SUN节点和PLANET节点,SUN节点使用STM32W108无线开发板,PLANET节点使用STM32W108无线节点,SUN节点可与PC机进行通信. 程序设计与实现 程序的设计基于SimpleMac协议栈进行,根据官方提供的MAC协议栈示例代码进行的裁剪更改,第10章已对协议栈代码进行了解析,在此就不详细说明,以下只给出部分主要相关代码. 文件solar-syste

STM32W108无线射频模块多节点之间通信实例

STM32W108无线射频模块多节点之间通信实例 基于STM32W108的SimpleMac协议栈编写程序,实现多个无线节点之间的通信.节点分为SUN节点和PLANET节点,SUN节点使用STM32W108无线开发板,PLANET节点使用STM32W108无线数据采集节点,SUN节点可与PC机进行通信. 编程与实现 程序的设计基于SimpleMac协议栈进行,以下给出部分主要相关代码.该实例中的部分代码与第11章中的两节点通信实例代码相同,本章不再重复说明. 文件solar-system.c部分