fairygui的cocos2dx类源码分析:UIEventDispatcher类

继承Ref类,相当于给这个类加上了cocos2dx的内存管理机制

class UIEventDispatcher : public cocos2d::Ref

private成员变量:

_dispatching:一个判断标志,判断自身是否正在派遣事件。在构造类实例时默认初始为0.
EventCallbackItem:callBack事件回调函数。eventType事件类型,tag事件标记(EventTag类),dispatching事件是否正在派遣的标志

	struct EventCallbackItem
	{
        EventCallback callback;
        int eventType;
        EventTag tag;
        int dispatching;
    };
    std::vector<EventCallbackItem*> _callbacks;
    int _dispatching;

EventCallback一个参数为EventContext* context返回为空的函数指针

typedef std::function<void(EventContext* context)> EventCallback;

EventContext
事件上下文类:成员变量

//绑定要派送这个上下文的事件调度器(即触发这个事件的object)
cocos2d::Ref* _sender;
//inputEvent输入事件类的一些信息(触摸事件的位置,按键事件的键盘,点击事件的次数等等)
InputEvent* _inputEvent;
//事件的数据value
cocos2d::Value _dataValue;
//指向事件数据的指针
void* _data;
//冒泡事件,是否停止传播这个事件,用于判断是否向父节点继续传播
bool _isStopped;
//是否默认阻止,作为派遣事件的返回,做一些派遣事件的后续处理。目前来看,在GObject的touchMove里进行DragStart事件,以及slider进行Changed事件有判断
bool _defaultPrevented;
//捕获触摸事件的判断,1为捕获触摸事件,2为释放触摸事件
int _touchCapture;
//事件类型
int _type;
friend class UIEventDispatcher;

EventTag类注意有个value值,isNone是value是否0的判断就行,其他函数就是EventTag的构造和一些操作符的重载

class EventTag
{
public:
	//...
	//...
    bool isNone() const { return _value == 0; }
private:
    uintptr_t _value;
};

public成员函数:

构造和析构:

UIEventDispatcher::UIEventDispatcher() :_dispatching(0)
{
}

UIEventDispatcher::~UIEventDispatcher()
{
    _dispatching = 0;
    removeEventListeners();
}

根据事件类型添加事件监听:
如果有tag标记的监听者,则判断是否更新旧的监听回调。否则增加新的监听者
无tag的监听者直接加入

void addEventListener(int eventType, const EventCallback& callback) { return addEventListener(eventType, callback, EventTag::None); }
void UIEventDispatcher::addEventListener(int eventType, const EventCallback& callback, const EventTag& tag)
{
    if (!tag.isNone())
    {
        for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
        {
            if ((*it)->eventType == eventType && (*it)->tag == tag)
            {
                (*it)->callback = callback;
                return;
            }
        }
    }
    EventCallbackItem* item = new EventCallbackItem();
    item->callback = callback;
    item->eventType = eventType;
    item->tag = tag;
    item->dispatching = 0;
    _callbacks.push_back(item);
}

根据事件类型删除事件监听

void removeEventListener(int eventType) { removeEventListener(eventType, EventTag::None); }

有tag则删除tag对应的监听,无tag则删除所有tag为None的监听
如果当前正在派遣事件,则把监听回调置空,否则直接删除监听

void UIEventDispatcher::removeEventListener(int eventType, const EventTag& tag)
{
    if (_callbacks.empty())
        return;

    for (auto it = _callbacks.begin(); it != _callbacks.end(); )
    {
        if ((*it)->eventType == eventType && ((*it)->tag == tag || tag.isNone()))
        {
            if (_dispatching > 0)
            {
                (*it)->callback = nullptr;
                it++;
            }
            else
            {
                delete (*it);
                it = _callbacks.erase(it);
            }
        }
        else
            it++;
    }
}

删除全部监听者,与单个删除同理

