Cocos2d-x 3.0 新特性体验-触摸事件处理机制
2014-04-09 15:20
453 查看
在cocos2d-x 2.x版本中,相信大家都抱怨过其中的触摸机制;在3.0版本中,采用了全新的触摸事件处理机制。
在官方的文档中:点击打开链接 这篇文章有对新的事件分发机制的介绍。
下面,我将通过引擎中自带的sample来探索一下这个新的触摸事件处理机制。
注:例子来自Test cpp/NewEventDispatcherTest
一、例子1
(1)创建三个精灵
[cpp] view
plaincopy
auto sprite1 = Sprite::create("Images/CyanSquare.png");
sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 80));
addChild(sprite1, 10); //其中 10 表示 zOreder
auto sprite2 = Sprite::create("Images/MagentaSquare.png");
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 20);
auto sprite3 = Sprite::create("Images/YellowSquare.png");
sprite3->setPosition(Point(0, 0));
sprite2->addChild(sprite3, 1); //注意 sprite3 是添加到 sprite2 上的
(2)创建一个单点触摸事件监听器,处理触摸事件逻辑
[cpp] view
plaincopy
// Make sprite1 touchable
auto listener1 = EventListenerTouchOneByOne::create();//创建一个触摸监听
listener1->setSwallowTouches(true); //设置是否想下传递触摸
//通过 lambda 表达式 直接实现触摸事件的回掉方法
listener1->onTouchBegan = [](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 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;
};
listener1->onTouchMoved = [](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
target->setPosition(target->getPosition() + touch->getDelta());
};
listener1->onTouchEnded = [=](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
log("sprite onTouchesEnded.. ");
target->setOpacity(255);
if (target == sprite2)
{
sprite1->setZOrder(100);
}
else if(target == sprite1)
{
sprite1->setZOrder(0);
}
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);
①其中的触摸监听类型为:EventListenerTouchOneByOne 表示的是单点触摸;而EventListenerTouchAllAtOnce 表示的就是多点触摸。
[cpp] view
plaincopy
class EventListenerTouchOneByOne : public EventListener
{
public:
static const std::string LISTENER_ID;
static EventListenerTouchOneByOne* create();
virtual ~EventListenerTouchOneByOne();
void setSwallowTouches(bool needSwallow);
/// Overrides
virtual EventListenerTouchOneByOne* clone() override;
virtual bool checkAvailable() override;
//
public:
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;
};
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;
//
public:
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();
private:
friend class EventDispatcher;
};
看起来很是熟悉吧,和cocos2dx 2.x 版本中的 target touch 和 standard touch 差不多吧!只是使用的形式不太一样罢了。还有在3.0版本中,不需要注册触摸事件代理delegate了。
② _eventDispatcher
事件监听器包含以下几种:
触摸事件 (EventListenerTouch)
键盘响应事件 (EventListenerKeyboard)
加速记录事件 (EventListenerAcceleration)
鼠标响应事件 (EventListenerMouse)
自定义事件 (EventListenerCustom)
以上事件监听器统一由
_eventDispatcher 是 Node 的属性,通过它管理当前节点(如
场景 、层、精灵等 )的所有事件分发情况。但是它本身是一个单例模式值的引用,在 Node 构造函数中,通过 "Director::getInstance()->getEventDispatcher();" 获取,有了这个属性,我们能更为方便的调用。
有两种方式将 事件监听器 listener1 添加到 事件调度器_eventDispatcher 中:
[cpp] view
plaincopy
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
看看这两种方式的实现代码:
[cpp] view
plaincopy
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
CCASSERT(listener && node, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
if (!listener->checkAvailable())
return;
listener->setSceneGraphPriority(node);
listener->setFixedPriority(0);
listener->setRegistered(true);
addEventListener(listener);
}
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
CCASSERT(listener, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
if (!listener->checkAvailable())
return;
listener->setSceneGraphPriority(nullptr);
listener->setFixedPriority(fixedPriority);
listener->setRegistered(true);
listener->setPaused(false);
addEventListener(listener);
}
从中我们可以知道: 其中的 addEventListenerWithSceneGraphPriority 的事件监听器优先级是 0 ;而且在 addEventListenerWithFixedPriority 中的事件监听器的优先级不可以设置为 0,因为这个是保留给 SceneGraphPriority
使用的。
注意:(1) 这里当我们再次使用 listener1 的时候,需要使用
看看clone()方法的代码:
[cpp] view
plaincopy
EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
{
auto ret = new EventListenerTouchOneByOne();
if (ret && ret->init())
{
ret->autorelease();
ret->onTouchBegan = onTouchBegan;
ret->onTouchMoved = onTouchMoved;
ret->onTouchEnded = onTouchEnded;
ret->onTouchCancelled = onTouchCancelled;
ret->_claimedTouches = _claimedTouches;
ret->_needSwallow = _needSwallow;
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
(2)另外,有一点非常重要,FixedPriority listener添加完之后需要手动remove,而SceneGraphPriority listener是跟node绑定的,在node的析构函数中会被移除。
[cpp] view
plaincopy
_eventDispatcher->cleanTarget(this);
CC_SAFE_RELEASE(_eventDispatcher);
二、例子2
在上面的例子中,使用的是 addEventListenerWithSceneGraphPriority 添加触摸监听器,也就是单点触摸。其结点的触摸优先级都是相同的 0 。那么上层的结点 是比 下层的结点 先处理触摸事件的。
下面看看如何使用 addEventListenerWithFixedPriority 自定义结点的触摸优先级。
(1)首先自定义精灵,其中可以设置精灵接受触摸的优先级。
[cpp] view
plaincopy
class TouchableSpriteWithFixedPriority : public Sprite
{
public:
CREATE_FUNC(TouchableSpriteWithFixedPriority);
TouchableSpriteWithFixedPriority()
: _listener(nullptr)
, _fixedPriority(0)
, _useNodePriority(false)
{
}
void setPriority(int fixedPriority) { _fixedPriority = fixedPriority; _useNodePriority = false; };
void setPriorityWithThis(bool useNodePriority) { _useNodePriority = useNodePriority; _fixedPriority = true; }
void onEnter() override
{
Sprite::onEnter();
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event){
Point locationInNode = this->convertToNodeSpace(touch->getLocation());
Size s = this->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
if (rect.containsPoint(locationInNode))
{
this->setColor(Color3B::RED);
return true;
}
return false;
};
listener->onTouchMoved = [=](Touch* touch, Event* event){
//this->setPosition(this->getPosition() + touch->getDelta());
};
listener->onTouchEnded = [=](Touch* touch, Event* event){
this->setColor(Color3B::WHITE);
};
if (_useNodePriority)
{
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
else
{
_eventDispatcher->addEventListenerWithFixedPriority(listener, _fixedPriority);
}
_listener = listener;
}
void onExit() override
{
_eventDispatcher->removeEventListener(_listener);
Sprite::onExit();
}
private:
EventListener* _listener;
int _fixedPriority;
bool _useNodePriority;
};
(2)分别创建三个精灵,可以自定义设置每一个精灵的触摸优先级。注意:优先级值小的,接受触摸优先。
[cpp] view
plaincopy
auto sprite1 = TouchableSpriteWithFixedPriority::create();
sprite1->setTexture("Images/CyanSquare.png");
sprite1->setPriority(30);
sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 40));
addChild(sprite1, 10);
auto sprite2 = TouchableSpriteWithFixedPriority::create();
sprite2->setTexture("Images/MagentaSquare.png");
sprite2->setPriority(20);
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 20);
auto sprite3 = TouchableSpriteWithFixedPriority::create();
sprite3->setTexture("Images/YellowSquare.png");
sprite3->setPriority(10);
sprite3->setPosition(Point(0, 0));
sprite2->addChild(sprite3, 1);
三、删除触摸监听器的方法:
[cpp] view
plaincopy
/** Remove a listener
* @param listener The specified event listener which needs to be removed.
*/
void removeEventListener(EventListener* listener);
/** Removes all listeners with the same event listener type */
void removeEventListeners(EventListener::Type listenerType);
前者只是删除某一个事件监听器,而后者是删除某一类事件监听器(使用了 clone 克隆)
在官方的文档中:点击打开链接 这篇文章有对新的事件分发机制的介绍。
下面,我将通过引擎中自带的sample来探索一下这个新的触摸事件处理机制。
注:例子来自Test cpp/NewEventDispatcherTest
一、例子1
(1)创建三个精灵
[cpp] view
plaincopy
auto sprite1 = Sprite::create("Images/CyanSquare.png");
sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 80));
addChild(sprite1, 10); //其中 10 表示 zOreder
auto sprite2 = Sprite::create("Images/MagentaSquare.png");
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 20);
auto sprite3 = Sprite::create("Images/YellowSquare.png");
sprite3->setPosition(Point(0, 0));
sprite2->addChild(sprite3, 1); //注意 sprite3 是添加到 sprite2 上的
(2)创建一个单点触摸事件监听器,处理触摸事件逻辑
[cpp] view
plaincopy
// Make sprite1 touchable
auto listener1 = EventListenerTouchOneByOne::create();//创建一个触摸监听
listener1->setSwallowTouches(true); //设置是否想下传递触摸
//通过 lambda 表达式 直接实现触摸事件的回掉方法
listener1->onTouchBegan = [](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 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;
};
listener1->onTouchMoved = [](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
target->setPosition(target->getPosition() + touch->getDelta());
};
listener1->onTouchEnded = [=](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
log("sprite onTouchesEnded.. ");
target->setOpacity(255);
if (target == sprite2)
{
sprite1->setZOrder(100);
}
else if(target == sprite1)
{
sprite1->setZOrder(0);
}
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);
①其中的触摸监听类型为:EventListenerTouchOneByOne 表示的是单点触摸;而EventListenerTouchAllAtOnce 表示的就是多点触摸。
[cpp] view
plaincopy
class EventListenerTouchOneByOne : public EventListener
{
public:
static const std::string LISTENER_ID;
static EventListenerTouchOneByOne* create();
virtual ~EventListenerTouchOneByOne();
void setSwallowTouches(bool needSwallow);
/// Overrides
virtual EventListenerTouchOneByOne* clone() override;
virtual bool checkAvailable() override;
//
public:
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;
};
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;
//
public:
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();
private:
friend class EventDispatcher;
};
看起来很是熟悉吧,和cocos2dx 2.x 版本中的 target touch 和 standard touch 差不多吧!只是使用的形式不太一样罢了。还有在3.0版本中,不需要注册触摸事件代理delegate了。
② _eventDispatcher
事件监听器包含以下几种:
触摸事件 (EventListenerTouch)
键盘响应事件 (EventListenerKeyboard)
加速记录事件 (EventListenerAcceleration)
鼠标响应事件 (EventListenerMouse)
自定义事件 (EventListenerCustom)
以上事件监听器统一由
_eventDispatcher来进行管理。
_eventDispatcher 是 Node 的属性,通过它管理当前节点(如
场景 、层、精灵等 )的所有事件分发情况。但是它本身是一个单例模式值的引用,在 Node 构造函数中,通过 "Director::getInstance()->getEventDispatcher();" 获取,有了这个属性,我们能更为方便的调用。
有两种方式将 事件监听器 listener1 添加到 事件调度器_eventDispatcher 中:
[cpp] view
plaincopy
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
看看这两种方式的实现代码:
[cpp] view
plaincopy
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
CCASSERT(listener && node, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
if (!listener->checkAvailable())
return;
listener->setSceneGraphPriority(node);
listener->setFixedPriority(0);
listener->setRegistered(true);
addEventListener(listener);
}
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
CCASSERT(listener, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
if (!listener->checkAvailable())
return;
listener->setSceneGraphPriority(nullptr);
listener->setFixedPriority(fixedPriority);
listener->setRegistered(true);
listener->setPaused(false);
addEventListener(listener);
}
从中我们可以知道: 其中的 addEventListenerWithSceneGraphPriority 的事件监听器优先级是 0 ;而且在 addEventListenerWithFixedPriority 中的事件监听器的优先级不可以设置为 0,因为这个是保留给 SceneGraphPriority
使用的。
注意:(1) 这里当我们再次使用 listener1 的时候,需要使用
clone()方法创建一个新的克隆,因为在使用
addEventListenerWithSceneGraphPriority或者
addEventListenerWithFixedPriority方法时,会对当前使用的事件监听器添加一个已注册的标记,这使得它不能够被添加多次。
看看clone()方法的代码:
[cpp] view
plaincopy
EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
{
auto ret = new EventListenerTouchOneByOne();
if (ret && ret->init())
{
ret->autorelease();
ret->onTouchBegan = onTouchBegan;
ret->onTouchMoved = onTouchMoved;
ret->onTouchEnded = onTouchEnded;
ret->onTouchCancelled = onTouchCancelled;
ret->_claimedTouches = _claimedTouches;
ret->_needSwallow = _needSwallow;
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
(2)另外,有一点非常重要,FixedPriority listener添加完之后需要手动remove,而SceneGraphPriority listener是跟node绑定的,在node的析构函数中会被移除。
[cpp] view
plaincopy
_eventDispatcher->cleanTarget(this);
CC_SAFE_RELEASE(_eventDispatcher);
二、例子2
在上面的例子中,使用的是 addEventListenerWithSceneGraphPriority 添加触摸监听器,也就是单点触摸。其结点的触摸优先级都是相同的 0 。那么上层的结点 是比 下层的结点 先处理触摸事件的。
下面看看如何使用 addEventListenerWithFixedPriority 自定义结点的触摸优先级。
(1)首先自定义精灵,其中可以设置精灵接受触摸的优先级。
[cpp] view
plaincopy
class TouchableSpriteWithFixedPriority : public Sprite
{
public:
CREATE_FUNC(TouchableSpriteWithFixedPriority);
TouchableSpriteWithFixedPriority()
: _listener(nullptr)
, _fixedPriority(0)
, _useNodePriority(false)
{
}
void setPriority(int fixedPriority) { _fixedPriority = fixedPriority; _useNodePriority = false; };
void setPriorityWithThis(bool useNodePriority) { _useNodePriority = useNodePriority; _fixedPriority = true; }
void onEnter() override
{
Sprite::onEnter();
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event){
Point locationInNode = this->convertToNodeSpace(touch->getLocation());
Size s = this->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
if (rect.containsPoint(locationInNode))
{
this->setColor(Color3B::RED);
return true;
}
return false;
};
listener->onTouchMoved = [=](Touch* touch, Event* event){
//this->setPosition(this->getPosition() + touch->getDelta());
};
listener->onTouchEnded = [=](Touch* touch, Event* event){
this->setColor(Color3B::WHITE);
};
if (_useNodePriority)
{
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
else
{
_eventDispatcher->addEventListenerWithFixedPriority(listener, _fixedPriority);
}
_listener = listener;
}
void onExit() override
{
_eventDispatcher->removeEventListener(_listener);
Sprite::onExit();
}
private:
EventListener* _listener;
int _fixedPriority;
bool _useNodePriority;
};
(2)分别创建三个精灵,可以自定义设置每一个精灵的触摸优先级。注意:优先级值小的,接受触摸优先。
[cpp] view
plaincopy
auto sprite1 = TouchableSpriteWithFixedPriority::create();
sprite1->setTexture("Images/CyanSquare.png");
sprite1->setPriority(30);
sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 40));
addChild(sprite1, 10);
auto sprite2 = TouchableSpriteWithFixedPriority::create();
sprite2->setTexture("Images/MagentaSquare.png");
sprite2->setPriority(20);
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 20);
auto sprite3 = TouchableSpriteWithFixedPriority::create();
sprite3->setTexture("Images/YellowSquare.png");
sprite3->setPriority(10);
sprite3->setPosition(Point(0, 0));
sprite2->addChild(sprite3, 1);
三、删除触摸监听器的方法:
[cpp] view
plaincopy
/** Remove a listener
* @param listener The specified event listener which needs to be removed.
*/
void removeEventListener(EventListener* listener);
/** Removes all listeners with the same event listener type */
void removeEventListeners(EventListener::Type listenerType);
前者只是删除某一个事件监听器,而后者是删除某一类事件监听器(使用了 clone 克隆)
相关文章推荐
- Cocos2d-x 3.0 新特性体验(3)触摸事件处理机制
- Cocos2d-x 3.0 新特性体验(3)触摸事件处理机制
- Cocos2d-x 3.0 新特性体验(3)触摸事件处理机制
- Cocos2d-x 3.0 触摸事件处理机制
- Cocos2d-x 3.0 触摸事件处理机制
- Cocos2d-x-3.0 Touch事件处理机制
- cocos2d-x 3.0 全新触摸检测与事件分发机制
- cocos2d-x 触摸事件处理机制
- cocos2d-x 3.0 事件分发机制 —触摸事件监听
- cocos2d-x (四):触摸事件处理机制
- Cocos2d-x之Touch事件处理机制 提供两种触摸事件处理机制:CCStandardTouchDelegate和CCTargetedTouchDelegate。
- cocos2d触摸事件处理机制(2.x和3.x变化)
- cocos2d-x基本知识点:事件处理机制之触屏事件2
- cocos2d-3.0 Helloworld::onTouchMoved的处理机制的推測
- Cocos2d-X 事件处理机制之触屏事件(单点触屏+多点触屏)
- Cocos2d-x学习笔记(五)CCLayer分析及输入事件处理(触摸、重力传感器、按键)
- Cocos2d-x 3.0 屏幕触摸及消息分发机制
- cocos2d-x 3.0 事件分发机制
- Android 触摸事件处理机制
- 【基础】Cocos2d-x 浅谈事件处理机制