-
cocos2d-x触摸分发器道理
添加时间:2013-7-1 点击量:
为了实现触摸事务,CCLayer已经封装好了简单的接口(持续了CCTouchDelegate类)来实现触摸事务的响应。
起首,触摸事务有两种:标准触摸和目标触摸。那么我们先看看如何开启这两种触摸。
1.标准触摸
在层初始化时调用setTouchEnable(true)办法即可实现标准触摸,实现处理惩罚事务回调函数,处理惩罚触摸事务即可。
// optional
virtual void ccTouchesBegan(CCSet pTouches, CCEvent pEvent)
virtual void ccTouchesMoved(CCSet pTouches, CCEvent pEvent)
virtual void ccTouchesEnded(CCSet pTouches, CCEvent pEvent)
virtual void ccTouchesCancelled(CCSet pTouches, CCEvent pEvent)第一个参数存放的是触摸点凑集,第二个参数为cocos2d-iphone遗留下的,在cocos2d-x中没有意义。那么在这4个触摸事务回调函数中参加事务处理惩罚代码即可。例:
void TouchLayer::ccTouchesMoved(CCSet pTouches, CCEvent pEvent)
{
if(pTouches->count() == 1)
{
CCTouch touch = dynamic_cast<CCTouch>(pTouches->anyObject());
//因为在不合平台下触摸点的坐标系与OpenGL浮现区域的参数可能不尽雷同,所以触摸点的地位凡是与体系相干,须做如下处理惩罚即可获取触摸点在游戏中的地位了
oint position = touch->locationInView();//获取游戏画面中的点地位
position = CCDirector::sharedDirector()->convertToGL(position);//把屏幕左边转换为游戏坐标
//此处处理惩罚触摸事务
}
else
{
//若是不止一个触摸点,则在此处处理惩罚多点触摸事务
}
}
那么来看看setTouchEnable做了什么事,才让触摸回调函数被调用的呢
void CCLayer::setTouchEnabled(bool enabled)
{
if (m_bTouchEnabled != enabled)
{
m_bTouchEnabled = enabled;
if (m_bRunning)
{
if (enabled)
{
this->registerWithTouchDispatcher();
}
else
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
}
}
}再进入registerWithTouchDispatcher办法中看到调用了pDispatcher->addStandardDelegate(this, 0)办法,也就是将该对象注册为标准。
对于标准,只要事务分发器接管到用户的触摸事务,就会分发给所有的订阅者;还有当体系存在多个触摸点时,所有的触摸点都邑传递给回调函数,然后很多景象下每个触摸点之间是自力的,屏幕上是否存在其他触摸点我们并不关怀。
2.我们在来看看目标:
要为该层应用目标,起首调用CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true)开启目标(第二个参数为优先级,第三个参数为是否吞噬触摸)。然后重载事务回调函数:
//重视返回类型,函数名,参数有什么不合
virtual bool ccTouchBegan(CCTouch pTouch, CCEvent pEvent)
// optional
virtual void ccTouchMoved(CCTouch pTouch, CCEvent pEvent)
virtual void ccTouchEnded(CCTouch pTouch, CCEvent pEvent)
virtual void ccTouchCancelled(CCTouch pTouch, CCEvent pEvent)第一个参数为CCTouch,已不再是凑集,而是一个触摸点。ccTouchBegan办法返回的是一个布尔值,注解声明是否要捕获传入的这个触摸点,返回true默示要捕获,那么在后面Moved和Ended中处理惩罚触摸事务即可。若是注册的时辰选择了要吞噬触摸,触摸事务不会再分发下去,则优先级低的对象无法接管到触摸。
那么实现一个对象的触摸就分为如下几步了:
1)此对象持续CCStandardTouchDelegate / CCTargetedTouchDelegate接口
2)应用addStandardDelegate / addTargetedDelegate办法把本身注册给触摸时候分发器CCTouchDispatcher
3)重载事务处理惩罚回调函数。(重视目标触摸开端时候Began中必须针对须要接管的事务返回true)
4)当不再须要接管触摸事务时,应用removeDelegate办法来刊出触摸事务的接管。
3. 触摸分发器道理
来看看CCDispatcher的首要成员
//注册标准触摸事务
void addStandardDelegate(CCTouchDelegate pDelegate, int nPriority);
//注册目标触摸事务
void addTargetedDelegate(CCTouchDelegate pDelegate, int nPriority, bool bSwallowsTouches);
//刊出触摸派发
void removeDelegate(CCTouchDelegate pDelegate);
void removeAllDelegates(void);
//从头设定指定对象的事务优先级
void setPriority(int nPriority, CCTouchDelegate pDelegate);
//分发事务
void touches(CCSet pTouches, CCEvent pEvent, unsigned int uIndex);
protected:
CCArray m_pTargetedHandlers; //记录注册了带目标的触摸事务对象
CCArray m_pStandardHandlers; //记录注册了标准触摸事务的对象
当触摸分发器从体系接管到触摸事务后,还须要一一分发给触摸处理惩罚对象,此中事务分发的相干代码首要集中在touches办法中。
// dispatch events
void CCTouchDispatcher::touches(CCSet pTouches, CCEvent pEvent, unsigned int uIndex)
{
//。。。。。。。。。
// 1。处理惩罚带目标的触摸事务
if (uTargetedHandlersCount > 0)
{
CCTouch pTouch;
CCSetIterator setIter;
//1.1 遍历每一个从体系接管到的触摸事务
for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter)
{
pTouch = (CCTouch )(setIter);
CCTargetedTouchHandler pHandler = NULL;
CCObject pObj = NULL;
//1.2 遍历每一个已注册目标触摸事务的对象,分发事务
CCARRAY_FOREACH(m_pTargetedHandlers, pObj)
{
pHandler = (CCTargetedTouchHandler )(pObj);
if (! pHandler)
break;
bool bClaimed = false;
//起首处理惩罚触摸开端时候
if (uIndex == CCTOUCHBEGAN)
{
bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);
if (bClaimed)
{
pHandler->getClaimedTouches()->addObject(pTouch);
}
} else
if (pHandler->getClaimedTouches()->containsObject(pTouch))
{//再处理惩罚移动、停止和作废事务
// moved ended canceled
bClaimed = true;
switch (sHelper.m_type)
{
case CCTOUCHMOVED:
pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent);
break;
case CCTOUCHENDED:
pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch);
break;
case CCTOUCHCANCELLED:
pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch);
break;
}
}
//若是此触摸被捕获,且注册的是吞噬触摸,则设置“吞噬触摸事务”
if (bClaimed && pHandler->isSwallowsTouches())
{
if (bNeedsMutableSet)
{
pMutableTouches->removeObject(pTouch);
}
break;
}
}
}
}
// 2. 处理惩罚标准触摸事务
if (uStandardHandlersCount > 0 && pMutableTouches->count() > 0)
{
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;
}
}
}
//。。。。。。
//删除 标识表记标帜为吞噬的触摸事务
}在触摸凑集中的每一个触摸点,遵守优先级询问每一个注册到分发器的对象。
拥有最低优先级(正无穷)的目标的优先级 要比 拥有高优先级(负无穷)的标准的优先级 高。
对于目标,只有在开端事务中返回true,后续事务(移动、停止、作废)才会持续分发给目标对象。
若是设置了吞噬,被捕获到的点会被吞噬掉,被吞噬的点将立即移除触摸凑集,不在分发给后续目标。
值得重视的是:接管触摸的对象并不必然正显示在屏幕上。触摸分发器和引擎中的画图是彼此对的,所以在不须要的时辰及时从触摸分发器中移除触摸。
所有随风而逝的都属于昨天的,所有历经风雨留下来的才是面向未来的。—— 玛格丽特·米切尔 《飘》