retain过的对象重新添加到场景中的问题

我在MainScene.lua的构造函数里创建了一个图片,代码如下:

 
self.node_ = display.newScale9Sprite("Button01.png", display.cx, display.cy, cc.size(500, 400), cc.rect(10, 10, 30, 30)) 
self.node_:retain()  
self.node_:setNodeEventEnabled(true, function(evt)  
    local name = evt.name  
    if name == "enter" then  
        self.node_:setTouchEnabled(true)  
        self.node_:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(evt)  
            print(evt.name)  
         end)  
    end 
end)

点击该图片会输出点击事件
我创建了该图片没有马上添加到场景上面,而是retain了

然后我在场景上面添加了一个按钮,用来控制上面的图片在场景上面的添加和删除
就是如果图片没被添加到场景时执行:

self.node_:addTo(self)

图片已经在场景时执行:

self.node_:removeSelf()

第一次点击按钮,图片被添加到场景上,点击图片,能正常输出点击事件
再点击按钮,图片从场景上移除
问题来了:再点击按钮,图片重新添加到场景, 点击图片,不输出点击事件了,这是为什么?

===================结贴=================

找到原因了,看看CCNode.cpp的cleanup函数和setTouchEnabled函数

void Node::cleanup()
{
// actions
this->stopAllActions();
this->unscheduleAllSelectors();

#if CC_ENABLE_SCRIPT_BINDING
if (_keyboardListener) {
_eventDispatcher->removeEventListener(_keyboardListener);
_keyboardListener = nullptr;
}
if (_accelerationListener) {
_eventDispatcher->removeEventListener(_accelerationListener);
_accelerationListener = nullptr;
}
if (_scriptEventDispatcher->hasScriptEventListener(NODE_EVENT))
{
ScriptEngineManager::getInstance()->getScriptEngine()->executeNodeEvent(this, kNodeOnCleanup);
}
#endif // #if CC_ENABLE_SCRIPT_BINDING

if (isTouchEnabled()) {
    unregisterWithTouchDispatcher();
}

// timers
for( const auto &child: _children)
    child->cleanup();

}


void Node::setTouchEnabled(bool enabled)
{
if (m_bTouchEnabled != enabled)
{
m_bTouchEnabled = enabled;
//if (_running)
{
if (enabled)
{
registerWithTouchDispatcher();
}
else
{
unregisterWithTouchDispatcher();
}
}
}
}

红字部分直接运行unregisterWithTouchDispatcher()来让对象触摸失效,跟setTouchEnabled(false)的区别就在于有没将m_bTouchEnabled设为false
当对象重新添加到场景时执行setTouchEnabled(true),函数发现m_bTouchEnabled还是为true,所以就没让对象触摸生效了

为什么cleanup函数里要用unregisterWithTouchDispatcher()而不用setTouchEnabled(false)呢??


原来的代码改为这样就可以运行:
self.node_ = display.newScale9Sprite(“Button01.png”, display.cx, display.cy, cc.size(500, 400), cc.rect(20, 20, 48, 38))
self.node_:retain()
self.node_:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(evt)
print(evt.name)
end)
self.node_:setNodeEventEnabled(true, function(evt)
local name = evt.name
if name == “enter” then
self.node_:setTouchEnabled(true)
elseif name == “exit” then
self.node_:setTouchEnabled(false)
end
end)

重新设置点击事件的监听

没看见已经设置了吗?
在第一块代码的第6行开始

自己顶一个,望大大们解答

移除后连setNodeEventEnabled都已经失效了的,你连“enter”这个消息都进不来吧

能进,你试试就知道

找到原因了,看看CCNode.cpp的cleanup函数和setTouchEnabled函数

void Node::cleanup()
{
// actions
this->stopAllActions();
this->unscheduleAllSelectors();

#if CC_ENABLE_SCRIPT_BINDING
if (_keyboardListener) {
_eventDispatcher->removeEventListener(_keyboardListener);
_keyboardListener = nullptr;
}
if (_accelerationListener) {
_eventDispatcher->removeEventListener(_accelerationListener);
_accelerationListener = nullptr;
}
if (_scriptEventDispatcher->hasScriptEventListener(NODE_EVENT))
{
ScriptEngineManager::getInstance()->getScriptEngine()->executeNodeEvent(this, kNodeOnCleanup);
}
#endif // #if CC_ENABLE_SCRIPT_BINDING

if (isTouchEnabled()) {
    unregisterWithTouchDispatcher();
}

// timers
for( const auto &child: _children)
    child->cleanup();

}

void Node::setTouchEnabled(bool enabled)
{
if (m_bTouchEnabled != enabled)
{
m_bTouchEnabled = enabled;
//if (_running)
{
if (enabled)
{
registerWithTouchDispatcher();
}
else
{
unregisterWithTouchDispatcher();
}
}
}
}

红字部分直接运行unregisterWithTouchDispatcher()来让对象触摸失效,跟setTouchEnabled(false)的区别就在于有没将m_bTouchEnabled设为false
当对象重新添加到场景时执行setTouchEnabled(true),函数发现m_bTouchEnabled还是为true,所以就没让对象触摸生效了

为什么cleanup函数里要用unregisterWithTouchDispatcher()而不用setTouchEnabled(false)呢??

确实是个bug,楼主递交一个PR吧

额…不会搞哈

我现在用3.3final还是有问题,之前3.3rc1是没有问题的。期待你的回复