void UIEventDispatcher::removeEventListeners()
{
    if (_callbacks.empty())
        return;

    if (_dispatching > 0)
    {
        for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
            (*it)->callback = nullptr;
    }
    else
    {
        for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
            delete (*it);
        _callbacks.clear();
    }
}

判断是否有对应的事件类型监听
比较简单,没啥说的

bool hasEventListener(int eventType) const { return hasEventListener(eventType, EventTag::None); }
bool hasEventListener(int eventType, const EventTag& tag) const;

事件派遣
设置事件上下文类的数据:设置自身为派送这个事件的调度器和事件的类型。_activeProcessor是InputProcessor静态成员,用来判断有无输入事件(触摸,按键,点击等等),事件的数据

bool UIEventDispatcher::dispatchEvent(int eventType, void* data, const Value& dataValue)
{
    if (_callbacks.size() == 0)
        return false;

    EventContext context;
    context._sender = this;
    context._type = eventType;
    if (InputProcessor::_activeProcessor)
        context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
    context._dataValue = dataValue;
    context._data = data;
    doDispatch(eventType, &context);
    return context._defaultPrevented;
}

进行事件的派遣:doDispatch

void UIEventDispatcher::doDispatch(int eventType, EventContext* context)
{
    retain();
    //设置正在派遣的数量
    _dispatching++;
    context->_sender = this;
    //是否有需要删除的监听者
    bool hasDeletedItems = false;
    size_t cnt = _callbacks.size(); //dont use iterator, because new item would be added in callback.
    for (size_t i = 0; i < cnt; i++)
    {
        EventCallbackItem* ci = _callbacks[i];
        //事件回调为空的,需要删除无用的监听者
        if (ci->callback == nullptr)
        {
            hasDeletedItems = true;
            continue;
        }
        //对应事件类型的监听者触发回调
        if (ci->eventType == eventType)
        {
            ci->dispatching++;
            //重置触摸捕获
            context->_touchCapture = 0;
            //触发回调
            ci->callback(context);
            ci->dispatching--;
            //判断是否捕获触摸,并且自身为GObject对象,则设置自身为该触摸事件的监听之一(触摸事件是TouchInfo类,有个vector成员变量,储存这个触摸事件的监听者)
            if (context->_touchCapture != 0 && dynamic_cast<GObject*>(this))
            {
            	//捕获触摸监听者
                if (context->_touchCapture == 1 && eventType == UIEventType::TouchBegin)
                    context->getInput()->getProcessor()->addTouchMonitor(context->getInput()->getTouchId(), dynamic_cast<GObject*>(this));
                //释放触摸监听者
                else if (context->_touchCapture == 2)
                    context->getInput()->getProcessor()->removeTouchMonitor(dynamic_cast<GObject*>(this));
            }
        }
    }
    _dispatching--;
    //判断是否需要删除无用监听者,并删除
    if (hasDeletedItems && _dispatching == 0)
    {
        for (auto it = _callbacks.begin(); it != _callbacks.end(); )
        {
            if ((*it)->callback == nullptr)
            {
                delete (*it);
                it = _callbacks.erase(it);
            }
            else
                it++;
        }
    }
    release();
}

根据事件类型进行冒泡派遣
与单独派送类似,只是不用设置派送事件的对象

bool UIEventDispatcher::bubbleEvent(int eventType, void* data, const Value& dataValue)
{
    EventContext context;
    if (InputProcessor::_activeProcessor)
        context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
    context._type = eventType;
    context._dataValue = dataValue;
    context._data = data;
    doBubble(eventType, &context);
    return context._defaultPrevented;
}
void UIEventDispatcher::doBubble(int eventType, EventContext* context)
{
    //parent maybe disposed in callbacks
    //获取父节点的弱引用
    WeakPtr wptr(((GObject*)this)->findParent());
    if (!_callbacks.empty())
    {
    	//重置冒泡标志
        context->_isStopped = false;
        //进行自身事件回调
        doDispatch(eventType, context);
        if (context->_isStopped)
            return;
    }
    GObject* p = wptr.ptr();
    //如果回调中父节点还在,则调用父节点冒泡派遣
    if (p)
        p->doBubble(eventType, context);
}

