cocos3——11.事件分发

【纹理】

TextureCache::addImage

texture = new (std::nothrow) Texture2D(); // ref = 1, 没有autorelease

TextureCache::removeUnusedTextures

把引用计数是1的纹理释放掉

TextureCache::removeAllTextures

释放所有缓存的纹理

【事件】

分发顺序:优先级<0,场景图顺序(从前往后)(优先级=0),优先级>0

注册订阅者:

用场景图优先级方式添加,要绑定node,默认优先级为0

void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);

按固定优先级方式添加,不能设置优先级为0(因为0在上面用,有特殊意义)

void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);

添加的时候是放到一个map去:

std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;

而侦听id根据不同的事件类型获取的,每种事件对应一个字符串,而用户自定义事件则是事件的名字:

static EventListener::ListenerID __getListenerID(Event* event)
{
    EventListener::ListenerID ret;
    switch (event->getType())
    {
        case Event::Type::ACCELERATION:
            ret = EventListenerAcceleration::LISTENER_ID;
            break;
        case Event::Type::CUSTOM:
            {
                auto customEvent = static_cast<EventCustom*>(event);
                ret = customEvent->getEventName();
            }
            break;
        case Event::Type::KEYBOARD:
            ret = EventListenerKeyboard::LISTENER_ID;
            break;
        case Event::Type::MOUSE:
            ret = EventListenerMouse::LISTENER_ID;
            break;
        case Event::Type::FOCUS:
            ret = EventListenerFocus::LISTENER_ID;
            break;
        case Event::Type::TOUCH:
            // Touch listener is very special, it contains two kinds of listeners, EventListenerTouchOneByOne and EventListenerTouchAllAtOnce.
            // return UNKNOWN instead.
            CCASSERT(false, "Don't call this method if the event is for touch.");
            break;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        case Event::Type::GAME_CONTROLLER:
            ret = EventListenerController::LISTENER_ID;
            break;
#endif
        default:
            CCASSERT(false, "Invalid type!");
            break;
    }

    return ret;
}

暂停、恢复与节点相关的侦听

void resumeEventListenersForTarget(Node* target, bool recursive = false);

void pauseEventListenersForTarget(Node* target, bool recursive = false);

开关订阅者

inline void setEnabled(bool enabled)

inline bool isEnabled()

设置优先级

void setPriority(EventListener* listener, int fixedPriority);

分发事件:

void dispatchEvent(Event* event);

void dispatchCustomEvent(const std::string &eventName, void *optionalUserData = nullptr);

void EventDispatcher::dispatchEvent(Event* event)
{
    if (!_isEnabled)
        return;

    updateDirtyFlagForSceneGraph();

    DispatchGuard guard(_inDispatch);

    if (event->getType() == Event::Type::TOUCH)
    {
        dispatchTouchEvent(static_cast<EventTouch*>(event));
        return;
    }

    auto listenerID = __getListenerID(event);

    sortEventListeners(listenerID);

    auto iter = _listenerMap.find(listenerID);
    if (iter != _listenerMap.end())
    {
        auto listeners = iter->second;

        auto onEvent = [&event](EventListener* listener) -> bool{
            event->setCurrentTarget(listener->getAssociatedNode());
            listener->_onEvent(event);
            return event->isStopped();
        };

        dispatchEventToListeners(listeners, onEvent);
    }

    updateListeners(event);
}

分发的过程:先对标记为dirty的侦听者进行排序,然后根据事件的侦听id找到对应的侦听者集合,然后遍历处理。而处理的结果event->isStopped会影响该事件是否继续传递给其他侦听者。

