Cocos2dx之touch事件
今天看了下ccocos2dx touch事件部分的源码,从CCTouch、CCTouchHandler和CCTouchDispatcher简单的做了分析和总结,先直接看源码吧!
1、CCTouch
class CC_DLL CCTouch : public CCObject
{
public:
CCTouch()
: m_nId(),
m_startPointCaptured(false)
{} /** returns the current touch location in OpenGL coordinates */
CCPoint getLocation() const;//获取当前touch位置,该位置基于OpenGL坐标
/** returns the previous touch location in OpenGL coordinates */
CCPoint getPreviousLocation() const;//获取前一次touch位置,该位置基于OpenGL坐标
/** returns the start touch location in OpenGL coordinates */
CCPoint getStartLocation() const;//获取该touch的起始位置,该位置基于OpenGL坐标
/** returns the delta of 2 current touches locations in screen coordinates */
CCPoint getDelta() const; //获取前后两次位置的偏移量,基于OpenGL坐标
/** returns the current touch location in screen coordinates */
CCPoint getLocationInView() const; //当前touch位置,该位置基于屏幕坐标位置
/** returns the previous touch location in screen coordinates */
CCPoint getPreviousLocationInView() const; //获取touch前一次的位置,基于屏幕坐标位置
/** returns the start touch location in screen coordinates */
CCPoint getStartLocationInView() const; //获取touch起始位置,基于屏幕坐标位置 void setTouchInfo(int id, float x, float y)
{
m_nId = id;
m_prevPoint = m_point;
m_point.x = x;
m_point.y = y;
if (!m_startPointCaptured)
{
m_startPoint = m_point;
m_startPointCaptured = true;
}
} int getID() const
{
return m_nId;
} private:
int m_nId;
bool m_startPointCaptured;
CCPoint m_startPoint;
CCPoint m_point;
CCPoint m_prevPoint;
};
CCTouch中有三个主要成员,m_startPoint、m_point、m_prevPoint,这三个点都是基于屏幕坐标。将这三个点转化为OpenGL坐标可以用CCDirector::sharedDirector()->convertToGL(m_point)函数来转化。
2、CCTouchHandler、CCStandardTouchHandler和CCTargetedTouchHandler
class CC_DLL CCTouchHandler : public CCObject
{
public:
virtual ~CCTouchHandler(void); /** delegate */
CCTouchDelegate* getDelegate(); //获取touch代理
void setDelegate(CCTouchDelegate *pDelegate); //设置touch代理 /** priority */
int getPriority(void); //获取代理优先级
void setPriority(int nPriority); //获取代理优先级 /** enabled selectors */
int getEnabledSelectors(void); //
void setEnalbedSelectors(int nValue); /** initializes a TouchHandler with a delegate and a priority */
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority); public:
/** allocates a TouchHandler with a delegate and a priority *///创建一个CCTouchHandler
static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority); protected:
CCTouchDelegate *m_pDelegate; //touch代理
int m_nPriority; //优先级
int m_nEnabledSelectors; //该成员没看出来有什么作用
};
CCTouchHandler主要将touch代理和优先级封装起来,CCTouchHandler还有两个派生对象: CCStandardTouchHandler和CCTargetedTouchHandler。这两个派生类很简单不需多说,简单的贴上代码吧。
class CC_DLL CCStandardTouchHandler : public CCTouchHandler
{
public:
/** initializes a TouchHandler with a delegate and a priority */
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority); public:
/** allocates a TouchHandler with a delegate and a priority */
static CCStandardTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
};
class CC_DLL CCTargetedTouchHandler : public CCTouchHandler
{
public:
~CCTargetedTouchHandler(void); /** whether or not the touches are swallowed */
bool isSwallowsTouches(void); //是否吞掉CCTouch
void setSwallowsTouches(bool bSwallowsTouches); //设置是否吞掉CCTouch /** MutableSet that contains the claimed touches */
CCSet* getClaimedTouches(void); //获取将要处理的CCTouch的集合 /** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow); public:
/** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
static CCTargetedTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow); protected:
bool m_bSwallowsTouches; //处理CCTouch后是否吞掉该CCTouch
CCSet *m_pClaimedTouches; //要处理的CCTouch集合
};
3、CCTouch事件分发器CCTouchDispatcher
class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
{
public:
~CCTouchDispatcher();
bool init(void);
CCTouchDispatcher()
: m_pTargetedHandlers(NULL)
, m_pStandardHandlers(NULL)
, m_pHandlersToAdd(NULL)
, m_pHandlersToRemove(NULL) {} public:
/** Whether or not the events are going to be dispatched. Default: true */
bool isDispatchEvents(void); //事件是否要被分发
void setDispatchEvents(bool bDispatchEvents); //设置是否分发事件 /** Adds a standard touch delegate to the dispatcher's list.
See StandardTouchDelegate description.
IMPORTANT: The delegate will be retained.
*/
void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority); //向标准代理容器添加代理 /** Adds a targeted touch delegate to the dispatcher's list.
See TargetedTouchDelegate description.
IMPORTANT: The delegate will be retained.
*/
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches); //向目标代理容器添加代理 /** Removes a touch delegate.
The delegate will be released
*/
void removeDelegate(CCTouchDelegate *pDelegate);//移除特定代理 /** Removes all touch delegates, releasing all the delegates */
void removeAllDelegates(void);//移除所有代理 /** Changes the priority of a previously added delegate. The lower the number,
the higher the priority */
void setPriority(int nPriority, CCTouchDelegate *pDelegate);//设置特定代理的优先级 void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex); //分发事件逻辑处理,主要看的函数
//以下是对四种事件的处理
virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent); public:
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate); //根据代理查找特定CCTouchHandler
protected:
void forceRemoveDelegate(CCTouchDelegate *pDelegate);
void forceAddHandler(CCTouchHandler *pHandler, CCArray* pArray);
void forceRemoveAllDelegates(void);
void rearrangeHandlers(CCArray* pArray); //重新根据优先级对代理排序
CCTouchHandler* findHandler(CCArray* pArray, CCTouchDelegate *pDelegate); protected:
CCArray* m_pTargetedHandlers; //目标事件代理容器
CCArray* m_pStandardHandlers; //标准事件代理容器 bool m_bLocked; //是否被锁
bool m_bToAdd; //是否需要添加
bool m_bToRemove; //是否需要删除
CCArray* m_pHandlersToAdd; //要添加的代理容器
struct _ccCArray *m_pHandlersToRemove; //要删除的代理容器
bool m_bToQuit; //是否要退出
bool m_bDispatchEvents; //是否要处理touch事件 // 4, 1 for each type of event
struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];
};
我们主要看一看void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex); 这个函数看看touch事件分发器是如何实现事件的分发。先贴上该函数源码
void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)
{
CCAssert(uIndex >= && uIndex < , ""); //检查4种touch事件的类型 CCSet *pMutableTouches;
m_bLocked = true; //正在进行事件分发的时候先锁定,避免代理容器内部发生变化 // optimization to prevent a mutable copy when it is not necessary
unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count(); //获取目标事件代理个数
unsigned int uStandardHandlersCount = m_pStandardHandlers->count(); //获取标准事件代理个数
bool bNeedsMutableSet = (uTargetedHandlersCount && uStandardHandlersCount); //需不需要拷贝CCTouch容器 pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches); //拷贝CCTouch容器用于向标准touch代理分发事件 struct ccTouchHandlerHelperData sHelper = m_sHandlerHelperData[uIndex];
//
// process the target handlers 1st
//
if (uTargetedHandlersCount > )
{
CCTouch *pTouch;
CCSetIterator setIter;
for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter) //遍历CCTouch集合
{
pTouch = (CCTouch *)(*setIter); CCTargetedTouchHandler *pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pTargetedHandlers, pObj) //对于每一个CCTouch,遍历每一个目标事件代理处理器
{
pHandler = (CCTargetedTouchHandler *)(pObj); if (! pHandler)
{
break;
} bool bClaimed = false; //是否要得到处理
if (uIndex == CCTOUCHBEGAN)
{
bClaimed=pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);//调用代理的ccTouchBegan函数
if (bClaimed) //如果ccTouchBegan函数返回true,说明事件要被处理
{
pHandler->getClaimedTouches()->addObject(pTouch); //将该touch事件加入到该touch事件处理器的待处理事件容器中
}
} else
if (pHandler->getClaimedTouches()->containsObject(pTouch)) //判断handler内是否有该CCTouch
{
// moved ended canceled
bClaimed = true; //标记要被处理 switch (sHelper.m_type)
{
case CCTOUCHMOVED:
pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent); //注意处理CCTouchMoved 不会移除相应CCTouch
break;
case CCTOUCHENDED:
pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch); //从代理handler中的要处理的CCTouch容器中移除该CCTouch
break;
case CCTOUCHCANCELLED:
pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch); //从代理handler中的要处理的CCTouch容器中移除该CCTouch
break;
}
} if (bClaimed && pHandler->isSwallowsTouches()) //已经被处理并且要吞掉
{
if (bNeedsMutableSet) //
{
pMutableTouches->removeObject(pTouch); //从用于向标准代理分发事件的容器中移除该CCTouch
} break;
}
}
}
} //
// process standard handlers 2nd
//处理标准事件的分发,比目标事件简单
if (uStandardHandlersCount > && pMutableTouches->count() > )
{
CCStandardTouchHandler *pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pStandardHandlers, pObj)
{
pHandler = (CCStandardTouchHandler*)(pObj); if (! pHandler)
{
break;
} switch (sHelper.m_type)
{
case CCTOUCHBEGAN:
pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent);
break;
case CCTOUCHMOVED:
pHandler->getDelegate()->ccTouchesMoved(pMutableTouches, pEvent);
break;
case CCTOUCHENDED:
pHandler->getDelegate()->ccTouchesEnded(pMutableTouches, pEvent);
break;
case CCTOUCHCANCELLED:
pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent);
break;
}
}
} if (bNeedsMutableSet)
{
pMutableTouches->release(); //释放掉拷贝过来用于分发标准事件的touch集合
} //
// Optimization. To prevent a [handlers copy] which is expensive
// the add/removes/quit is done after the iterations
//
m_bLocked = false; //解除锁定
if (m_bToRemove) //有需要被移除的代理
{
m_bToRemove = false;
for (unsigned int i = ; i < m_pHandlersToRemove->num; ++i)
{
forceRemoveDelegate((CCTouchDelegate*)m_pHandlersToRemove->arr[i]);
}
ccCArrayRemoveAllValues(m_pHandlersToRemove);
} if (m_bToAdd) //有需要被添加的代理
{
m_bToAdd = false;
CCTouchHandler* pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pHandlersToAdd, pObj)
{
pHandler = (CCTouchHandler*)pObj;
if (! pHandler)
{
break;
} if (dynamic_cast<CCTargetedTouchHandler*>(pHandler) != NULL)
{
forceAddHandler(pHandler, m_pTargetedHandlers);
}
else
{
forceAddHandler(pHandler, m_pStandardHandlers);
}
} m_pHandlersToAdd->removeAllObjects();
} if (m_bToQuit) //需要退出
{
m_bToQuit = false;
forceRemoveAllDelegates(); //删除所有代理
}
}
从代码中我们可以清楚的看到时间分发的逻辑,cocos2dx将代理分为两种类型:标准事件代理和目标事件代理,事件分发的时候分别处理;事件分为四种事件,CCTOUCHBEGAN、CCTOUCHMOVED、CCTOUCHENDED和CCTOUCHCANCELLED;当调用目标代理的ccTouchBegan函数返回为真说明改代理需要处理该事件,并将该事件暂存到CCTargetedTouchHandler得集合中,当调用ccTouchMoved、ccTouchEnded和ccTouchCanceled时若该代理是否要吞掉该事件则删除标准容器中的该事件。标准事件的分发比较简单略过,还有一点就是,cocos2dx在进行事件分发的时候,将两种容器锁定,避免分发事件的时候容器中的代理有变化,事件分发结束后再将该添加的代理添加,该删除的代理删除。
4、CCTouch、CCTouchHandler和CCTouchDispatcher之间的关系如下图所示:
Cocos2dx之touch事件的更多相关文章
- cocos2d-x中处理touch事件
在cocos2d-x中, touch事件分为两种:一种是单点事件, 另一种是多点事件. 单点事件对应的代理方法是: virtual bool ccTouchBegan(CCTouch *pTouch, ...
- cocos2dx 3.1从零学习(三)——Touch事件(回调,反向传值)
第三讲 Touch 前面两篇我们学习的内容,足够我们做一款简单的小游戏.也能够说,我们已经入门了,能够蹒跚的走路了. 本篇将解说cocos2dx中非常重要的touch回调机制.你肯定记得第一章做定时器 ...
- cocos2d-x Touch 事件应用的一个例子
1效果图: 这个是<Cocos2d-X by Example Beginner's Guide>上的第一个例子,我稍微重构了下代码.是一个简单的IPad上的双人游戏,把球射入对方的球门就得 ...
- 深入cocos2d-x中的touch事件
深入cocos2d-x中的touch事件 在文章cocos2d-x中处理touch事件中简单讨论过怎样处理touch事件, 那么今天来深入了解下cocos2d-x中是怎样分发touch事件的. 我们最 ...
- cocos2d-x中关于touch事件的响应
原作者:有缘人 来源:新浪微博 地址:http://blog.sina.com.cn/s/blog_6ac2c7260102vvdu.html 一.touch事件响应分为单点触摸响应和多点触摸响应. ...
- cocos2d-x lua 触摸事件
cocos2d-x lua 触摸事件 version: cocos2d-x 3.6 1.监听 function GameLayer:onEnter() local eventDispatcher = ...
- CCLayer在Touch事件(Standard Touch Delegate和Targeted Touch Delegate)
在做练习,触摸故障,看到源代码,以了解下触摸事件. 练习操作:直CClayer子类init在 this->setTouchEnabled(true); 事件处理方法覆盖 virtual bool ...
- UC浏览器中touch事件的异常记录
以前也在UC上面栽过几个坑,不过都是页面显示方面的.上个周的时候,商品详情页重做,要添加个上拉显示详情的效果. 有两个条件需要判断: 1.是否到达底部: 2.到达底部之后拖动的y轴距离. 效果写完后, ...
- 移动端开发概览【webview和touch事件】
作为一个前端,而且作为一个做移动端开发的前端,那意味着你要有三头六臂,跟iOS开发哥哥一起打酱油,跟Android开发哥哥一起修bug... Android vs Ios 我在webkit内核的chr ...
随机推荐
- Mac下docker搭建lnmp环境 + redis + elasticsearch
之前在windows下一直使用vagrant做开发, 团队里面也是各种开发环境,几个人也没有统一环境,各种上线都是人肉,偶尔还会有因为开发.测试.生产环境由于软件版本或者配置不一致产生的问题, 今年准 ...
- ASP.NET Ajax 客户端框架未能加载、"Sys"未定义
在Windows Server 2003 系统上部署asp.net项目出现以下问题: IIS为6.0 导致菜单控件的图片显示不出来: WebSite:程序中的图片显示正常. 但用到ASP.net 2. ...
- MOSS 2013研究系列---列表的资源限制
MOSS2010 以后,对列表的条目数做了一些限制,大量的将数据存储在列表中,会降低列表的运行效能,因此,MOSS中对列表默认有了一个阀值,默认是5000条数据,当你存储的数据多余5000条的时候,用 ...
- mqtt 异步消息 长连接 解析
mqtt 是轻量级基于代理的发布/订阅的消息传输协议,设计思想是开放,简单,轻量级,且易于实现,这些优点使得他受用于任何环境 该协议的特点有: 使用发布/订阅消息的模式,提供一对多的消息发布,解除应用 ...
- 【学习记录】二分查找的C++实现,代码逐步优化
二分查找的思想很简单,它是针对于有序数组的,相当于数组(设为int a[N])排成一颗二叉平衡树(左子节点<=父节点<=右子节点),然后从根节点(对应数组下标a[N/2])开始判断,若值& ...
- C++中如何在顺序容器中删除符合特定条件的元素
以前很少做删除操作,vector一直当成数组用,而实际追求效率时又经常舍弃vector选用C风格数组.看<C++ Primer>到顺序容器删除这节时试着实现课后习题结果一动手我就出错了. ...
- 黄聪:WordPress默认编辑器可视化切换不见了,非插件导致消失问题
1.后台---用户---我的个人资料 2.看看 [可视化编辑器]的[撰写文章时不使用可视化编辑器]项目是不是勾上了 3.去掉保存即可
- github打不开问题
修改host 185.31.17.184 github.global.ssl.fastly.net 207.97.227.239 http://github.com 65.74.177.129 htt ...
- Java-Runoob-高级编程:Java 网络编程
ylbtech-Java-Runoob-高级编程:Java 网络编程 1.返回顶部 1. Java 网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.n ...
- [转]Jsp 常用标签
<jsp:include> 动态引入,涉及到的多个 jsp 页面会翻译成多个 servlet 并在执行时合并. include 指令 是静态引入,涉及到的多个 jsp 页面会翻译成一个 s ...