cocox2dx 3.2的事件系统是基于观察者模式,又称订阅者模式来实现的。

观察者/订阅者模式

概述

观察者模式定义了一种一对多的依赖关系,多个观察者(订阅者)对象同时监听某一状态对象。这个对象的状态改变后,会通知所有(或者选择性的)观察者对象。

实现方式

参与实现该模式的模型包括触发者、响应者、事件分发器。程序运行中,触发者向事件分发器发送一种类型的状态改变消息,事件分发器获取到状态消息时,检查是否有响应者已经订阅过此消息,如果有,则转发给相应的响应者去处理该消息。如果没有,则不做任何处理。

优缺点

优点:
1,减少了模块之间的耦合度。
2,程序运行中动态的决定是否响应某个事件。
3,代码层次更为清晰,模块独立性更好,有利于单元测试。
缺点:
事件分发器发送状态消息时,会涉及到响应者的排序,查询等操作,当需要更新的状态比较多时,影响程序的性能,尤其是游戏中有每帧都有很多UI状态要改变时,比较影响实时性能。

cocos2dx 3.2的事件机制

cocos2dx 3.2中把触摸、键盘、鼠标、加速度、重力感应、焦点改变、以及用户自定义的消息事件类全部继承自了EventListener类,使用起来更为方便。
/**
 *  The base class of event listener.
 *  If you need custom listener which with different callback,you need to inherit this class.
 *  For instance,you Could refer to EventListeneracceleration,EventListenerKeyboard,EventListenerTouchOneByOne,EventListenerCustom.
 */
class EventListener : public Ref
{
public:
    enum class Type
    {
        UNKNowN,TOUCH_ONE_BY_ONE,TOUCH_ALL_AT_ONCE,KEYBOARD,MOUSE,acceleration,FOCUS,#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
		GAME_CONTROLLER,#endif
        CUSTOM
    };

    typedef std::string ListenerID;

protected:
    /** Constructor */
    EventListener();

    /** Initializes event with type and callback function */
    bool init(Type t,const ListenerID& listenerID,const std::function<void(Event*)>& callback);
EventListener类中有三个开发者需要了解的类型:
Type,即事件类型,是触摸消息还是键盘消息,或者是开发者自定义的消息。只有七种类型,分别是单点触摸,多点触摸,键盘事件,鼠标事件,重力加速度消息,焦点改变消息,以及开发者自定义消息。这里使用的CUSTOM消息,其实是跟2.x版本中的NotificationCenter使用效果是一样的。
listenerID,是为了区分具体的响应者。除了CUSTOM类型以外,其他类型listenerID和type都是唯一一个。CUSTOM类型,listenerID是创建时开发者自己定义的,EventListener接收到带有listnerID的CUSTOM类型消息时,会根据listnerID查找相应的响应者处理,对应下面接口中的eventName。
EventListenerCustom* Eventdispatcher::addCustomEventListener(const std::string &eventName,const std::function<void(EventCustom*)>& callback)
{
    EventListenerCustom *listener = EventListenerCustom::create(eventName,callback);
    addEventListenerWithFixedPriority(listener,1);
    return listener;
}
callback,响应者的消息处理函数。

触摸事件的使用方式

3.x版本中的触摸分为两种类型,多点触摸:EventListenerTouchAllAtOnce,单点触摸:EventListenerTouchOneByOne。

EventListenerTouchAllAtOnce

const std::string EventListenerTouchAllAtOnce::LISTENER_ID = "__cc_touch_all_at_once";
class EventListenerTouchAllAtOnce : public EventListener
{
public:
    static const std::string LISTENER_ID;
    
    static EventListenerTouchAllAtOnce* create();
    virtual ~EventListenerTouchAllAtOnce();
    
    /// Overrides
    virtual EventListenerTouchAllAtOnce* clone() override;
    virtual bool checkAvailable() override;
    //
public:
    std::function<void(const std::vector<Touch*>&,Event*)> ontouchesBegan;
    std::function<void(const std::vector<Touch*>&,Event*)> ontouchesMoved;
    std::function<void(const std::vector<Touch*>&,Event*)> ontouchesEnded;
    std::function<void(const std::vector<Touch*>&,Event*)> ontouchesCancelled;

多点触摸继承自EventListener,TYPE为TOUCH_ALL_AT_ONCE,listener_ID为,__cc_touch_all_at_once,从ontouchesBegan方法中可以看出,这里是一次处理了多个触摸点的消息。

EventListenerTouchOneByOne

const std::string EventListenerTouchOneByOne::LISTENER_ID = "__cc_touch_one_by_one";
class EventListenerTouchOneByOne : public EventListener
{
public:
    static const std::string LISTENER_ID;
    
    static EventListenerTouchOneByOne* create();
    
    virtual ~EventListenerTouchOneByOne();
    
    void setSwallowtouches(bool needSwallow);
    bool isSwallowtouches();
    