void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
    bool shouldStopPropagation = false;
    auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
    auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();

    ssize_t i = 0;
    // priority < 0
    if (fixedPriorityListeners)
    {
        CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");

        if (!fixedPriorityListeners->empty())
        {
            for (; i < listeners->getGt0Index(); ++i)
            {
                auto l = fixedPriorityListeners->at(i);
                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }

    if (sceneGraphPriorityListeners)
    {
        if (!shouldStopPropagation)
        {
            // priority == 0, scene graph priority
            for (auto& l : *sceneGraphPriorityListeners)
            {
                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }

    if (fixedPriorityListeners)
    {
        if (!shouldStopPropagation)
        {
            // priority > 0
            ssize_t size = fixedPriorityListeners->size();
            for (; i < size; ++i)
            {
                auto l = fixedPriorityListeners->at(i);

                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 13:44:07

cocos3——11.事件分发的相关文章

cocos基础教程(11)事件分发机制

cocos3.0的事件分发机制: 创建一个事件监听器-用来实现各种触发后的逻辑. 事件监听器添加到事件分发器_eventDispatcher,所有事件监听器有这个分发器统一管理. 事件监听器有以下几种: 触摸事件 (EventListenerTouch) 键盘响应事件 (EventListenerKeyboard) 鼠标响应事件 (EventListenerMouse) 自定义事件 (EventListenerCustom) 加速记录事件 (EventListenerAcceleration)

Cocos2d-X 3.x 事件分发机制详解

事件分发机制 新事件分发机制:在2.x 版本事件处理时,将要触发的事件交给代理(delegate)处理,再通过实现代理里面的onTouchBegan等方法接收事件,最后完成事件的响应.而在新的事件分发机制中,只需通过创建一个事件监听器-用来实现各种触发后的逻辑,然后添加到事件分发器_eventDispatcher,所有事件监听器由这个分发器统一管理,即可完成事件响应.请参考更多3.0资料... 事件监听器有以下几种: 触摸事件 (EventListenerTouch) 键盘响应事件 (Event

图解 Android 事件分发机制

首发原文:http://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548149&idx=1&sn=709149df682c7d3a6e453c9ef0626a1f&chksm=f1180e08c66f871eb2e7e39e057a5b090214fd71adcd98aa36b3d7fcecf77ad5d08138c50131#rd 在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟

Android事件分发机制的学习

最近被Android事件分发机制折磨的很烦躁,网上各种博客资料看完觉得还是得自己写一篇,一方面加深理解,另一方面希望能帮助到也同样在学习相关知识的童鞋们. 话不多说,直接开整. 当用户的手指点击到屏幕,便是整个事件的开始. 首先获取到该事件的是view层的控制者Activity,具体怎么获得我们不得而知,在此也不追究,而继续我们的主题.Activity获得事件后便执行它自身的方法: public boolean dispatchTouchEvent(MotionEvent ev) { if (e

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用Ima

Cocos2d-x 3.x事件分发机制总结

在2.x中处理事件需要用到委托代理(delegate),相信学过2.x的触摸事件的同学,都知道创建和移除的流程十分繁琐.而在3.x中由于加入了C++11的特性,而对事件的分发机制通过事件分发器EventDispatcher 来进行统一的管理. 事件监听器主要有: 触摸事件     : EventListenerTouchOneByOne.EventListenerTouchAllAtOnce 鼠标响应事件 : EventListenerMouse 键盘响应事件 : EventListenerKe

自定义控件(视图)2期笔记14:自定义视图之View事件分发 dispatchTouchEvent,onTouch,onTouchEvent,onClick逻辑顺序过程

1. 这里我们先从案例角度说明dispatchTouchEvent,onTouch,onTouchEvent,onClick逻辑顺序过程: (1)首先我们重写一个MyButton 继承自 Button,代码如下: 1 package com.himi.eventdemo; 2 3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.util.Log; 6 import andro

android 事件分发机制(图文详解)

在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少.废话不多说,总结一句:事件分发机制很重要. Android 事件分发流 关于Android 事件分发机制网上的博文很多,但是很多都是写个Demo然后贴一下输出的Log或者拿源码分析,然后一堆的注释和说明,如果用心的

cocos2dx[3.2](12)——新事件分发机制

[唠叨] 在2.x中处理事件需要用到委托代理(delegate),相信学过2.x的触摸事件的同学,都知道创建和移除的流程十分繁琐. 而在3.x中由于加入了C++11的特性,而对事件的分发机制通过事件分发器EventDispatcher 来进行统一的管理. 事件监听器主要有: > 触摸事件     : EventListenerTouchOneByOne.EventListenerTouchAllAtOnce > 鼠标响应事件 : EventListenerMouse > 键盘响应事件 :