判断某类型事件是否正在派遣

bool UIEventDispatcher::isDispatchingEvent(int eventType)
{
    for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
    {
        if ((*it)->eventType == eventType)
            return (*it)->dispatching > 0;
    }
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
About CocoStudio is a game development tool kit based on Cocos2d-x. It breaks down tasks in game development into different roles, it includes: UI editor for UI graphic artists, Animation editor for graphic artists, Number cruncher for game data designers, Scene editor for game designers CocoStudio forms a complete game development solution. The UI editor The UI was designed to serve its only purpose: create UI for games. Its simple and intuitive interface allows graphic artists to focus on their expertise, without worrying about other aspects such as programming. Currently the UI editor has 12 different UI elements ready to be used in games, new UI elements will be added with each and every release of CocoStudio, Other key features that the UI editor supports are: Texture packaging - Automatically packs individual texture files into a single large sprite, which further saves memory and improves game performance. Multi-resolution adaption - Automatically adapts to multiple resolution sizes with relative UI positioning. Templating - Reuse the same UI layout across different games, swap out texture resources to give it a new look. The Animation editor The Animation editor was designed to feel like Adobe Flash, which makes graphic artists feel right at home. The Animation editor brings skeletal animation to Cocos2d-x. What advantage does skeletal animation holds against the traditional frame animation? Lower memory consumption - An animation with the traditional frame based solution could use dozens of individual textures, but with skeletal animation, only 1 set of body parts is required to make infinite number of different animations. Smaller file size - due to less number of assets. Animation blending - you can combine animations together to easily make new animation, for example, you could blend attacking animation with walk animation to create "attacking while walking animation". Animation reuse - you can share skeletal animations with another character with the same skeleton setup. Smooth interpolation - traditional frame based animation is very choppy especially in slow motion. Skeletal animation interpolates between 2 sets of key frames, so animation is always played at the same frame rate as the game. However Skeletal animation cannot replace the traditional frame based animation, for example, it cannot make isometric character, it cannot make explosion, that is why we did not forget frame based animation, we even made it better and simpler. You only have to drag and drop frame sequences to the work space, and the animation editor will automatically creates the frame animation for you. Other highlight of Animation editor includes: WYSIWYG collision box editing - editing collision box in wysiwyg way has never being easier and accurate. Reference point - enables characters to wield swords, mount horses, and attaching other objects easily. Texture packing - Automatically packs individual texture files into a single large sprite, which further saves memory and improves game performance. The Data Cruncher The data Cruncher imports excel tables and converts the data into a format readable by cocos2d-x, which can also be used as a component for the Scene editor. The Scene editor The scene editor pieces all the assets made by the UI editor, Animation editor, and the Data Cruncher into a game scene, it can then simulate the game inside the editor. The scene editor also supports many assets made from third party editors such as particle designer, tiled etc. The scene editor relies on the CocosStudio Framework. CocoStudio Framework CocoStudio Framework is an open source higher level framework on top of Cocos2d-x, it employes entity and component system, it is used to read the data saved from the scene editor. The Scene editor saves data in a MVC like fashion, it includes all entities and events used in the current scene, and exports to corresponding code template for the programmers. A programmer can then write the code in Javascript to bring the game alive. CocoStudio的安装 1.CocoStudio的运行平台是Windows操作系统,推荐使用Windows7操作系统。 2.安装CocoStudio之前,确保电脑中安装了.Net 4.0 Framework 3.安装目录尽量不要在C盘的Program Files文件夹下,可能会导致启动器无法启动编辑器。当然,通过“以管理员身份运行”的方式也可以打开软件 4.在Xp和Windows8的操作系统下,可能会出现的闪屏或无法运行的问题。这个问题会尽快修复
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值