在移动平台中设备与用户的交互必须通过事件处理完成。用户输入被封装为事件,Cocos2d-x游戏引擎能够接收并处理这些事件,包括触摸事件、键盘事件、鼠标事件、加速度事件和自定义事件等。这里需要注意,不同平台之间事件略有差异,这与硬件有关,如在iOS
平台就无法接收键盘事件,在PC和Mac OS X平台无法接收触摸事件和加速度事件。

Cocos2d-x 用户事件处理机制
一般来说,事件处理机制都有三个角色:事件、事件源和事件处理,其中事件源是事件发生的场所,通常指控件或视图;事件处理者是接收事件并对其进行响应处理。

(1) 事件:

事件类是Event,它的子类主要有:

EventTouch(触摸事件)
EventKeyBoard(键盘事件)
EventMouth(鼠标事件)
Eventacceleration(加速度事件)
EventCustom(自定义事件)

(2) 事件源:

指的是Cocos2d-x中的精灵、层和菜单等节点对象。

(3) 事件处理:

Cocos2d-x中的事件处理者是事件监听类EventListener,它的子类主要有:

EventListenerTouchOneByOne(单点触摸监听器)
EventListenerTouchAllAtOnce(多点触摸监听器)
EventListenerKeyBoard(键盘事件监听器)
EventListenerMouse(鼠标事件监听器)
EventListeneracceleration(加速度事件监听器)
EventListenerCustom(自定义事件监听器)

1.事件分发器

事件的监听和事件具有对应关系,Cocos2d-x提供了一个事件分发器(Eventdispatcher)用于管理这种关系。
Eventdispatcher类采用的是单例模式,可以通过Director::getInstance()->getEventdispatcher()获得事件分发对象。

Eventdispatcher类中注册事件监听器到事件的函数如下:
(1)指定固定的事件优先级注册监听器,事件优先级决定事件响应的优先级,值越小优先级越高。

void addEventListenerWithFixedPriority(EventListener * listener,int fixedPriority)

(2)把一些控件的显示优先级作为事件优先级,越上层的精灵或层越先响应事件。

void addEventListenerWithSceneGraPHPriority(EventListener * listener,Node * node)

当不再进行事件响应时,需要注销事件监听器。主要的注销函数如下:

(1)注销指定事件监听器

void removeEventListener(EventListener * listener)

(2)注销自定义事件监听器

void removeCustomEventListener(EventListener * listener)

(3)注销所有事件监听,注意:使用该函数之后,菜单也不能响应事件了,因为它需要接收触摸事件。

void removeAllEventListeners(EventListener * listener)

2.事件

下面主要介绍五类事件:

2.1 触摸事件

触摸事件可以有“按下”、“移动”和“抬起”的阶段,表示触摸的开始、移动和结束状态。另外,触摸事件的不同阶段都有单点触摸和多点触摸,具体还得看平台和设备。

(1)EventListenerTouchOneByOne(单点触摸监听器)

单点触摸事件中的响应属性:

1)当一个手指触摸屏幕时回调该属性的指定函数。如果返回为true,则可以回调后面两个属性所指定的函数,否则不回调。

std::function<bool(Touch *,Event *)> onTouchBegan

2)当一个手指在屏幕移动时回调该属性所指定的函数。

std::function<void(Touch *,Event *)> onTouchMoved

3)当一个手指离开屏幕时回调该属性所指定的函数。

std::function<void(Touch *,Event *)> onTouchEnded

4)当单点触摸事件被取消时回调该属性所指定的函数

std::function<void(Touch *,Event *)> onTouchCancelled

(2)EventListenerTouchAllAtOnce(多点触摸监听器)

多点触摸事件中的响应属性:

1)当多个手指触摸屏幕时回调该属性的指定函数。如果返回为true,则可以回调后面两个属性所指定的函数,否则不回调。

std::function<void(const std::vector<Touch * >&,Event *)> ontouchesBegan

2)当多个手指在屏幕移动时回调该属性所指定的函数。

std::function<void(const std::vector<Touch * >&,Event *)> ontouchesMoved

3)当多个手指离开屏幕时回调该属性所指定的函数。

std::function<void(const std::vector<Touch * >&,Event *)> ontouchesEnded