    /// Overrides
    virtual EventListenerTouchOneByOne* clone() override;
    virtual bool checkAvailable() override;
    //

public:
    std::function<bool(Touch*,Event*)> onTouchBegan;
    std::function<void(Touch*,Event*)> onTouchMoved;
    std::function<void(Touch*,Event*)> onTouchEnded;
    std::function<void(Touch*,Event*)> onTouchCancelled;
单点触摸的实现方式也是继承自EventListener,TYPE为TOUCH_ONE_BY_ONE,listener_ID为__cc_touch_one_by_one,这里是将多个触摸消息按照触发顺序依次响应,例如如果同时在屏幕上按了四个点,则触摸响应函数会触发四次。onTouchBegan是需要注意的一个函数,返回值是bool,程序至少得实现这个函数,否则无法接收到触摸消息。返回值为false的时候,onTouchMoved,onTouchEnded,onTouchCancelled则不再执行,触摸消息直接传递给下一个接收者。2.x版本的触摸当这个函数返回true时表示吞噬触摸消息,不再往下传递。3.x版本需要设置setSwallowTouched为true,则触摸消息不再往下传递。在此事件中需要 处理两个按钮不能同时响应的问题。
触摸的另一个问题是如何控制触摸响应的顺序,触摸响应的顺序根响应的优先级有关。如下是创建触摸的两个通用函数:
    /** Adds a event listener for a specified event with the priority of scene graph.
     *  @param listener The listener of a specified event.
     *  @param node The priority of the listener is based on the draw order of this node.
     *  @note  The priority of scene graph will be fixed value 0. So the order of listener item
     *          in the vector will be ' <0,scene graph (0 priority),>0'.
     */
    void addEventListenerWithSceneGraPHPriority(EventListener* listener,Node* node);

    /** Adds a event listener for a specified event with the fixed priority.
     *  @param listener The listener of a specified event.
     *  @param fixedPriority The fixed priority of the listener.
     *  @note A lower priority will be called before the ones that have a higher value.
     *        0 priority is forbidden for fixed priority since it's used for scene graph based priority.
     */
    void addEventListenerWithFixedPriority(EventListener* listener,int fixedPriority);
第一个接口,是根据node元素的绘制顺序来决定触摸优先级,元素越晚绘制,即元素的zorder越高,则优先级越高。即使动态改变了node元素的层级关系,触摸也能正常响应。接口注释中也写得比较清楚,接口会默认把元素的优先级设置为0。触摸分发时,先分发优先级小于0的,然后再分发等于0的,即是根据元素层级关系来分发,最后分发大于0的。元素移除时,会自动移除相关联的触摸监听者。
第二个接口,是直接设置了触摸响应的优先级,可以设置除了0之外的优先级。优先级越低,触摸响应越早。即按照优先级从小到大的顺序分发。

触摸使用示例:

auto touchListener = EventListenerTouchOneByOne::create();
		touchListener->onTouchBegan = CC_CALLBACK_2(RoomLayer::onTouchBegan,this);
		touchListener->onTouchEnded = CC_CALLBACK_2(RoomLayer::onTouchEnd,this);
		touchListener->onTouchCancelled = CC_CALLBACK_2(RoomLayer::onTouchCancle,this);
		touchListener->setSwallowtouches(true);
		_eventdispatcher->addEventListenerWithSceneGraPHPriority(touchListener,btn);

开发者自定义事件使用示例:

这是监听游戏从后台进入前台时的消息,其他的事件消息类似使用方式。
	auto toForegroundListener = EventListenerCustom::create(EVENT_COME_TO_FOREGROUND,[this](EventCustom* event)
	{
		onTouchEnded(nullptr,nullptr);
	});
	_eventdispatcher->addEventListenerWithSceneGraPHPriority(toForegroundListener,this);

cocos2dx 3.2 新的事件分发机制 观察者/订阅者模式的更多相关文章

  1. ios – Objective-C管理观察者的设计模式

    有一种方法来检测UI控制器是否由父控制器发布,而不使用viewWilldisappear方法?有最好的做法来解决这种情况吗?

  2. Swift设计模式之观察者模式

    转自Swift设计模式原文Design-Patterns-In-Swift

  3. 观察者模式 swift

    在MVC里,观察者模式意味着需要允许Model对象和View对象进行交流,而不能有直接的关联。Cocoa使用两种方式实现了观察者模式:Notification和Key-ValueObserving。Apple对于通知的使用很频繁,比如当键盘弹出或者收起的时候,系统会分别发送UIKeyboardWillShowNotification/UIKeyboardWillHideNotification的通知。在LibaratyAPI.swift里加上取消订阅的代码:deinit{NSNotificationCen

  4. KVO原理分析及使用进阶

    本篇文章对KVO的实现原理进行了详细的分析,并且简单的实现了一个KVO,来当做技术交流。概述KVO全称keyvalueObserving,是苹果提供的一套事件通知机制。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。实际应用KVO主要用来做键值观察操作,想要一个值发生改变后通知另一个对象,则用KVO实现最为合适。下面是KVO前后打印的关键信息,我们在下面做详细分析。

  5. 浅谈Nodejs观察者模式

    这篇文章主要介绍了浅谈Nodejs观察者模式的相关资料,需要的朋友可以参考下

  6. PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】

    这篇文章主要介绍了PHP中常用的三种设计模式,结合实例形式详细分析了php单例模式、工厂模式与观察者模式概念、功能、相关使用技巧与操作注意事项,需要的朋友可以参考下

  7. 深入理解Javascript中的观察者模式

    观察者模式又称发布订阅模式,是一种最常用的设计模式之一了。下面这篇文章主要给大家深入的介绍了Javascript中观察者模式的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。

  8. PHP设计模式的策略,适配器和观察者模式详解

    这篇文章主要为大家详细介绍了PHP设计模式的策略,适配器和观察者模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  9. PHP设计模式之观察者模式入门与应用案例详解

    这篇文章主要介绍了PHP设计模式之观察者模式入门与应用,结合具体案例形式详细分析了PHP观察者模式的相关概念、原理、使用方法及操作注意事项,需要的朋友可以参考下

  10. 详解Android观察者模式的使用与优劣

    这篇文章主要介绍了Android观察者模式的相关资料,帮助大家更好的理解和学习Android的设计模式,感兴趣的朋友可以了解下

随机推荐

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

返回
顶部