1. 首页菜单

cocos2d-x 3.0 触摸注册函数

2015年01月20日 10:35 0 点赞 0 评论 更新于 2025-11-21 14:54

一、cocos2d-x 3.0 事件分发机制概述

cocos2d-x 3.0 版本对事件分发机制进行了修改,将事件处理逻辑分离出来,并通过不同的事件监听器来监听不同的事件。当一个节点接收到事件时,会指派一个事件分发器 _eventDispatcher 专门来分发这些事件。以触摸事件为例,大致的处理过程如下:

  1. 创建一个对应触摸事件的监听器。
  2. 覆盖触摸事件的函数,并将其绑定到监听器。
  3. 设置监听器的属性。
  4. 将监听器添加到分发器中,系统会自动处理触摸事件。

二、单点触摸的使用

单点触摸监听器类

以下是源代码中关于单点触摸监听器的类:

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;
};

代码示例

HelloWorldinit 函数中注册监听器并添加到事件分发器中:

// 添加一个测试的精灵
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() 方法来获取对象并进行处理。

事件分发器添加监听器的两种方法

在将监听器添加到事件分发器时,有两种方法:addEventListenerWithSceneGraphPriorityaddEventListenerWithFixedPriority

源代码定义

/** 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