4)当多点触摸事件被取消时回调该属性所指定的函数

std::function<void(const std::vector<Touch * >&,Event *)> ontouchesCancelled

另外,每个触摸点(touch)对象包含了当前位置信息,以及之前的位置信息。
下面的函数是可以获得触摸点之前的位置信息:

Vec2 getPrevIoUsLocationInView()    //UI坐标
Vec2 getPrevIoUsLocation()      //OpenGL坐标

下面的函数是可以获得触摸点当前的位置信息:

Vec2 getLocationInView()    //UI坐标
Vec2 getLocation()      //OpenGL坐标

接下来是一个简单单点触摸示例:

//一般来说监听器在onEnter时注册
void HelloWorld::onEnter()
{
    Layer::onEnter();
    auto listener = EventListenerTouchOneByOne::create();
    listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::touchBegan,this);
    listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::touchMoved,this);
    listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::touchEnded,this);

    Eventdispatcher * eventdispatcher = Director::getInstance()->getEventdispatcher();
    //参数为Node类型,故需要用getChildByTag函数获取节点
    eventdispatcher->addEventListenerWithGraPHPriority(listener,getChildByTag(tagA));    
    /* 当一个事件监听器需要重复利用时,需要用clone()方法创建一个新的克隆,因为在使用addEventListenerWithSceneGraPHPriorith或者addEventListenerWithFixedPriority方法进行注册时,会对当前使用的事件监听器添加一个已注册的标记,这使得它不能够被添加多次。 */
    eventdispatcher->addEventListenerWithGraPHPriority(listener->clone(),getChildByTag(tagB)); 
    eventdispatcher->addEventListenerWithGraPHPriority(listener->clone(),getChildByTag(tagC)); 
}

bool HelloWorld::touchBegan(Touch * touch,Event * event)
{
    auto target = static_cast<Sprite *>(event->getCurrentTarget());
    Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
    Size s = target->getContentSize();
    Rect rect = Rect(0,0,s.width,s.height);
    //判断单击是否在范围内
    if(rect.containsPoint(locationInNode))
    {
    target->runAction(ScaleBy::create(1.5f,1.5f));
    ...
    return true;//吞没事件
    }
    return false;
}

void HelloWorld::touchMoved(Touch * touch,Event * event)
{
    auto target = static_cast<Sprite *>(event->getCurrentTarget());
    target->setPosition(target->getPosition() + touch->getDelta());
}

void HelloWorld::touchEnded(Touch * touch,s.height);

    if(rect.containsPoint(locationInNode))
    {
    target->runAction(Scaleto::create(1.0f,1.0f));
    ...
    return true;
    }
}

其中,CC_CALLBACK_2(HelloWorld::touchBegan,this) 是使用CC_CALLBACK_2宏绑定回调函数。

2.2 键盘事件

键盘事件监听器是EventListenerKeyboard,其中的事件响应属性有:

(1)按键按下时回调该属性所指定函数。

std::function<void(EventKeyboard::KeyCode,Event *)> onKeypressed

(2)按键抬起时回调该属性所指定函数。

std::function<void(EventKeyboard::KeyCode,Event *)> onkeyreleased

键盘事件处理的代码片段如下,这里使用Lambda表达式,之后会介绍:

void HelloWorld::onEnter()
{
    Layer::onEnter();
    auto listener = EventListenerKeyboard::create();
    //EventKeyboard::KeyCode 是按键号
    listener->onKeypressed = [](EventKeyboard::KeyCode keyCode,Event * event)
    {
    ...
    };
    listener->onkeyreleased = [](EventKeyboard::KeyCode keyCode,Event * event)
    {
    ...
    };

    Eventdispatcher * eventdispatcher = Director::getInstance()->getEventdispatcher();

    eventdispatcher->addEventListenerWithGraPHPriority(listener,this);    
}

2.3 鼠标事件

鼠标事件监听器是EventListenerMouse,其中的事件响应属性有:
(1)当鼠标键按下时回调该属性所指定的函数。

std::function<void(Event * event)> onMouseDown

(2)当鼠标移动时回调该属性所指定的函数。

std::function<void(Event * event)> onMouseMove

