问题:
游戏中经常都有背包,一般做法是在一个scrollview上放入一些物品,轻滑能翻页,物品能按住一会后变大,然后可拖动物品移动物品格子位置。
物品和scrollview都可以接收触摸事件,这导致两个操作冲突,也就是拖着物品移动的时候scrollview也会滚动。
探究:
经过研究,发现cocos2d-x注册事件的时候可以设置是否吞没事件(第三个参数),设置为false时表示不吞没事件,这样当前节点后面的那些节点也能收到触摸事件。
这样就可以实现触摸点落在物品上时也能滚动翻页。
void CTLayer::registerWithTouchDispatcher(void)
{
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
}
//看下这个方法的定义
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)
但是这个设置是在触摸事件的三个阶段都起效(ccTouchBegan,ccTouchMoved,ccTouchEnded)
是否可以根据情况设置三个阶段是否吞没事件呢?
我们来看下CCTouchDispatcher.cpp中的下面这个方法
void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)
我们发现有一段是这样写的:
if (bClaimed && pHandler->isSwallowsTouches())
{
if (bNeedsMutableSet)
{
pMutableTouches->removeObject(pTouch);
}
break;
}
他每次执行三个阶段中的方法时都会判断当前是否吞没,如果吞没的话就break了,后面的节点就不会再收到触摸事件。
因此我们可以在ccTouchBegan,ccTouchMoved,ccTouchEnded这三个方法处理过程中根据情况动态设置是否吞没事件
另见CCTargetedTouchHandler类中有void setSwallowsTouches(bool bSwallowsTouches);方法
class CC_DLL CCTargetedTouchHandler : public CCTouchHandler
{
public:
~CCTargetedTouchHandler(void);
/** whether or not the touches are swallowed */
bool isSwallowsTouches(void);
void setSwallowsTouches(bool bSwallowsTouches);
/** MutableSet that contains the claimed touches */
CCSet* getClaimedTouches(void);
/** 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;
CCSet *m_pClaimedTouches;
};
因此我们可以在ccTouchBegan,ccTouchMoved,ccTouchEnded这三个方法中使用
CCTargetedTouchHandler* handler = (CCTargetedTouchHandler*)CCDirector::sharedDirector()->getTouchDispatcher()->findHandler(this);
if(handler)
handler->setSwallowsTouches(isSwallow);
来动态设置是否吞没事件。
为方便,我修改了CCLayer.cpp,在里面加入这个方法,方便设置是否吞没事件。因为我们项目是用Lua编写的,也方便我们绑定方法到lua中。
void CCLayer::setSwallow(bool isSwallow)
{
CCTargetedTouchHandler* handler = (CCTargetedTouchHandler*)CCDirector::sharedDirector()->getTouchDispatcher()->findHandler(this);
if(handler)
handler->setSwallowsTouches(isSwallow);
}
接下来我要写个测试的层,我把它起名为CTLayer。(CT是custom的缩写)
CTlayer.h
#ifndef CTLALYER_H_
#define CTLALYER_H_
#include "cocos2d.h"
using namespace cocos2d;
class CTLayer : public CCLayerColor
{
public:
bool init();
CREATE_FUNC(CTLayer);
void onEnter();
void onExit();
virtual void registerWithTouchDispatcher(void);
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
};
#endif
实现:CTLayer.cpp
#include "CTLayer.h"
bool CTLayer::init()
{
CCLayerColor::init();
return true;
}
void CTLayer::registerWithTouchDispatcher(void)
{
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
}
long msNow()
{
struct cc_timeval now;
CCTime::gettimeofdayCocos2d( &now, NULL );
return ( now.tv_sec * 1000 + now.tv_usec / 1000 );
}
int lastTime = 0;
bool needSwallow = false;
bool CTLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
CCLog("began:%d", this->getTag());
if(this->getTag() == 20)
{
needSwallow = false;
int time = msNow();
int dur = time - lastTime ;
CCLog("time:%d", dur);
//双击按下,表示物品拖动,标志为吞没事件
if(dur < 500)
{
needSwallow = true;
}
lastTime = time;
}
return true;
}
void CTLayer::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
if(this->getTag() == 20 && needSwallow)
{
needSwallow = false;
this->setSwallow(true);
//也可以直接用下面的方法
//CCTargetedTouchHandler* handler = (CCTargetedTouchHandler*)CCDirector::sharedDirector()->getTouchDispatcher()->findHandler(this);
//handler->setSwallowsTouches(true);
//CCDirector::sharedDirector()->getTouchDispatcher()->setSwallow(this, true);
}
//获得触摸点初始坐标
CCPoint beginLoc = pTouch->getLocationInView();
beginLoc = CCDirector::sharedDirector()->convertToGL(beginLoc);
//获得前一个触摸点坐标
CCPoint endLoc = pTouch->getPreviousLocationInView();
endLoc = CCDirector::sharedDirector()->convertToGL(endLoc);
//计算偏移量
CCPoint offSet = ccpSub(beginLoc, endLoc);
this->setPosition(ccpAdd(this->getPosition(), offSet));
CCLog("move:%d", this->getTag());
}
void CTLayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
if(this->getTag() == 20)
{
//CCTargetedTouchHandler* handler = (CCTargetedTouchHandler*)CCDirector::sharedDirector()->getTouchDispatcher()->findHandler(this);
//handler->setSwallowsTouches(false);
//CCDirector::sharedDirector()->getTouchDispatcher()->setSwallow(this, false);
this->setSwallow(false);
}
CCLog("end:%d", this->getTag());
}
void CTLayer::onEnter()
{
CCLayerColor::onEnter();
CCLog("enter:%d", this->getTag());
}
void CTLayer::onExit()
{
CCLayerColor::onExit();
CCLog("exit:%d", this->getTag());
}
测试代码:
CTLayer* ctlayer = CTLayer::create();
ctlayer->setColor(ccc3(255, 0, 0));
ctlayer->setOpacity(150);
ctlayer->setTag(19);
ctlayer->setContentSize(CCSizeMake(100, 100));
ctlayer->setPosition(ccp(200, 200));
ctlayer->setTouchEnabled(true);
this->addChild(ctlayer);
CTLayer* ctlayer2 = CTLayer::create();
ctlayer2->setColor(ccc3(255, 255, 0));
ctlayer2->setOpacity(150);
ctlayer2->setContentSize(CCSizeMake(100, 100));
ctlayer2->setPosition(ccp(0, 0));
ctlayer2->setTouchEnabled(true);
ctlayer2->setTag(20);
ctlayer->addChild(ctlayer2);
这时双击按住拖动只有黄色块可以拖动,而直接点击拖动时红色和黄色块都会跟着移动
效果图:
转载请注明:http://blog.csdn.net/atsoar/article/details/10050429
第一次写技术博客,希望大家多指点。