yorhomwang 发表于 2015-2-27 15:23:12

ENTER_FRAME中删除自己导致闪烁bug的解决方案

在lufylegend.js中运行以下代码会出现闪烁的问题:LInit(50, "mygame", 600, 480, main);

var img = null;
var addIndex = 40, addSpeed = addIndex;

function main () {
        var loader = new LLoader();
        loader.addEventListener(LEvent.COMPLETE, demoInit);
        loader.load("./gold_ingot.png");
}
function demoInit (e) {
        img = e.target;

        var layer = new LSprite();
        addChild(layer);
        layer.addEventListener(LEvent.ENTER_FRAME, function (e) {
                var s = e.currentTarget;

                if (addIndex++ > addSpeed) {
                        addIndex = 0;

                        var item = new Item();
                        s.addChild(item);
                }
        });
}

function Item () {
        var s = this;
        LExtends(s, LSprite, []);

        var bmpd = new LBitmapData(img);
        var bmp = new LBitmap(bmpd);
        s.addChild(bmp);

        s.addEventListener(LEvent.ENTER_FRAME, s.loop);
}
Item.prototype.loop = function(e) {
        var s = e.currentTarget;

        s.x += 3;

        if (s.x > LGlobal.width) {
                s.remove();
        }
};测试地址:http://wyh.wjjsoft.com/test/blink_bug/index.html

出现这类问题是因为调用remove函数删除自己破坏了父元素显示列表。ENTER_FRAME事件是在LSprite对象渲染完毕时调度的,子LSprite元素渲染函数是在父元素遍历显示列表childList时调用的,所以在这里面删除自己会导致父元素还未完成遍历显示列表,显示列表就已经被破坏了。为此,我查看了lufylegend里LSprite的ll_show方法:_ll_show : function (c) {
        var s = this;
        s.graphics.ll_show();
        LGlobal.show(s.childList);
        s._ll_debugShape();
},可见,要解决这个问题,可以通过更改LGlobal.show方法来实现,原来的LGlobal.show的代码如下:LGlobal.show = function (s) {
        for (var i = 0, l = s.length; i < l; i++) {
                if (s && s.ll_show) {
                        s.ll_show();
                }
        }
};由于用变量l保存了列表的length属性,删除自己时length改变了,但是l并没有改变,所以就出现遍历错误的问题。
更改后的代码如下:LGlobal.show = function (s) {
        var list = s.slice(0, s.length);

        for (var i = 0, l = list.length; i < l; i++) {
                if (list && list.ll_show) {
                        list.ll_show();
                }
        }
};
更改后这个问题基本上就解决了
测试地址:http://wyh.wjjsoft.com/test/blink_bug/index2.html
除了上述的方法,还可以用一个数组保存需要删除的对象,在父元素的ENTER_FRAME事件中,清除这个列表里保存的对象,并清空这个数组。

lufy 发表于 2015-2-27 17:08:06

这样做虽然能解决你说的这个问题,但是每个显示对象都会每次拷贝(s.slice)自己的子对象数组,这样也会导致另外两个问题
第一个,就是内存使用量增加,这个影响倒不大
第二个,就是导致效率降低,画面上对象越多桢率越高,就会越明显,(数组自带的函数操作效率不高,如果想让效率更高,在高频率操作中,尽量避免数组的操作),虽然不能说这个非常严重,但是效率本来就是一点点来提升的,如果不注重每一个细节,积少成多,以后效率就会越来越慢,而且也不容易再改回来了

还是多谢了,这个地方我来想办法吧


除了上述的方法,还可以用一个数组保存需要删除的对象,在父元素的ENTER_FRAME事件中,清除这个列表里保存的对象,并清空这个数组。
如果开发中,真的碰到了这个问题,这个临时方案是可行的,因为不会影响到其他显示对象的列表操作

lufy 发表于 2015-2-27 17:53:31

lufy 发表于 2015-2-27 17:08 static/image/common/back.gif
这样做虽然能解决你说的这个问题,但是每个显示对象都会每次拷贝(s.slice)自己的子对象数组,这样也会导 ...

想了想,解决起来也并不太复杂,此问题1.9.8中解决

yorhomwang 发表于 2015-2-27 18:24:40

lufy 发表于 2015-2-27 17:53 static/image/common/back.gif
想了想,解决起来也并不太复杂,此问题1.9.8中解决

能说说思路吗?

yorhomwang 发表于 2015-2-27 18:25:49

本帖最后由 yorhomwang 于 2015-2-27 18:27 编辑

lufy 发表于 2015-2-27 17:53 static/image/common/back.gif
想了想,解决起来也并不太复杂,此问题1.9.8中解决
准备两套数组?

lufy 发表于 2015-2-27 21:52:32

yorhomwang 发表于 2015-2-27 18:25 static/image/common/back.gif
准备两套数组?

准备两套数组一样是浪费内存阿
还是等过两天新版本更新后直接看代码吧
页: [1]
查看完整版本: ENTER_FRAME中删除自己导致闪烁bug的解决方案