(3)当鼠标滚动时回调该属性所指定的函数。

std::function<void(Event * event)> onMouseScroll

(4)当鼠标键抬起时回调该属性所指定的函数。

std::function<void(Event * event)> onmouseup

鼠标事件处理的代码片段如下,这里使用Lambda表达式,之后会介绍:

void HelloWorld::onEnter()
{
    Layer::onEnter();
    auto listener = EventListenerMouse::create();

    listener->onMouseMove = [](Event * event)
    {
        EventMouse * e = (EventMouse *)event;
        ...
    };
    listener->onmouseup = [](Event * event)
    {
        EventMouse * e = (EventMouse *)event;
        ...
    };
    listener->onMouseScroll = [](Event * event)
    {
        EventMouse * e = (EventMouse *)event;
        ...
    };
    listener->onMouseDown = [](Event * event)
    {
        EventMouse * e = (EventMouse *)event;
        ...
    };

    Eventdispatcher * eventdispatcher = Director::getInstance()->getEventdispatcher();

    eventdispatcher->addEventListenerWithGraPHPriority(listener,this);    
}

2.4 加速度事件

大多数的移动设备都支持加速度计传感器,加速度计传感器是一种能够感知设备一个方向上线性加速度的传感器。iOS和安卓设备三轴加速度计的坐标系是右手坐标系。

加速度计三维坐标系

使用事件分发器之前需要注册加速度事件监听器,在此之前还需先启用此设备硬件设备:

Device::setAccelerometerEnabled(true);

加速度事件监听器是EventListeneracceleration,与其他事件监听器不同的是,它没有事件响应属性,事件响应是通过静态create指定的。代码如下:

static EventListeneracceleration * create(std::function<void(acceleration *,Event *)>callback)

下面是示例片段:

void HelloWorld::onEnter()
{
    Layer::onEnter();
    Device::setAccelerometerEnabled(true);
    auto listener = EventListeneracceleration::create([](acceleration * acc,Event * event)
    {
    ...
    });
    Eventdispatcher * eventdispatcher = Director::getInstance()->getEventdispatcher();
    eventdispatcher->addEventListenerWithGraPHPriority(listener,this); 
}

2.5 自定义事件

上面的事件类型是系统已经定义了的,而且事件(例如触摸屏幕,按键响应)是由系统自动触发的。另外,你可以制作你自己的custom events ,它们可以不由系统触发,但是必须通过你的代码,如下:

_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 对象,并且设置了他的 UserData。之后,它被 _eventdispatcher->dispatchEvent(&event);手动的分发。它将触发之前定义好的事件处理方法。

3.Lambda表达式

在Cocos2d-x 3.0之后提供了对C++11标准的支持,其中的Lambda表达式使用起来十分简洁。

对上一节的代码进行替换:

listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
...
bool HelloWorld::onTouchBegan(Touch * touch,Event * event)
{
    ....
    return false;
}

替换为:

listener->onTouchBegan = [](Touch * touch,Event * event)
{
    ...
    return false;
};

上面语句中的[](Touch * touch,Event * event){…}就是Lambda表达式,Lambada表达式就是JavaScript语言中的匿名函数,它可以直接声明函数而不需要独立声明。

替换为Lambda表达式之后之前的头文件代码也可以修改的比较简洁。

4.在层中进行的事件处理

层是节点的派生类,可以在层中响应事件处理,Cocos2d-x中为Layer又定义了一些与事件相关的函数。

单点触摸相关函数:

(1)bool onTouchBegan(Touch * touch,Event * event)
(2)void onTouchCancelled(Touch * touch,Event * event)
(3)void onTouchEnded(Touch * touch,Event * event)
(4)void onTouchMoved(Touch * touch,Event * event)

多点触摸相关函数:

(1)void ontouchesBegan(const std::vector<Touch * >&touches,Event * event)
(2)void ontouchesCancelled(const std::vector<Touch * >&touches,Event * event)
(3)void ontouchesEnded(const std::vector<Touch * >&touches,Event * event)
(4)void ontouchesMoved(const std::vector<Touch * >&touches,Event * event)

键盘事件相关函数:

(1)void onKeypressed(EventKeyboard::KeyCode keyCode,Event * event)
(2)void onkeyreleased(EventKeyboard::KeyCode keyCode,Event * event)

加速度事件相关函数:

void onacceleration(acceleration * acc,Event * event)

注意,若使用层的事件处理,需要在层的头文件中定义相关函数,由于是重写,需要在前面加上virtual关键字,且函数名需与父类一致。

有关事件的初始化可以放在onEnter函数或者init函数中,还需加入以下代码:

//使层开始支持触摸事件
setTouchEnabled(true);
//设置单点触摸,多点触摸是Touch::dispatchMode::ALL_AT_ONCE
setTouchMode(Touch::dispatchMode::ONE_BY_ONE);

层中的触摸事件使用起来比较简单,由于事件监听的对象是层,而不是层中的精灵等对象,当判断是否单击了哪个精灵对象时比较麻烦,需要使用Rect的containsPoint函数逐一判断每个精灵对象。

可以看出,层中的事件处理比较简单,不需要注册事件监听器,不需要指定它的事件响应优先级,这种优点也是它的缺点,当处理多个精灵的触摸事件时就有些繁琐。

总结

我们了解了Cocos2d-x的用户输入事件处理,包括五类事件的注册和处理,希望能够很好的在开发过程中使用。

Cocos2d-x 用户事件处理机制的更多相关文章

  1. 详解使用postMessage解决iframe跨域通信问题

    这篇文章主要介绍了详解使用postMessage解决iframe跨域通信问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. HTML5手指下滑弹出负一屏阻止移动端浏览器内置下拉刷新功能的实现代码

    这篇文章主要介绍了HTML5手指下滑弹出负一屏阻止移动端浏览器内置下拉刷新功能的实现代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  4. 浅谈html5之sse服务器发送事件EventSource介绍

    本篇文章主要介绍了浅谈html5之sse服务器发送事件EventSource介绍,具有一定的参考价值,有兴趣的可以了解一下

  5. HTML5 拖放(Drag 和 Drop)详解与实例代码

    本篇文章主要介绍了HTML5 拖放(Drag 和 Drop)详解与实例代码,具有一定的参考价值,有兴趣的可以了解一下

  6. ios – Swift中的非响应流委托

    所以我在Swift中使用套接字并试图将应用程序与我的服务器连接起来.我让应用程序连接到服务器的IP地址,并在服务器上使用netcat进行测试.在执行期间,应用程序的控制台输出显示它已成功连接到服务器.但是,流委托似乎没有响应.当我输入netcat时,app控制台没有打印任何内容.我已经搜索了很长一段时间,发现我的实现与其他实现非常相似.也许我在这里遗漏了一些我看不到的东西.任何想到这个问题的人都将不胜感激!

  7. ios – UIScrollView内容不允许用户交互

    我有一个启用了分页的UIScrollView,如下所示:在UIScrollView中,我添加了几个UIWebViews,并将其启用的交互设置为是这样的.它打破了UIScrollView上的分页和所有触摸.如果我将用户交互设置为NO,则页面有效,但我无法在UIWebView中突出显示文本.我试着像下面那样对UIScrollView进行子类化,但是会出现同样的情况.任何的想法?

  8. ios – 如何知道用户在iPhone中的播放控件上单击快进和快退按钮

    还是有其他方法吗?

  9. 使用iOS 7获取后台步骤

    我正在开发一个应用程序,在其中我应该获得我在体育活动中所做的步骤数.我找到了这段代码:使用此代码,当iPhone的显示器打开时,它工作得很好,但是当我关闭显示器时,它不再起作用.为了跟踪位置,我在iOS7中看到了一个功能“后台模式”.使用此功能,我可以在iPhone显示屏关闭时获取坐标.现在我要在显示器关闭时获取加速度计值,我该怎么做?我在网上看到iOS不允许在后台模式下使用加速度计,我如何在后台模式下使用加速度计来计算步数?

  10. ios – 如何在使用隐式动画为CALayer设置动画时继承动画属性

    我试图使用隐式动画在CALayer上设置自定义属性的动画:在-actionForKey:方法我需要返回动画,负责插值.当然,我必须以某种方式告诉动画如何检索动画的其他参数.有关如何实现这一点的任何想法?

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部