Cocos2d-js 事件处理机制
Cocos2d-x学习笔记—事件处理机制一:事件处理机制一个事件由触发到完成响应,主要由以下三部分组成:
在Cocos2d-x v3.x中,关于事件的东西,无非就是围绕上述的三个部分展开来的,掌握了上述的三个部分,也就掌握了Cocos2d-x v3.x中事件处理的精髓。 (1)事件分发器:事件分发器,就相当于是所有事件的“总长官”;它负责调度和管理所有的事件监听器;当有事件发生时,它负责调度对应的事件;一般调用Director类中的getEventDispatcher获得一个事件调度器,在游戏启动时,就会创建一个默认的EventDispatcher对象。 事件监听器与事件具有对应关系。例如,键盘事件(EvemKeyboard)只能由键盘事件监听器(EventListenerKeyboard)处理,它们之间需要在程序中建立关系,这种关系的建立过程被称为“注册监听器”。CoCos2d-x提供一个事件分发器(EvemDispatcher)负责管理这种关系,具体说事件分发器负责注册监听器、注销监听器和事件分发。EventDispatcher 类采用单例模式设计,通过 Director::getlnstance()->getEventDispatcher()语句获得事件分发器对象。 EventDispatcher类中注册事件监听器到事件分发器函数如下: (1) void addEventListenerWithFixedPriority (EventListener * listener,int fixedPriority) 指定固定的事件优先级注册监听器,事件优先级决定事件响应的优先级别,值越小优先级越髙。 (2) void addEventListenerWithSceneGraphPriority(EventListener * listener,Node * node) 把精灵显示优先级作为事件优先级,参数node是要触摸的精灵对象。 当不再进行事件响应时,应该注销事件监听器。主要的注销函数如下: (1) void removeEventListener(EventListener * listener)。注销指定的事件监听器。 (2) void removeCustomEventListeners(const std:: string&* customEventName)。注销自定义事件监听器。 (3) void removeAllEventListener()。注销所有事件监听器,需要注意的是,使用该函数之后,菜单也不能响应事件了,因为它也需要接受触摸事件。 注意: (1)addEventListenerWithSceneGraphPriority的事件监听器优先级是0, 而且在addEventListenerWithFixedPriority中的事件监听器的优先级不可以设置为0,因为这个是保留给SceneGraphPriority使用的。 (2)另外,有一点非常重要,FixedPriority listener添加完之后需要手动remove,而SceneGraphPriority listener是跟node绑定的,在node的析构函数中会被移除。 移除方法为dispatcher->removeEventListener(listener); (2)事件类型:在Cocos2d-x中定义了以下几种事件类型: enum class Type { TOUCH,// 触摸事件 KEYBOARD,// 键盘事件 ACCELERATION,// 加速器事件 MOUSE,// 鼠标事件 FOCUS,// 焦点事件 CUSTOM // 自定义事件 } (3)事件监听器:事件监听器实现了各种事件触发后对应的逻辑;由事件分发器EventDispatcher调用对应的事件监听器,进而由事件监听者响应所绑定的回调函数。在Cocos2d-x中定义以下的几种事件监听器: enum class Type { // 未知的事件监听器 UNKNOWN,// 单点触摸事件监听器创建方法与回调函数形参 TOUCH_ONE_BY_ONE,EventListenerTouchOneByOne::create(); typedef std::function<bool(Touch*,Event*)> ccTouchBeganCallback; typedef std::function<void(Touch*,Event*)> ccTouchCallback; // 多点触摸事件监听器创建方法与回调函数形参 TOUCH_ALL_AT_ONCE,EventListenerTouchAllAtOnce::create(); typedef std::function<void(const std::vector<Touch*>&,Event*)> ccTouchesCallback; // 键盘事件监听器创建方法与回调函数形参 KEYBOARD,EventListenerKeyboard::create(); std::function<void(EventKeyboard::KeyCode,Event*)> onKeyPressed; std::function<void(EventKeyboard::KeyCode,Event*)> onKeyReleased; // 鼠标事件监听器创建方法与回调函数形参 MOUSE,EventListenerMouse::create(); std::function<void(EventMouse* event)> onMouseDown; std::function<void(EventMouse* event)> onMouseUp; std::function<void(EventMouse* event)> onMouseMove; std::function<void(EventMouse* event)> onMouseScroll; // 加速器事件监听器创建方法与回调函数形参 ACCELERATION,EventListenerAcceleration::create(); std::function<void(Acceleration*,Event*)> onAccelerationEvent; // 焦点事件监听器创建方法与回调函数形参 FOCUS,EventListenerFocus::create(); std::function<void(ui::Widget*,ui::Widget*)> onFocusChanged; // 自定义事件监听器创建方法与回调函数形参 CUSTOM EventListenerCustom::create(); std::function<void(EventCustom*)> _onCustomEvent; } 二:单点触摸事件处理方法(1)创建一个单点触摸事件监听器:auto listener = EventListenerTouchOneByOne::create(); (2)设置监听器回调函数:// 设置是否吞没事件,在onTouchBegan方法返回true时吞没,事件不会传递给下一个Node对象 listener->setSwallowTouches(true); listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::touchBegan,this); listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::touchMoved,this); listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::touchEnded,this); (3)添加监听器// 其中listener->clone()获得listener对象,使用clone()函数是因为每—事件监听器只能被注册一次, // addEventListenerWithSceneGraphPriority和addEventListenerWithFixedPriority会在注册事件监听器时设置一个注册标 // 识,一旦设置了注册标识,该监听器就不能再用于注册其他事件监听了,因此需要使用listener->clone()克隆一个新的监听器对象, // 把这个新的监听器对象用于注册。 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,pLayer1); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener->clone(),pLayer2); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener->clone(),pLayer3);
(4)具体触摸事件bool HelloWorld::TouchBegan(Touch *touch,Event *unused_event) { // 获取事件所绑定的对象 auto target = static_cast<Layer*>(unused_event->getCurrentTarget()); if (target == nullptr) { return false; } // 获取当前点击点相对绑定对象的局部坐标(Node坐标系) // getLocation得到的是openGL坐标系,也就是世界坐标系 Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation()); Size s = target->getContentSize(); Rect rect = Rect(0,s.width,s.height); // 点击范围判断检测 if (rect.containsPoint(locationInNode)) { log("sprite began... x = %f,y = %f",locationInNode.x,locationInNode.y); target->setOpacity(180); return true; } return false; } 关键理解:
对setSwallowTouches吞没事件的理解:
判断是否触摸到某目标的方法可以这么理解,以触摸对象为精灵pLayer1为例:
三:层中单点触摸事件处理方法事件监听的对象是层,而非精灵,对于是否触摸到某个精灵的判断较为复杂,但使用简单,首先在头文件中声明如下虚函数: virtual bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event); 再在主程序中开启层触摸响应即可 this->setTouchEnabled(true); // 打开触摸监听 this->setTouchMode(Touch::DispatchMode::ONE_BY_ONE); // 设置为单点触摸模式 四:多点触摸本节分析一下使用多点触摸的一些细节,以及应该如何处理。首先由一个Target,这个Target是一个可点击的对象,实现了几个功能;当点击到该対象的时候,该对象可以拖动,直到手指松开。 (1)第一种情况,多个TouchPoint点击在同一个Target上。
(2)第二种情况,一个TouchPoint点击在多个Target上。
(3)第三种情况,多个TouchPoint点击在多个Target上。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |