最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
cocos2d-x 3.0 触摸注册函数
一、cocos2d-x 3.0 事件分发机制概述
cocos2d-x 3.0 版本对事件分发机制进行了修改,将事件处理逻辑分离出来,并通过不同的事件监听器来监听不同的事件。当一个节点接收到事件时,会指派一个事件分发器 _eventDispatcher 专门来分发这些事件。以触摸事件为例,大致的处理过程如下:
- 创建一个对应触摸事件的监听器。
- 覆盖触摸事件的函数,并将其绑定到监听器。
- 设置监听器的属性。
- 将监听器添加到分发器中,系统会自动处理触摸事件。
二、单点触摸的使用
单点触摸监听器类
以下是源代码中关于单点触摸监听器的类:
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;
std::function<bool(Touch*, Event*)> onTouchBegan;
std::function<void(Touch*, Event*)> onTouchMoved;
std::function<void(Touch*, Event*)> onTouchEnded;
std::function<void(Touch*, Event*)> onTouchCancelled;
private:
EventListenerTouchOneByOne();
bool init();
std::vector<Touch*> _claimedTouches;
bool _needSwallow;
friend class EventDispatcher;
};
代码示例
在 HelloWorld 的 init 函数中注册监听器并添加到事件分发器中:
// 添加一个测试的精灵
auto onion = Sprite::create("onion.png");
onion->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
onion->setScale(0.2);
this->addChild(onion);
// 创建一个触摸监听器,这里使用单点触摸事件
auto TouchListenr = EventListenerTouchOneByOne::create();
// 设置吞噬为 true,不让触摸往下传递
TouchListenr->setSwallowTouches(true);
// 和回调函数绑定
TouchListenr->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
TouchListenr->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
TouchListenr->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
// 添加监听器到事件分发器中
_eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr, onion);
覆盖单点触摸函数
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
// 获取精灵对象并取得精灵的矩阵
auto sprite = static_cast<Sprite*>(event->getCurrentTarget());
Rect rect = sprite->getBoundingBox();
// 获取触摸点的坐标
Point point = touch->getLocation();
// 判断触摸点是否在精灵的矩阵范围内
if(rect.containsPoint(point))
{
return true;
}
return false;
}
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
// 获取精灵对象
auto sprite = static_cast<Sprite*>(event->getCurrentTarget());
// 改变精灵的位置
sprite->setPosition(sprite->getPosition() + touch->getDelta());
}
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
CCLog("touch end!");
}
点击调试运行,就可以在屏幕中拉动所测试的精灵。
Touch 类和 Event 类分析
Touch 类
Touch 类继承了 REF,主要传入触摸点的坐标位置,并提供了一些获取坐标的方法:
/** returns the current touch location in OpenGL coordinates */
Point getLocation() const;
/** returns the previous touch location in OpenGL coordinates */
Point getPreviousLocation() const;
/** returns the start touch location in OpenGL coordinates */
Point getStartLocation() const;
/** returns the delta of 2 current touches locations in screen coordinates */
Point getDelta() const;
/** returns the current touch location in screen coordinates */
Point getLocationInView() const;
/** returns the previous touch location in screen coordinates */
Point getPreviousLocationInView() const;
/** returns the start touch location in screen coordinates */
Point getStartLocationInView() const;
例如,在触摸移动时,可以使用 getDelta() 方法来计算点的位移。
Event 类
Event 类主要传入处理的对象,其主要成员如下:
/** Gets the event type */
inline Type getType() const { return _type; };
/** Stops propagation for current event */
inline void stopPropagation() { _isStopped = true; };
/** Checks whether the event has been stopped */
inline bool isStopped() const { return _isStopped; };
/** @brief Gets current target of the event
* @return The target with which the event associates.
* @note It only be available when the event listener is associated with node.
* It returns 0 when the listener is associated with fixed priority.
*/
inline Node* getCurrentTarget() { return _currentTarget; };
在处理触摸对象时,可以通过 getCurrentTarget() 方法来获取对象并进行处理。
事件分发器添加监听器的两种方法
在将监听器添加到事件分发器时,有两种方法:addEventListenerWithSceneGraphPriority 和 addEventListenerWithFixedPriority。
源代码定义
/** 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);
两种方法的区别
- 优先级确定方式:
addEventListenerWithSceneGraphPriority:触发优先级按照第二个参数中的node的显示顺序来确定,默认的fixedPriority为 0,即精灵位置靠前的会优先响应触摸。addEventListenerWithFixedPriority:按照第二个参数的整形变量值的大小来确定优先级,且不能为 0,值越小越优先响应触摸。- 监听器移除方式:
addEventListenerWithSceneGraphPriority:在触摸对象对应的node析构之后,系统会自动调用移除触摸。addEventListenerWithFixedPriority:需要手动调用_eventDispatcher->removeEventListener(listenerName)来移除监听器。
代码示例修改
可以修改上述例子的代码,添加多两个精灵,并在分发事件代码中添加:
_eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr->clone(), onion2);
_eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr->clone(), onion3);
点击运行进行测试。如果使用 addEventListenerWithFixedPriority 方式,虽然可以自定义优先级,但由于没有绑定 node 对象,需要在触摸函数中引入需要控制的对象。最后别忘了手动移除监听器。
三、多点触摸
多点触摸和单点触摸类似,以下是多点触摸监听器的源码:
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;
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;
private:
EventListenerTouchAllAtOnce();
bool init();
friend class EventDispatcher;
};
多点触摸传入多个 Touch 对象,处理时可以遍历 vector<Touch*> 来逐个处理每一个点,具体例子可以参考源码自带的 MutiTouchTest。