cocos2d-x如何解决背包物品拖动和翻页操作的冲突

问题:

游戏中经常都有背包,一般做法是在一个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

第一次写技术博客,希望大家多指点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值