Cocos2d-x v3.x 的事件派发机制(消息处理机制CCNotificationCenter)

来源:互联网 发布:openwrt nginx服务器 编辑:程序博客网 时间:2024/06/05 17:13

1.版本更新

从cocos2d-x v3.0开始,CCNotificationCenter类被抛弃,使用新的事件派发机制:EventDispatcher

2.简介

从cocos2d-x v3.0开始,由于采用了新的C++11的标准,cocos引入了一种新的处理用户事件的事件派发机制。

由三部分组成:
- Event Listener 封装你的事件代码
- Event Dispatcher 通知相应的事件监听器
- Event Object 包含事件的相关信息

为了响应event,你必须创建一个EventListener。针对不同类型的event,共有5种不同的EventListener
- EventListenerTouch 触摸事件
- EventListenerKeyboard 按键事件
- EventListenerAcceleration 加速事件
- EventListenerMouse 鼠标事件
- EventListenerCustom 自定义事件

之后,将你的事件处理代码(一般是在callback函数中)和相应的事件监听器关联起来。例如,onTouchBeginEventListenerTouch相关联、onKeyPressedEventListenerKeyboard相关联。

之后,在EventDispatcher上注册你的EventListener

当事件发生时,EventDispatcher将会将事件对象Event Object派发到指定的事件处理回调函数。

3.例子

3.1 TouchEvent

首先,创建3个Sprite

    auto sprite1 = Sprite::create("Images/CyanSquare.png");    sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 80));    addChild(sprite1, 10);    auto sprite2 = Sprite::create("Images/MagentaSquare.png");    sprite2->setPosition(origin+Point(size.width/2, size.height/2));    addChild(sprite2, 20);    auto sprite3 = Sprite::create("Images/YellowSquare.png");    sprite3->setPosition(Point(0, 0));    sprite2->addChild(sprite3, 1);  

这里写图片描述

之后,编写EventListener和相应的回调函数

    //Create a "one by one" touch event listener (processes one touch at a time)    auto listener1 = EventListenerTouchOneByOne::create();    // When "swallow touches" is true, then returning 'true' from the onTouchBegan method will "swallow" the touch event, preventing other listeners from using it.    listener1->setSwallowTouches(true);    // Example of using a lambda expression to implement onTouchBegan event callback function    listener1->onTouchBegan = [](Touch* touch, Event* event)    {        // event->getCurrentTarget() returns the *listener's* sceneGraphPriority node.        auto target = static_cast<Sprite*>(event->getCurrentTarget());        //Get the position of the current point relative to the button        Point locationInNode = target->convertToNodeSpace(touch->getLocation());        Size s = target->getContentSize();        Rect rect = Rect(0, 0, s.width, s.height);        //Check the click area        if (rect.containsPoint(locationInNode))        {            log("sprite began... x = %f, y = %f", locationInNode.x, locationInNode.y);            target->setOpacity(180);            return true;        }        return false;    };    //Trigger when moving touch    listener1->onTouchMoved = [](Touch* touch, Event* event){        auto target = static_cast<Sprite*>(event->getCurrentTarget());        //Move the position of current button sprite        target->setPosition(target->getPosition() + touch->getDelta());    };    //Process the touch end event    listener1->onTouchEnded = [=](Touch* touch, Event* event){        auto target = static_cast<Sprite*>(event->getCurrentTarget());        log("sprite onTouchesEnded.. ");        target->setOpacity(255);        //Reset zOrder and the display sequence will change        if (target == sprite2)        {            sprite1->setZOrder(100);        }        else if(target == sprite1)        {            sprite1->setZOrder(0);        }    };

EventDispatcher中注册EventListener

    //Add listener    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);

_eventDispatcherNode节点的一个属性,你可以使用它在任意节点中管理事件,例如SceneLayer,Sprite等等。

上述的例子中,有几个关键的地方需要注意。
1. 在第二次、第三次调用addEventListenerWithSceneGraphPriority时,我们将listener1进行了clone,这是因为一个listener只能注册一次,
2. FixedPrioritySceneGraphPriority
FixedPriority运行你自己设定事件监听器的优先级,值越小,优先级越高。
SceneGraphPriority则是关联到Node节点的优先级设计,Node节点的Z-Index越高,优先级越高。

3.2自定义事件

触摸、按键事件的事件的触发都是由系统自行管理的,除此之外,你还可以设计自定义的事件触发机制。

    _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);    _eventDispatcher->dispatchEvent(&event);    CC_SAFE_DELETE_ARRAY(buf);

上述的代码中,创建了一个EventCustom对象,它通过_eventDispatcher->dispatchEvent(&event)这种方式把事件派发出去。

4. 删除事件监听器EventListener

删除某一个特定的事件监听器:

    _eventDispatcher->removeEventListener(listerner);

删除所有监听器

    _eventDispatcher->removeAllEventListeners();

注意,在删除了所有监听器之后,menu也会变为不可用,因为删除了触摸事件监听器,所以,删除所有监听器的操作需要慎重。

0 0