cocos基础教程(11)事件分发机制

cocos3.0的事件分发机制:

  • 创建一个事件监听器-用来实现各种触发后的逻辑。
  • 事件监听器添加到事件分发器_eventDispatcher,所有事件监听器有这个分发器统一管理。

事件监听器有以下几种:

  • 触摸事件 (EventListenerTouch)
  • 键盘响应事件 (EventListenerKeyboard)
  • 鼠标响应事件 (EventListenerMouse)
  • 自定义事件 (EventListenerCustom)
  • 加速记录事件 (EventListenerAcceleration)

_eventDispatcher的工作由三部分组成:

  • 事件分发器 EventDispatcher
  • 事件类型 EventTouch, EventKeyboard 等
  • 事件监听器 EventListenerTouch, EventListenerKeyboard 等

触摸事件

在处理触摸事件时,既可以重写三个方法onTouchBegan,onTouchMovedonTouchEnded,也可以直接通过Lambda表达式完成响应逻辑。其中的触摸监听类型触摸事件分为EventListenerTouchOneByOne和EventListenerTouchAllAtOnce。EventListenerTouchOneByOne 表示的是单点触摸;而EventListenerTouchAllAtOnce 表示的就是多点触摸。

  1. 只需创建多点触摸事件监听器。
  2. 将其添加到事件分发器中即可。
 // 创建一个事件监听器类型为 OneByOne 的单点触摸
    auto listener1 = EventListenerTouchOneByOne::create();
    // 设置是否吞没事件,在 onTouchBegan 方法返回 true 时吞没
    listener1->setSwallowTouches(true);

    // 使用 lambda 实现 onTouchBegan 事件回调函数
    listener1->onTouchBegan = [](Touch* touch, Event* event){
        // 获取事件所绑定的 target
        auto target = static_cast<Sprite*>(event->getCurrentTarget());

        // 获取当前点击点所在相对按钮的位置坐标
        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){...};

最后需要将事件监听器添加到事件分发器

    // 添加监听器
    _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之后菜单也不能响应。因为它也需要接受触摸事件。

键盘响应事件

键盘响应事件和处理触摸事件使用了相同的处理方式,一下代码演示如何处理键盘响应事件:

    // 初始化并绑定
    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 中多了鼠标捕获事件派发,这可以在不同的平台上,丰富我们游戏的用户体验。

下面代码实现鼠标响应事件的实现步骤:

    // 创建监听器
    _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);

自定义事件

以上是系统自带的事件类型,事件由系统内部自动触发,如 触摸屏幕,键盘响应等,除此之外,还提供了一种 自定义事件,简而言之,它不是由系统自动触发,而是人为的干涉,如下:

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

以上定义了一个 “自定义事件监听器”,实现了相关逻辑,并且添加到事件分发器。上面的自定义事件将由以下代码触发:

    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个方向的加速度,相关代码如下:

class Acceleration
{
public:
    double x;
    double y;
    double z;

    double timestamp;

    Acceleration(): x(0), y(0), z(0), timestamp(0) {}
};

该类中每个方向的加速度大小都为一个重力加速度大小。

在使用加速计事件监听器之前,需要先启用此硬件设备:

Device::setAccelerometerEnabled(true);

然后创建对应的监听器,在创建回调函数时,可以使用 lambda 表达式创建匿名函数,也可以绑定已有的函数逻辑实现,如下:

    auto listener = EventListenerAcceleration::create([=](Acceleration* acc, Event* event){
        //逻辑代码段
    });
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
时间: 2024-10-13 07:11:50

cocos基础教程(11)事件分发机制的相关文章

Android的Touch事件分发机制简单探析

前言 Android中关于触摸事件的分发传递是一个很值得研究的东西.曾不见你引入了一个ListView的滑动功能,ListView就不听你手指的指唤来滚动了:也不知道为啥Button设置了onClick和onTouch,其中谁会先响应:或许你会问onTouch和onTouchEvent有什么区别,又该如何使用?这里一切的一切,只要你了解了事件分发机制,你会发现,解释这都不是事儿! 相关Touch事件的方法 1.public boolean dispatchTouchEvent(MotionEve

Android事件分发机制详解:史上最全面、最易懂

前言 Android事件分发机制是每个Android开发者必须了解的基础知识 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全.思路不清晰.无源码分析.简单问题复杂化等等 今天,我将全面总结Android的事件分发机制,我能保证这是市面上的最全面.最清晰.最易懂的 本文秉着"结论先行.详细分析在后"的原则,即先让大家感性认识,再通过理性分析从而理解问题: 所以,请各位读者先记住结论,再往下继续看分析: 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读 目

Cocos2d-X 3.x 事件分发机制详解

事件分发机制 新事件分发机制:在2.x 版本事件处理时,将要触发的事件交给代理(delegate)处理,再通过实现代理里面的onTouchBegan等方法接收事件,最后完成事件的响应.而在新的事件分发机制中,只需通过创建一个事件监听器-用来实现各种触发后的逻辑,然后添加到事件分发器_eventDispatcher,所有事件监听器由这个分发器统一管理,即可完成事件响应.请参考更多3.0资料... 事件监听器有以下几种: 触摸事件 (EventListenerTouch) 键盘响应事件 (Event

Android View的事件分发机制

准备了一阵子,一直想写一篇事件分发的文章总结一下.这个知识点实在是太重要了. 一个应用的布局是丰富的,有TextView,ImageView,Button等.这些子View的外层还有ViewGroup.如RelativeLayout.LinearLayout.作为一个开发人员,我们会思考.当点击一个button,Android系统是如何确定我点的就是button而不是TextView的?然后还正确的响应了button的点击事件. 内部经过了一系列什么过程呢? 先铺垫一些知识能更加清晰的理解事件分

图解 Android 事件分发机制

首发原文:http://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548149&idx=1&sn=709149df682c7d3a6e453c9ef0626a1f&chksm=f1180e08c66f871eb2e7e39e057a5b090214fd71adcd98aa36b3d7fcecf77ad5d08138c50131#rd 在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟

Android事件分发机制的学习

最近被Android事件分发机制折磨的很烦躁,网上各种博客资料看完觉得还是得自己写一篇,一方面加深理解,另一方面希望能帮助到也同样在学习相关知识的童鞋们. 话不多说,直接开整. 当用户的手指点击到屏幕,便是整个事件的开始. 首先获取到该事件的是view层的控制者Activity,具体怎么获得我们不得而知,在此也不追究,而继续我们的主题.Activity获得事件后便执行它自身的方法: public boolean dispatchTouchEvent(MotionEvent ev) { if (e

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用Ima

android 事件分发机制(图文详解)

在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少.废话不多说,总结一句:事件分发机制很重要. Android 事件分发流 关于Android 事件分发机制网上的博文很多,但是很多都是写个Demo然后贴一下输出的Log或者拿源码分析,然后一堆的注释和说明,如果用心的

Cocos2d-x 3.X 事件分发机制

介绍 Cocos2d-X 3.X 引入了一种新的响应用户事件的机制. 涉及三个基本的方面: Event listeners 封装你的事件处理代码 Event dispatcher 向 listener 分发用户事件 Event 对象 包含关于事件的信息 为了响应事件,首先你要创建一个 EventListener,有五种不同的 EventListener. EventListenerTouch 响应触控事件 EventListenerKeyboard 响应键盘事件 EventListenerAcc