setTouchPriority sometimes doesn't work due to a bug in CCTouchDispatcher
setTouchPriority sometimes doesn't work due to a bug in CCTouchDispatcher
Bug #4317 [New]
If the priority is changed we have the CCTouchHandler present both in m_pHandlersToRemove and m_pHandlersToAdd. But in CCTouchDispatcher::touches we first iterate m_pHandlersToRemove and than m_pHandlersToAdd. So the CCTouchHandler stays and there is no memory leak.
Status: | New | |
---|---|---|
Start date: | 2014-03-09 | |
Priority: | Low | |
Due date: | ||
Assignee: | - | |
% Done: | 0% |
|
Category: | all | |
Target version: | - |
The problem is in version 2.2.2. The bug was introduced in this fix: http://cocos2d-x.org/issues/752
Test case:
I created a Layer, which has a sole purpose to block ("swallow"
touches, and this feature can be turned on and off.
The class is very basic, if it receives the touch it always swallows it:
`bool BlockingLayer::init(){
// Super init.
if ( !CCLayer::init() )
{
return false;
}
setTouchEnabled(true);
setTouchMode(kCCTouchesOneByOne);
setTouchPriority(INT_MAX);
return true;
}
bool BlockingLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
CCLOG("BlockingLayer swallowed touch!");
return true;
}
So by default it has a really bad priority, it receives touches if no other class claimed it. But in the scene where I am using this layer I would like to set it to a different priority when certain events occur:
bool MyScene::init(int unitNumber, CCString* path){
// Super init.
...
blockingLayer = BlockingLayer::create();
this->addChild(blockingLayer);
return true;
}
bool MyScene::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
blockingLayer->setTouchPriority(INTMIN);
}`
Now the layer should have the best priority possible, so it should swallow all touches. But it does not, it's behaviour does not change.
I see its registerWithTouchDispatcher() called and the m_nTouchPriority changed correctly. BUT the layer's behaviour is unchanged.
Fix:
As wondeful18 suggested:
Replace in addStandardDelegate and addTargetedDelegate:
this:
if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))
{
ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
return;
}
to this:
if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))
{
CCTouchHandler *pOldHandler = findHandler(pDelegate);
if (pOldHandler && pOldHandler->getPriority() == nPriority)
{
ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
return;
}
}