0
点赞
收藏
分享

微信扫一扫

Cocos2d-x事件分发机制概述

小北的爹 2022-02-17 阅读 182

Cocos2d-x事件分发机制概述

  Cocos2d-x通过事件分发机制响应用户事件,已内置支持常见的事件如触摸事件,键盘事件等。同时提供了创建自定义事件的方法,满足我们在游戏的开发过程中,特殊的事件响应需求。

基本元素

  • 事件监听器:负责接收事件,并执行预定义的事件处理函数
  • 事件分发器:负责发起通知
  • 事件对象:记录事件的相关信息

监听器

五种类型

  • EventListenerTouch- 响应触摸事件
  • EventlistenerKeyboard- 响应键盘事件
  • EventListenerAcceleration- 响应加速度事件
  • EventListenerMouse - 响应鼠标事件
  • EventListenerCustom - 响应自定义事件

事件的吞没

  当你有一个监听器,已经接收到了期望的事件,这时时间应该被吞没。事件被吞没,意味着事件的传递过程中,你消耗了此事件,事件不再向下传递。避免了下游的其它监听器获取到此事件。

  设置吞没:

//当“swallow Touch”为真时,则OnTouch方法将“吞下”触摸事件,防止其它监听器使用它。
listener`->setSwallowTouches(true);

//同时我们在onTouchBegan()执行后也应该return true。
listener1->onTouchBegan = [](Touch* touch,Event* event){
    //TODO
    return true;
}

优先级

  事件的吞没中,我们提到了事件的传递。事件如何传递,先到哪个监听器?这是由优先级决定的。

  固定值优先级使用一个整形的数值,数值较低的监听器比数值较高的监听器,先接收到时间。

  场景图优先级是指向节点对象的指针,z-order较高的节点中的监听器比z-order较低的节点中的,先收到事件。

由于z-order较高的节点在顶部绘制,所以使用这种优先级可以确保触摸事件被正确响应。

  还记得这个场景图吗?图像绘制时,是按照A,B,C,D,E,F,G,H,I的顺序。

效果图

  当使用场景图优先级时,事件是按照绘制的反方向,即I,H,G,F,E,D,C,B,A传递。如果一个事件被触发,I节点先接收到,如果在I节点中事件被吞没,则不会继续传递,未被吞没,事件将传递到H节点,每个节点都重复同样的逻辑,直到事件被吞没,或者传递结束,本次事件触发才完成。

触摸事件

  触摸事件是手机游戏中最重要的事件,它易于创建,还能提供多种多样的功能。

  让我们先了解一下什么是触发事件,当你触发移动设备的屏幕时,设备感受到被触摸,了解到被触摸的位置,同时取得触摸到的内容,然后你的触摸被回答。这就是触摸事件。

  创建触摸事件监听器:

//创建一个“one by one”触发监听器
//只能一次处理一次触摸
auto listener1 = EventListenerTouchOneByOne::create();

//第一次按下触发
listener1->onTouchBegan = [](Touch* touch,Event* event){
    //TODO
    return true;//如果要销毁它则返回true
}

//当我们移动的时候触发
listener1->onTouchMoved = [](Touch* touch,Event* event){
    //TODO
}

//当我们离开的时候触发
listener1->onTouchEnded = [](Touch* touch,Event* event){
    //TODO
}

//添加监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listner1,this);//当节点销毁时,同时销毁添加的事件监听

  可以看到,在使用触摸事件监听器时,可以监听三种不同的事件,每一个事件都有自己触发的时机。

  三种事件及其触发时机:

  • onTouchBegan开始触摸屏幕时
  • onTouchMoved触摸屏幕,同时在屏幕上移动时
  • onTouchEnded结束触摸屏幕时

键盘事件

  对于桌面游戏,一般需要通过键盘做一些游戏内的控制,这时你就需要监听键盘事件。Cocos2d-x支持键盘事件。

  创建键盘事件监听器:

//创建一个键盘监听事件
auto listener = EventListenerKeyboard::creat();

listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed,this);
listener->onKeyReleased = CC_CALLBACK_2(KeyboradTest::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);
}

  可以看到,在使用键盘事件监听器时,可以监听两种不同的事件,每一个事件都有自己的触发时机。

  两种事件及触发时机:

  • onKeyPressed按键被按下时
  • onKeyReleased按下状态的按键被放开时

加速度传感器事件

  现在一些移动设备配备由加速度传感器,我们可以通过监听它的事件获取各方向的加速度。

  可以设想要完成一个游戏情景:通过来回移动手机,平衡小球在手机中的位置。这种场景的完成,就需要监听加速度传感器事件。

  使用加速度传感器,需要先启用

Device::setAccelerometerEnabled(true);

  创建加速度传感器监听器:

//创建一个加速度传感器事件
auto listener = EventListenerAcceleration::create(CC_CALLBACK_2(AccelecerometerTest::onAcceleration,this));

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);

//加速度传感器回调函数原型的实现
void AccelerometerTest::onAcceleration(Acceleration* acc,Event* evnet)
{
    //TODO
}

鼠标事件

  Cocos2d-x支持响应鼠标事件。

  创建鼠标事件监听器:

_mouseListener = EventListenerMouse::create();
_mouseListener->onMouseMove = CC_CALLBACK_2(MouseTest::onMouseMove,this);
_mouseListener->onMouseUp = CC_CALLBACK_2(MouseTest::onMouseUp,this);
_mouseListener->onMouseDown = CC_CALLBACK_2(MouseTest::onMouseDown,this);
_mouseListener->onMouseScroll = CC_CALLBACK_2(MouseTest::onMouseScroll,this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this);

void MouseTest::onMouseDown(Event* event)
{
    EventMouse* e = (EventMouse*)event;
    string str = "Mouse Down detected,Key:";
    str += tostr(e->getMouseButton());
}

void MouseTest::onMouseUp(Event *event)
{
    EventMouse* e = (EventMouse*)event;
    string str = "Mouse Up detected, Key: ";
    str += tostr(e->getMouseButton());
}

void MouseTest::onMouseMove(Event *event)
{
    EventMouse* e = (EventMouse*)event;
    string str = "MousePosition X:";
    str = str + tostr(e->getCursorX()) + " Y:" + tostr(e->getCursorY());
}

void MouseTest::onMouseScroll(Event *event)
{
    EventMouse* e = (EventMouse*)event;
    string str = "Mouse Scroll detected, X: ";
    str = str + tostr(e->getScrollX()) + " Y: " + tostr(e->getScrollY());
}

自定义事件

  自定义事件不是由系统控制触发的,而是通过代码手动触发。

  创建自定义事件监听器:

_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->addEventListenerWithSceneGraphPriority(_listener,this);

  上述制作了一个自定义事件监听器,并预设了响应方法。下面创建自定义事件,并手动分发:

static int count = 0;
++count;

char* buf[10];
sprintf(buf,"%d",count);

EventCustom event("game_custom_event1");
event.setUserData(buf);

_eventDispatcher->dispatchEvent(&event);

  示例创建了一个自定义事件(EventCustom)对象,并设置了UserDat,然后调用_eventDispatcher->dispatchEvent(&event)进行手动事件分发。当预定义的事件监听器,收到此事件,将会触发对应的响应函数。响应函数中可以获取到事件分发时设置的UserData完成数据处理。

进阶话题

注册事件监听

  当我们需求多个节点对象有相同的事件响应时,可以创建一个事件监听器,然后通过eventDispatcher,将其注册到多个对象。

  以触摸事件监听器为例:

//增加事件监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1,sprite1);

  需要注意的是,在添加到多个对象时,需要使用clone()方法。

//增加事件监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1,sprite1);

//增加相同的事件监听器到多个对象
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),sprite2);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),sprite3);

移除事件监听

  按照下面的方法,可以将已经添加的事件监听器移除。

_eventDispatcher->removeEventListener(listener);
举报

相关推荐

0 条评论