查看所有 quick 移植到 cocos2d-x lua 的文章
在 移植 quick2.2.3 的项目到 cocos2d-x 3.4 lua 中提到,我已经开始使用 cocos2d-x 3.4 lua 来开发目前公司的两个项目。
在这两个项目中,我将 cocos 的 lua 框架、quick 的 lua 框架和我自己开发的 lua 代码,全部整合到了我的 lua 项目 中。
下面提到的 quick 框架,都是指的我整合的这个 lua 项目。
使用 cocos2d-x 3.4 lua + quick 框架进行开发的时候,发现对于销毁再重建的按钮来说,有超过 30% 的几率无法响应触摸事件。
为了方便重现问题,我使用 quick 框架提供的 cc.ui.UIPushButton
做了测试。下面这段代码中 testUIButton()
方法会创建一个按钮,每次点击这个按钮时调用 newUIButton()
方法,这个方法销毁前面创建的按钮,然后再新建一个按钮。
这个新建的按钮,相当大的几率会出现无法响应触摸事件的情况。
function TestScene:ctor() self:testUIButton() end function TestScene:testUIButton() self._bi = 0 cc.ui.UIPushButton.new('normal.jpg') :setButtonSize(240, 60) :onButtonClicked(function(evt) self:newUIButton() end) :align(display.LEFT_CENTER, display.cx, display.cy) :addTo(self) end function TestScene:newUIButton() if self._bi > 0 then local name = 'btn'..self._bi self[name]:removeSelf(true) self[name] = nil end self._bi = self._bi + 1 name = 'btn'..self._bi local x = math.random(200) local y = math.random(200) self[name] = cc.ui.UIPushButton.new('normal.jpg') :setButtonSize(240, 60) :addTo(self) :align(display.CENTER, display.cx - x, display.cy - y) self[name]:onButtonClicked(function() print('--------------- test '.. name) end) end
用一个很简单的方法可以解决这个问题,修改 testUIButton()
方法,讲 newUIButton()
进行延迟调用即可:
function TestScene:testUIButton() self._bi = 0 cc.ui.UIPushButton.new('normal.jpg') :setButtonSize(240, 60) :onButtonClicked(function(evt) scheduler.performWithDelayGlobal(function() self:newUIButton() end, 0.1) end) :align(display.LEFT_CENTER, display.cx, display.cy) :addTo(self) end
但这是个恶心的解决方案。要知道具体的解决方案,就要知道这个 BUG 产生的原因。
当然,我上面的实现方式也是很恶心的。在一个按钮响应事件中创建一个按钮,在真实项目中应该不会这样使用。
不过,这个代码只是方便重现问题。在我们实际的项目中,只要是销毁之后再重建的按钮,就可能发生这种情况。而且,不仅仅是按钮,只要是继承 Node 的对象,销毁之后再重建,都会出现这个问题。
咨询了 cocos2d-x lua 开发组的 阳光七月 ,才知道原来这还是个历史遗留问题:
阳光七月 16:15:52
销毁的时候那个node标记为已经移除了,如果再创建时指针一样的话会判断为旧的,不会被添加触摸处理
Jacky 16:16:37
但是我已经换了变量名称,这样也会导致创建出相同的指针么?
阳光七月 16:17:18
在C++层创建与变量名称没有相关性啊
阳光七月 16:17:38
内存释放后又重新分配,当然有可能使用同一块内存
Jacky 16:17:54
是的,而且在同一段代码中,这种情况比较容易发生?
阳光七月 16:18:49
还是有不小机率的
阳光七月 16:21:13
估计不改Node是不行了
Jacky 16:21:41
Node 在 quick 里面不是改过么?
阳光七月 16:21:57
之前是想尽量不改-x的代码,在外面挂一层触摸模块
阳光七月 16:22:04
3.3之后没有改了
阳光七月 16:22:47
以现在为基础的话,改动应该也不大
阳光七月 16:23:01
主要是在Node释放时要处理一下
Jacky 16:23:25
quick2确实是没有这个问题的。
Jacky 16:23:42
如果在 C++层面这么写,也会有这个问题么?
阳光七月 16:24:09
肯定没有的,因为之前触摸模块是Node的一部分,不可能有问题
阳光七月 16:24:15
3.3之后才分开的
阳光七月 16:27:29
现在3.3之后是在lua层面收到onCleanup消息再回到C++层面释放触摸模块的
阳光七月 17:16:46
现在就是绕了个弯,在lua端收到onCleanup消息时再调用removeTouchEvent,这样的联系实在是不牢靠,所以问题也多
阳光七月 17:52:40
嗯,或者可以改一下引用机制,在底层延时销毁,上层不需要考虑这个细节。不过这样也要改Node,我后面再评估一下
看来,只需要坐等 cocos2d-x lua 开发组来修改就行啦。
(全文完)