这篇文章主要介绍touch事件机制,还会涉及到一些的介绍Cocos2d-x的内存回收相关内容。
一、触摸事件
简单介绍一下Touch事件流程:玩家触摸到设备屏幕后,引擎会把触摸事件派发给注册了事件监听的相应代理,触摸的具体信息会以参数的形式传递给相应回调函数。GameEngin-> EventDispatcher -> ??->onTouchXXX
TouchEvent(触摸事件)分为2种 :EventListenerTouchAllAtOnce(多点触摸) 和 EventListenerTouchOneByOne (单点触摸)。
以单点触摸为例,创建一个Touch事件后,要给 touch->onTouchBegan onTouchCancelled onTouchEnded onTouchMoved 赋值相应的回调,这4个回调分别代表了
onTouchBegan 开始接触屏幕
onTouchCancelled 事件被取消(比如程序切到后台)
onTouchEnded 触摸事件结束,手指离开屏幕
onTouchMoved 手指在屏幕上滑动
这4个回调方法里,除了第一个onTouchBegan 的返回值是bool,其他都是void。那么这个bool有什么用呢? 看一下CCEventDispatcher的源码(CCEventDispatcher.cpp),不难发现,当开始触摸事件返回true时,之后的触摸结束、触摸移动等事件才能触发,反之,如果TouchBegan返回false,后面的流程不会被触发。
下面贴出给node添加Touch事件的流程
<span style="white-space:pre"> </span>//添加点击监听(单点触摸)
EventListenerTouchOneByOne* tevent = EventListenerTouchOneByOne::create();
tevent->setSwallowTouches(true);
tevent->onTouchBegan = [&](Touch* touch, Event*){
for(auto key : m_clickDelegates)
{
key.second(touch);
}
return false;
};
tevent->onTouchCancelled = [&](Touch*, Event*){
};
tevent->onTouchEnded = [&](Touch*, Event*){
};
tevent->onTouchMoved = [&](Touch*, Event*){
};
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(tevent,this);setSwallowTouches 代表是否阻止当前事件向下一层级派发。
二、cocos2d::Map std::map (这里用大写的Map代表Cocosd中的,小写的map代表标准库函数中的)
cocos2d::Map和std::map功能基本一样,不同的是,Map沿用了cocos2dx的内存回收机制,当添加一个value到Map中时,value.retain()会被调用,移除后,value.release()会被调用,这样,我们就不用手动的去处理map内部引用计数了,但为了使用这个便利,Map<k,v>中的v 必须是 Ref* 类型 !。 这样,如果想用Ref* 做key,而value是一个 std::function<void(Touch*)>类型,就只能使用标准库函数了,但这样就要自己处理Map内部Ref*
类型的引用计数。
之前一直相当然的认为对std::map遍历的时候,是直接遍历所有的value,但结果遍历的类型是 std::pair<k,v> 。
下面看一下单点触摸层简单实现
class LayerTouch:public cocos2d::Layer
{
public:
LayerTouch();
~LayerTouch();
virtual bool init();
static LayerTouch* create();
//添加当前回调事件到点击事件回调map中
void addClickDelegate(cocos2d::Ref*,std::function);
private:
//点击事件回调字典
std::map> m_clickDelegates;
};
#include "LayerTouch.h"
USING_NS_CC;
LayerTouch::LayerTouch():m_clickDelegates(std::map>())
{
}
LayerTouch::~LayerTouch()
{
for(std::map>::iterator iter = m_clickDelegates.begin();iter != m_clickDelegates.end();iter++)
{
iter->first->release();
}
m_clickDelegates.clear();
}
void LayerTouch::addClickDelegate(cocos2d::Ref* clickDelegate,std::function callback)
{
m_clickDelegates[clickDelegate] = callback;
clickDelegate->retain();
}
bool LayerTouch::init()
{
if(Layer::init())
{
//添加点击监听(单点触摸)
EventListenerTouchOneByOne* tevent = EventListenerTouchOneByOne::create();
tevent->setSwallowTouches(true);
tevent->onTouchBegan = [&](Touch* touch, Event*){
for(auto key : m_clickDelegates)
{
key.second(touch);
}
//true 会继续监听后面的touch move,touch end等事件,false则不会
return false;
};
tevent->onTouchCancelled = [&](Touch*, Event*){
};
tevent->onTouchEnded = [&](Touch*, Event*){
};
tevent->onTouchMoved = [&](Touch*, Event*){
};
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(tevent,this);
return true;
}
return false;
}
LayerTouch* LayerTouch::create()
{
LayerTouch* tlayer = new LayerTouch();
if(tlayer && tlayer->init())
{
tlayer->autorelease();
return tlayer;
}else
{
CC_SAFE_RELEASE(tlayer);
}
return nullptr;
}
本文深入解析Cocos2d-x中的Touch事件机制,包括单点触摸和多点触摸的不同处理方式,以及如何通过事件监听进行交互设计。同时介绍了Cocos2d-x特有的内存回收机制,并对比了其与标准库std::map的不同之处。
7469

被折叠的 条评论
为什么被折叠?



