A闪的 BLOG 技术与人文
很多人对cacheAsBitmap不理解,或者理解的不够透彻。 其实很多东西都非常简单,只要你能够以全局的角度来看到Egret,那么你就会发现原来很多东西如此简单。
在上一篇文章《Egret性能优化之优化渲染》中,我曾经提到过一个优化的东西叫做cacheAsBitmap的优化技巧。由于篇幅的关心,和我不想啰嗦太多,导致讲解的不够细致。cacheAsBitmap很多时候用处非常大。在大型项目中,带来的性能提升也会非常明显。
首先我需要你回忆一下Egret中的Main Loop。这个东西和cacheAsBitmap息息相关。如果你还不太明白这个东西,请回到《Egret性能优化之优化渲染》重新阅读。
我们先来看一段代码,并且看看运行后的效果。(只贴出了关键的代码片段)
private context:egret.Sprite = new egret.Sprite(); private createGameScene(): void { egret.Profiler.getInstance().run(); for( var i:number=0; i<12;i++ ) { for(var t:number=0;t<5;t++) { var bit:egret.Bitmap = new egret.Bitmap(); bit.texture = RES.getRes("image_png"); bit.x = 75t+41(i%2); bit.y = 48*i; bit.scaleX = 0.5; bit.scaleY = 0.5; this.context.addChild(bit); } } this.addChild(this.context); }注意,我在代码中创建了60个位图,并且有序的排列。将60个Bitmap放到一个Sprite中。运行后看到的效果如下:
此时你会发现,当前draw的数量为60。也就是说,在Main Loop中,每帧执行60次draw操作(Main Loop第四步)
我现在将代码简单的修改一下。
private context:egret.Sprite = new egret.Sprite(); private createGameScene(): void { egret.Profiler.getInstance().run(); for( var i:number=0; i<12;i++ ) { for(var t:number=0;t<5;t++) { var bit:egret.Bitmap = new egret.Bitmap(); bit.texture = RES.getRes("image_png"); bit.x = 75t+41(i%2); bit.y = 48*i; bit.scaleX = 0.5; bit.scaleY = 0.5; this.context.addChild(bit); } } this.addChild(this.context); this.context.cacheAsBitmap = true; }在运行一下,效果如图:
此时,draw变成了1。为什么会这样?到底在哪里会因为我将cacheAsBitmap设置为了true之后,draw变成了1呢?很简单,此时Sprite内部的60个位图被缓存为了1张位图。所以从60变成了1。
这个用法有个需要注意的地方,使用了cacheAsBitmap后,内部的元素将无法进行图形修改,除非你把cacheAsBitmap再设置为false。
为了解释这个问题,我们将代码稍微修改一下。
private context:egret.Sprite = new egret.Sprite(); private createGameScene(): void { egret.Profiler.getInstance().run(); for( var i:number=0; i<12;i++ ) { for(var t:number=0;t<5;t++) { var bit:egret.Bitmap = new egret.Bitmap(); bit.texture = RES.getRes("image_png"); bit.x = 75t+41(i%2); bit.y = 48*i; bit.scaleX = 0.5; bit.scaleY = 0.5; this.context.addChild(bit); } } this.addChild(this.context); this.context.cacheAsBitmap = true; this.context.width = egret.MainContext.instance.stage.stageWidth; this.context.height = egret.MainContext.instance.stage.stageHeight; this.context.touchEnabled = true; this.context.addEventListener(egret.TouchEvent.TOUCH_BEGIN,this.click,this); }当我点击了这个Sprite之后,我希望第一张位图,能够横向拉伸2倍。但是,通过下面的截图你会发现,图像并没有修改。为了方便查看效果,我特意在点击事件中输出了click字符。private click(evt:egret.TouchEvent):void { this.context.getChildAt(0).scaleX = 2; console.log("click"); this.context.x += 10; }
这说名了一个问题,cacheAsBitmap被启用后,其内部的可视化对象不在参与第三步与第四步操作。这里所谓的操作是指,当Main Loop遍历显示列表中元素的时候,认为Sprite内部就是一个Bitmap,而非60个。而这一个Bitmap是有引擎为你缓存出来的图像。
我们稍微修改一下代码,把设置cacheAsBitmap这行注释掉。你再来看一下效果。
private context:egret.Sprite = new egret.Sprite(); private createGameScene(): void { egret.Profiler.getInstance().run(); for( var i:number=0; i<12;i++ ) { for(var t:number=0;t<5;t++) { var bit:egret.Bitmap = new egret.Bitmap(); bit.texture = RES.getRes("image_png"); bit.x = 75t+41(i%2); bit.y = 48*i; bit.scaleX = 0.5; bit.scaleY = 0.5; this.context.addChild(bit); } } this.addChild(this.context); //this.context.cacheAsBitmap = true; this.context.width = egret.MainContext.instance.stage.stageWidth; this.context.height = egret.MainContext.instance.stage.stageHeight; this.context.touchEnabled = true; this.context.addEventListener(egret.TouchEvent.TOUCH_BEGIN,this.click,this); }private click(evt:egret.TouchEvent):void { this.context.getChildAt(0).scaleX = 2; console.log("click"); this.context.x += 10; }
非常明显的区别。
最后留一个问题,如果我像下面这样编写代码,最后看到效果如图,为什么会这样?
private context:egret.Sprite = new egret.Sprite(); private createGameScene(): void { egret.Profiler.getInstance().run(); for( var i:number=0; i<12;i++ ) { for(var t:number=0;t<5;t++) { var bit:egret.Bitmap = new egret.Bitmap(); bit.texture = RES.getRes("image_png"); bit.x = 75t+41(i%2); bit.y = 48*i; bit.scaleX = 0.5; bit.scaleY = 0.5; this.context.addChild(bit); } } this.addChild(this.context); this.context.cacheAsBitmap = true; this.context.getChildAt(0).scaleX = 2; console.log("click"); this.context.x += 10; }
欢迎大家来Egret社区讨论,bbs.egret-labs.org