Cocos2dx引擎笔记——事件分发机制

一、事件分发机制

2.x 版本事件分发机制:事件处理时,将要触发的事件交给代理(delegate)处理,再通过实现代理里面的onTouchBegan等方法接收事件,最后完成事件的响应。

3.x 的事件分发机制:只需通过创建一个事件监听器-用来实现各种触发后的逻辑,然后添加到事件分发器_eventdispatcher,所有事件监听器有这个分发器统一管理,即可完成事件响应。

事件监听器有以下几种:

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

事件分发器_eventdispatcher的工作由三部分组成:

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

监听器实现了各种触发后的逻辑,在适当时候由事件分发器分发事件类型,然后调用相应类型的监听器

二、用户输入事件

触摸事件处理方法,两种:

1、 重写onTouchBegan,onTouchMovedonTouchEnded

2、 直接通过Lambda表达式完成响应逻辑。

在2.x版本中,开启多点触摸需要在AppController.mm中的application didFinishLaunchingWithOptions:launchOptions添加[__glView setMultipletouchEnabled: YES],另外还需重载5个相应函数

  • virtual void registerWithTouchdispatcher(void);
  • virtual void cctouchesBegan(cocos2d::CCSetptouches,cocos2d::CCEventpEvent);
  • virtual void cctouchesMoved(cocos2d::CCSetptouches,cocos2d::CCEventpEvent);
  • virtual void cctouchesEnded(cocos2d::CCSetptouches,cocos2d::CCEventpEvent);
  • virtual void cctouchesCancelled(cocos2d::CCSetptouches,cocos2d::CCEventpEvent);

而在3.0中,只需创建多点触摸事件监听器,并将其添加到事件分发器中即可。

以下代码一个界面中添加三个按钮,三个按钮相互遮挡,并且都能触发触摸事件:

// 创建按钮精灵
    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
    ...

创建好按钮精灵后,创建单点触摸事件监听器,并完成相应逻辑处理

 // 创建一个事件监听器类型为 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,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);
声明:本文是对http://www.cocos.com/帮助文档的阅读笔记。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...