【cocos2d-x 源码解析】事件系统

本文深入解析cocos2d-x 3.x的事件系统,包括事件(Event)、事件监听器(EventListener)和事件分发器(EventDispatcher)。事件主要由事件分发器派发,事件监听器接收到事件后执行回调函数处理。事件监听器包含固定优先级和依赖节点的监听器,事件分发器负责管理监听器的注册、移除、暂停和恢复。文章详细介绍了事件的创建、监听器的注册与回调,以及事件分发过程。
摘要由CSDN通过智能技术生成

事件系统

cocos2d-x 3.x 的事件比 2.x 要好用很多,也比较简单,主要由三部分组成:事件分发器 EventDispatcher、事件监听器 EventListener 和事件 Event

cocos2d-x 3.x 所有与事件相关的文件都在 cocos/base 模块下。

事件 Event

事件在现实中的意思是发生了一件事,当事情发生之后会有人去做一些处理;在应用程序中事件可以看作是一个带有数据的实体,而事件监听器就是事情发生之后做一些处理工作的人;派发事件就是将事件这个实体派发出去,告诉大家发生了这个事情,然后事件监听器会监听到事件触发,接收事件这个实体,取到事件中的数据,做相应的处理。

在这里事件可以简单地看成一个数据体,它在整个事件系统中的作用是传送数据,事件派发器将事件派发出去,事件监听器接收到这个数据,然后把事件中的数据取出来,进行下一步操作。事件的基类是 Event,它的定义很简单,只定义了几个属性

class CC_DLL Event : public Ref
{
public:
    /** Type Event type.*/
    enum class Type
    {
        TOUCH,
        KEYBOARD,
        ACCELERATION,
        MOUSE,
        FOCUS,
        GAME_CONTROLLER,
        CUSTOM
    };

public:
    //function
protected:
    Type _type;     ///< Event type
    bool _isStopped;       ///< whether the event has been stopped.
    Node* _currentTarget;  ///< Current target

    friend class EventDispatcher;
};

Event 类只声明了事件类型 _type,事件是否停止 _isStopped,事件附加的目标结点 _currentTarget 这三个属性。其中,事件类型共有七种,分别是 触摸事件、键盘事件、加速计事件、鼠标事件、焦点事件、手柄事件和自定义事件。具体事件类在 Event 的基础上多定义了几个属性而已,比如键盘事件 EventKeyboard 就多定义了两个属性,_keyCode 表示按下的键值,_isPressed 表示是按下还是松开

class CC_DLL EventKeyboard : public Event
{
public:
    //function
protected:
    KeyCode _keyCode;
    bool _isPressed;

    friend class EventListenerKeyboard;
};

事件监听器 EventListener

事件监听器作为处理事件的“人“,负责监听事件的发生,并调用相应的回调函数来处理事件。

class CC_DLL EventListener : public Ref
{
public:
    /** Type Event type.*/
    enum class Type
    {
        UNKNOWN,
        TOUCH_ONE_BY_ONE,
        TOUCH_ALL_AT_ONCE,
        KEYBOARD,
        MOUSE,
        ACCELERATION,
        FOCUS,
        GAME_CONTROLLER,
        CUSTOM
    };

    typedef std::string ListenerID;

public:
    bool init(Type t, const ListenerID& listenerID, const std::function<void(Event*)>& callback);
    virtual bool checkAvailable() = 0;
    //...

protected:
    std::function<void(Event*)> _onEvent;   /// Event callback function

    Type _type;                             /// Event listener type
    ListenerID _listenerID;                 /// Event listener ID
    bool _isRegistered;                     /// Whether the listener has been added to dispatcher.

    int   _fixedPriority;   // The higher the number, the higher the priority, 0 is for scene graph base priority.
    Node* _node;            // scene graph based priority
    bool _paused;           // Whether the listener is paused
    bool _isEnabled;        // Whether the listener is enabled
    friend class EventDispatcher;
};
  • _fixedPriority 表示事件的优先级,_node 表示事件依赖的场景结点,这两个属性是对立的,分别对应两种添加事件监听器的方式,一种是事件监听器依赖于场景结点,则需要保存这个结点(_node),这时事件不需要额外定义优先级;另一种是事件监听器注册在全局中,则需要定义事件的优先级(_fixedPriority)
  • _paused 表示当前监听器是否被暂停,_isEnabled 表示监听器是否启用,_isRegistered 表示监听器是否已注册,每个监听器只能注册一次,如果要重复注册,必须使用 clone 方法创建一个新的副本
  • _type 表示事件监听器的类型,这个类型和事件的类型要区分开,事件监听器有自己的一个类型,事件也有自己的类型,这两个类型有对应关系,但它们是两个不同的数据;_listenerID 表示监听器的唯一 ID,这是个字符串,在保存监听器到 map 时用作 key 值,这个 ID 在具体的事件监听器子类中定义
  • _onEvent 是事件回调函数,当事件触发时,这个函数将被调用

EventListener 也比较简单,比较重要的两个函数是 init 方法和 checkAvaliable 方法

bool EventListener::init(Type t, const ListenerID& listenerID, const std::function<void(Event*)>& callback)
{
    _onEvent = callback;
    _type = t;
    _listenerID = listenerID;
    _isRegistered = false;
    _paused = true;
    _isEnabled = true;

    return true;
}

bool EventListener::checkAvailable()
{ 
    return (_onEvent != nullptr);
}

