Cocos2d-X研究之v3.x 事件分发机制具体解释
事件分发机制
" src="http://www.cgzhw.com/wp-content/uploads/2014/07/inherent3.png" style="">
新事件分发机制:在2.x 版本号事件处理时。将要触发的事件交给代理(delegate)处理,再通过实现代理里面的onTouchBegan等方法接收事件。最后完毕事件的响应。而在新的事件分发机制中。仅仅需通过创建一个事件监听器-用来实现各种触发后的逻辑。然后加入到事件分发器_eventDispatcher。全部事件监听器由这个分发器统一管理,就可以完毕事件响应。请參考很多其它3.0资料。。。
事件监听器有下面几种:
- 触摸事件 (EventListenerTouch)
- 键盘响应事件 (EventListenerKeyboard)
- 鼠标响应事件 (EventListenerMouse)
- 自己定义事件 (EventListenerCustom)
- 加速记录事件 (EventListenerAcceleration)
_eventDispatcher的工作由三部分组成:
- 事件分发器 EventDispatcher
- 事件类型 EventTouch, EventKeyboard 等
- 事件监听器 EventListenerTouch, EventListenerKeyboard 等
监听器实现了各种触发后的逻辑。在适当时候由事件分发器分发事件类型。然后调用对应类型的监听器。
用户输入事件
触摸事件
在处理触摸事件时,既能够重写三个方法onTouchBegan,onTouchMoved和onTouchEnded,也能够直接通过Lambda表达式完毕响应逻辑。
在2.x版本号中,开启多点触摸须要在AppController.mm中的application didFinishLaunchingWithOptions:launchOptions中加入[__glView setMultipleTouchEnabled: YES],另外还需重载5个对应函数:
- virtual void registerWithTouchDispatcher(void);
- virtual void ccTouchesBegan(cocos2d::CCSet pTouches, cocos2d::CCEvent
pEvent); - virtual void ccTouchesMoved(cocos2d::CCSet pTouches, cocos2d::CCEvent
pEvent); - virtual void ccTouchesEnded(cocos2d::CCSet pTouches, cocos2d::CCEvent
pEvent); - virtual void ccTouchesCancelled(cocos2d::CCSet pTouches, cocos2d::CCEvent
pEvent);
而在3.0中,仅仅需创建多点触摸事件监听器。并将其加入到事件分发器中就可以。
下面代码在一个界面中加入三个button。三个button相互遮挡,而且都能触发触摸事件:
|
1
2
3
4
5
6
7
8
|
// 创建button精灵
auto sprite1
= Sprite::create("Images/CyanSquare.png"); sprite1->setPosition(origin+Point(size.width/2,
size.height/2) + Point(-80, 80));
addChild(sprite1,
10); // sprite2
...
// sprite3
...
|
" src="http://www.cgzhw.com/wp-content/uploads/2014/07/touch1.png">
创建好button精灵后,创建单点触摸事件监听器,并完毕对应逻辑处理
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// 创建一个事件监听器类型为 OneByOne 的单点触摸
auto listener1
= EventListenerTouchOneByOne::create(); // 设置是否吞没事件,在 onTouchBegan 方法返回 true 时吞没
listener1->setSwallowTouches(true);
// 使用 lambda 实现 onTouchBegan 事件回调函数
listener1->onTouchBegan
= [](Touch* touch, Event* event) -> bool {
// 获取事件所绑定的 target
auto
target = static_cast<Sprite*>(event->getCurrentTarget()); // 获取当前点击点所在相对button的位置坐标
Point locationInNode
= target->convertToNodeSpace(touch->getLocation()); Size
s = target->getContentSize();
Rect rect
= Rect(0, 0, s.width, s.height);
// 点击范围推断检測
if
(rect.containsPoint(locationInNode))
{
log("sprite began... x = %f, y = %f",
locationInNode.x, locationInNode.y);
target->setOpacity(180);
return
true;
}
return
false;
};
// 触摸移动时触发
listener1->onTouchMoved
= [](Touch* touch, Event* event){...}; // 点击事件结束处理
listener1->onTouchEnded
= [=](Touch* touch, Event* event){...}; |
最后须要将事件监听器加入到事件分发器
|
1
2
3
4
|
// 加入监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1,
sprite1); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),
sprite2);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),
sprite3); |
以上代码中_eventDispatcher是Node的属性,通过它管理当前节点(场景、层、精灵等)的全部事件的分发。
但它本身是一个单例模式值的引用,在Node的构造函数中。通过Director::getInstance()->getEventDispatcher(); 获取,有了这个属性,就能方便的处理事件。
注意:当再次使用 listener1 的时候,须要使用clone()方法创建一个新的克隆,由于在使用addEventListenerWithSceneGraphPriority或者addEventListenerWithFixedPriority方法时,会对当前使用的事件监听器加入一个已注冊的标记,这使得它不可以被加入多次。另外,有一点很重要,FixedPriority listener加入完之后须要手动remove,而SceneGraphPriority listener是跟Node绑定的,在Node的析构函数中会被移除。详细的演示样例使用方法可以參考引擎自带的tests。
我们能够通过下面方法移除一个已经被加入了的监听器。
_eventDispatcher->removeEventListener(listener);
也能够使用例如以下方法。移除当前事件分发器中全部监听器。
_eventDispatcher->removeAllEventListeners();
当使用removeAll的时候。此节点的全部的监听将被移除,推荐使用 指定删除的方式。
removeAll之后菜单也不能响应。
由于它也须要接受触摸事件。
键盘响应事件
键盘响应事件和处理触摸事件使用了同样的处理方式,一下代码演示怎样处理键盘响应事件:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 初始化并绑定
auto listener
= EventListenerKeyboard::create(); listener->onKeyPressed
= CC_CALLBACK_2(KeyboardTest::onKeyPressed, this);
listener->onKeyReleased
= CC_CALLBACK_2(KeyboardTest::onKeyReleased, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,
this);
// 键位响应函数原型
void
KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
log("Key with keycode %d pressed",
keyCode);
}
void
KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) {
log("Key with keycode %d released",
keyCode); }
|
鼠标响应事件
在 3.0 中多了鼠标捕获事件派发。这能够在不同的平台上。丰富我们游戏的用户体验。
以下代码实现鼠标响应事件的实现步骤:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 创建监听器
_mouseListener
= EventListenerMouse::create();
// 时间响应逻辑
_mouseListener->onMouseMove
= [=](Event *event){
EventMouse*
e = (EventMouse*)event; string
str = "Mouse Down detected, Key: ";
str
+= tostr(e->getMouseButton()); // ...
};
_mouseListener->onMouseUp
= [=](Event *event){...};
_mouseListener->onMouseDown
= [=](Event *event){...}; _mouseListener->onMouseScroll
= [=](Event *event){...};
// 加入到事件分发器
_eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener,
this); |
自己定义事件
以上是系统自带的事件类型。事件由系统内部自己主动触发,如 触摸屏幕,键盘响应等。除此之外,还提供了一种 自己定义事件,简而言之,它不是由系统自己主动触发。而是人为的干涉。例如以下:
|
1
2
3
4
5
6
7
8
9
|
_listener = EventListenerCustom::create("game_custom_event1", [=](EventCustom* event){
std::string
str("Custom event 1 received, "); char*
buf = static_cast<char*>(event->getUserData());
str
+= buf; str
+= " times";
statusLabel->setString(str.c_str());
});
_eventDispatcher->addEventListenerWithFixedPriority(_listener,
1); |
以上定义了一个 “自己定义事件监听器”。实现了相关逻辑,而且加入到事件分发器。
上面的自己定义事件将由下面代码触发:
|
1
2
3
4
5
6
7
8
9
10
11
|
static
int count = 0;
++count;
char*
buf = new char[10];
sprintf(buf,
"%d", count); EventCustom
event("game_custom_event1");
event.setUserData(buf);
if(...)
{
_eventDispatcher->dispatchEvent(&event);
}
CC_SAFE_DELETE_ARRAY(buf);
|
定义一个 EventCustom,而且设置了其 UserData 数据,手动的通过 _eventDispatcher->dispatchEvent(&event); 将此事件分发出去。从而触发之前所实现的逻辑。
加速计事件
除了触摸。移动设备上一个非常重要的输入源是设备的方向,因此大多数设备都配备了加速计。用于測量设备精巧或匀速运动时所受到的重力方向。
重力感应来自移动设备的加速计,通常支持X,Y和Z三个方向的加速度感应,所以又称为三向加速计。
在实际应用中。能够依据3个方向的力度大小来计算手机倾斜的角度或方向。
3.0中,新的事件机制下。我们须要通过创建一个加速计监听器EventListenerAcceleration,其静态create方法中有个Acceleration的參数须要注意。
Acceleration是一个类,包括了加速计获得的3个方向的加速度。相关代码例如以下:
|
1
2
3
4
5
6
7
8
9
10
11
|
class
Acceleration
{
public:
double
x; double
y;
double
z;
double
timestamp;
Acceleration():
x(0), y(0), z(0), timestamp(0) {} };
|
该类中每一个方向的加速度大小都为一个重力加速度大小。
在使用加速计事件监听器之前,须要先启用此硬件设备:
Device::setAccelerometerEnabled(true);
然后创建相应的监听器。在创建回调函数时。能够使用 lambda 表达式创建匿名函数,也能够绑定已有的函数逻辑实现,例如以下:
|
1
2
3
4
|
auto
listener = EventListenerAcceleration::create([=](Acceleration* acc, Event* event){
//逻辑代码段
});
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,
this); |
Cocos2d-X研究之v3.x 事件分发机制具体解释的更多相关文章
- Android 事件分发机制具体解释
很多其它内容请參照我的个人网站: http://stackvoid.com/ 网上非常多关于Android事件分发机制的解释,大多数描写叙述的都不够清晰,没有吧来龙去脉搞清晰,本文将带你从Touch事 ...
- Android事件分发机制具体解释
转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/52416141 1. 概述 Android日常研发时,与View接触占领相当多的时间.而 ...
- android 事件分发机制详解(OnTouchListener,OnClick)
昨天做东西做到触摸事件冲突,以前也经常碰到事件冲突,想到要研究一下Android的事件冲突机制,于是从昨天开始到今天整整一天时间都要了解这方面的知识,这才懂了安卓的触摸和点击事件的机制.探究如下: 首 ...
- Android View 事件分发机制 源码解析 (上)
一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...
- Cocos2d-x 3.2 学习笔记(九)EventDispatcher事件分发机制
EventDispatcher事件分发机制先创建事件,注册到事件管理中心_eventDispatcher,通过发布事件得到响应进行回调,完成事件流. 有五种不同的事件机制:EventListenerT ...
- Android View 事件分发机制详解
想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...
- Android查缺补漏(View篇)--事件分发机制
事件分发机制是Android中非常重要的一个知识点,同时也是难点,相信到目前为止很多Android开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...
- ViewGroup事件分发机制解析
最近在看View的事件分发机制,感觉比复杂的地方就是ViewGrop的dispatchTouchEvent函数,便对照着源码研究了一下.故名思意这个函数起到的作用就是分发事件,在具体分析之前还要说明几 ...
- android view事件分发机制
首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...
随机推荐
- SourceTree的简单使用
原文网址:http://blog.csdn.net/u011439289/article/details/42126507 今天开始参与公司项目的代码编写,公司内部采用的是gitlib,所以用到了So ...
- Entity framework 增加默认执行时间
public partial class ProductionSupportEntities : DbContext { public ProductionSupportEntities() : ba ...
- 液晶电视插有线电视信号线的是哪个接口 HDMI是什么接口
1.液晶电视插有线电视信号线的接口(模拟信号)是射频接口(也叫RF接口,同轴电缆接口,闭路线接口),数字信号就得通过机顶盒转换成模拟信号视频输出至电视,才能正常收看电视节目. 2.电视机或高清机顶盒上 ...
- QQ去除未读状态的动画
QQ去除未读状态的动画 by 伍雪颖 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmFpbmxlc3Zpbw==/font/5a6L5L2T/fonts ...
- springboot—spring aop 实现系统操作日志记录存储到数据库
原文:https://www.jianshu.com/p/d0bbdf1974bd 采用方案: 使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志 缺点是要针对 ...
- 【Gitlab】从Gitlab拉取项目+往Gitlab发布项目 【GitLab自定义端口】
1>GIt需要提前安装在本地,本机,自己的电脑,开发环境电脑,IDEA所在的电脑 2>代码仓库:gitlab 3>开发工具:IDEA 4>内网搭建gitlab,访问url: h ...
- h.264 x.264
这是两个不同类型的东西. x264是视频编码器,H.264是视频编码格式. x264编出来的东西就是h.264的.举个例子来说,x264就好比画图或者photoshop,h.264就好比jpg,bmp ...
- Ioc:Autofac Registration Concepts
Reflection Components When using reflection-based components, Autofac automatically uses the constru ...
- CQRS:When to use CQRS
Now that we are at the end of our journey, we can suggest some of the criteria you should evaluate t ...
- h5语音录制及上传(Java版语音聊天系统)
Since Chrome version 47, Voice Recording works only on HTTPS sites 目前基于webikit(谷歌之类的webikit)和Gecko(F ...