init 方法初始化几个属性,checkAvaliable 方法检查回调函数是否为空,如果为空,则不能注册监听器,因为没有回调函数,监听器即使监听到事件发生也无法处理事件。这两个方法在基类没看到调用的地方,init 方法在子类初始化的时候会调用,而 checkAvaliable 方法则在注册事件监听器的时候调用。

下面还是以键盘事件为例,看一下具体的事件监听器类做了哪些事件

class CC_DLL EventListenerKeyboard : public EventListener
{
public:
    static const std::string LISTENER_ID;

    /** Create a keyboard event listener.
     * 
     * @return An autoreleased EventListenerKeyboard object.
     */
    static EventListenerKeyboard* create();

    /// Overrides
    virtual EventListenerKeyboard* clone() override;
    virtual bool checkAvailable() override;

    std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed;
    std::function<void(EventKeyboard::KeyCode, Event*)> onKeyReleased;
CC_CONSTRUCTOR_ACCESS:
    EventListenerKeyboard();
    bool init();
};

EventListenerKeyboard 新定义了两个子回调事件 onKeyPressed 和 onKeyReleased,这个函数参数是对外公开的,由外部进行赋值;这两个子回调函数将由父类定义的回调函数 _onEvent 调用(看下面的 init 方法)。

EventListenerKeyKeyboard 的 init 方法首先会定义回调函数,然后调用父类的 init 方法,将事件类型、事件 ID 和回调函数传过去,做父类属性初始化。

bool EventListenerKeyboard::init()
{
    auto listener = [this](Event* event){
        auto keyboardEvent = static_cast<EventKeyboard*>(event);
        if (keyboardEvent->_isPressed)
        {
            if (onKeyPressed != nullptr)
                onKeyPressed(keyboardEvent->_keyCode, event);
        }
        else
        {
            if (onKeyReleased != nullptr)
                onKeyReleased(keyboardEvent->_keyCode, event);
        }
    };

    if (EventListener::init(Type::KEYBOARD, LISTENER_ID, listener))
    {
        return true;
    }

    return false;
}

init 方法定义了回调函数 _onEvent,_onEvent 会调用 onKeyPressed 或者 onKeyReleased 方法,所以 checkAvailable 方法不用再检查 _onEvent 是否为空,而是检查这两个子回调函数

bool EventListenerKeyboard::checkAvailable()
{
    if (onKeyPressed == nullptr && onKeyReleased == nullptr)
    {
        CCASSERT(false, "Invalid EventListenerKeyboard!");
        return false;
    }

    return true;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: cocos2d-x是一款流行的开游戏引擎,它可以用作开发本地移动游戏和桌面游戏。利用cocos2d-x游戏码,开发人员可以快速构建流畅、高效、具有吸引力的游戏。该引擎使用C ++语言和脚本语言Lua来实现游戏开发,用户可以根据自己的需要进行选择。 cocos2d-x游戏码包含许多强大的功能和工具,例如精灵、动画、场景管理、碰撞检测和音频控制等。通过这些功能,开发人员可以方便地创建各种类型的游戏,例如动作游戏、射击游戏、冒险游戏和益智游戏等。 此外,cocos2d-x游戏码还具有高度定制化的特性,允许开发人员根据他们的需求自定义游戏元素。这种定制化可以通过改进游戏画面,添加新的模式和关卡,甚至整个新的游戏玩法来完成。 总之,cocos2d-x游戏码是一款功能强大、易于使用和高度定制的游戏引擎,它可以帮助开发人员快速开发各种类型的游戏。无论你是专业开发人员还是无经验的游戏制作者,cocos2d-x都是一个极好的选择。 ### 回答2: Cocos2d-x游戏码是使用Cocos2d-x引擎进行开发的游戏程序代码。Cocos2d-x引擎是一个开的跨平台游戏引擎,可以支持iOS、Android、Windows Phone、Windows、MacOS和Linux等多个平台,并且提供了丰富的游戏开发API和工具集。Cocos2d-x游戏码包含了游戏的核心逻辑、UI设计、动画效果、音频效果等各方面的代码,可以作为开发者学习和借鉴的重要资料。 由于Cocos2d-x引擎支持多种编程语言(如C++、Lua等),因此Cocos2d-x游戏码也会有对应的编程语言版本。开发者可以通过阅读Cocos2d-x游戏码,了解游戏开发过程中的技术细节,学习如何使用Cocos2d-x引擎进行游戏开发。同时,开发者也可以通过对Cocos2d-x游戏码进行修改和优化,来满足游戏的特定需求,提升游戏的性能和用户体验。 总之,Cocos2d-x游戏码是游戏开发者必备的重要资,可以帮助开发者更好地了解游戏开发技术,提升游戏开发水平。 ### 回答3: cocos2d-x是一款优秀的游戏开发引擎,其码包含了许多功能强大的游戏开发工具和API。使用cocos2d-x可以帮助开发者更快速更高效地开发出优秀的游戏作品。 cocos2d-x的游戏码非常丰富,其包含了许多不同类型的游戏示例和模板,如平面射击、塔防、解谜等,这些示例可以帮助开发者更好地了解cocos2d-x的使用方法和原理。 cocos2d-x码还包含了许多强大的API和工具,例如场景管理、动画控制、音频引擎等,这些工具和API能够帮助开发者更好地完成游戏的开发和调试。 此外,cocos2d-x码还提供了完整的游戏开发框架,包括资管理、内存管理、事件机制等,这些框架可以帮助开发者更好地组织代码和提高代码的可维护性。 总的来说,cocos2d-x游戏码提供了丰富的工具和API,可以帮助开发者更高效地进行游戏开发,大大降低了开发难度和成本,是一款非常适合游戏开发者使用的引擎。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值