如何减少由于AIR,Flash应用程序上的图像解压缩导致的滞后或性能问题?

时间:2014-10-10 16:37:47

标签: actionscript-3 flash air compression adobe-scout

正如Adobe's Scout的许多用户已经注意到的那样,解压缩图像可能是对帧速率敏感的应用程序(例如游戏)的最大性能打击。

我的游戏中遇到了问题(2D侧卷轴)。帧率非常平滑(50+),除非侦察显示图像解压缩事件,然后降至2 - 15 fps。太可怕了。我添加的图像越多(屏幕上的图块)就越多。

如果您对此不熟悉,请注意闪存播放器会从内存中删除不需要的图像,而不会显示在屏幕上,并在移动到图像后重新解压缩它们屏幕再次。据报道,大约每10秒发生一次。

我想分享我的解决方案并询问你自己的一些解决方案,因为我认为目前的情况远非令人满意。

让我们从明显和我的评论开始:

  1. 在Flash Pro上,任何导入(嵌入)的图像都应在其属性面板上设置,以便无解压缩/无损PNG / GIF
  2. 评论:这有帮助,但减压仍然会发生,导致通常的滞后问题。

    1. 不是使用多个图块或图像,而是将它们合并到较大的图块中,或者按照每个级别的图像进行合并。你的游戏或应用程序。
    2. 评论:由于显而易见的原因,这也有很大帮助。图像较大,因此显示在所有屏幕上,或者在任何给定时间显示更多,因此Flash无法摆脱它。这实际上是一个丑陋的解决方案,原因显而易见:导入大图像时Flash崩溃,存在尺寸限制,并且在设计关卡或图形应用程序而非图块时通常很难处理大图像。但是,有时这可行。

      1. 拥有多个图片或图块,但在屏幕上添加它们(必须具有.visible = true),并强制将Flash保留在内存中。
      2. 评论:它确实有用,但它甚至比上面的解决方案更糟糕(如果它甚至可以称之为),它实际上只是一种解决方法,可以防止Flash在导入大图像时崩溃或者如果你达到最大尺寸。它可以做到这一点。如果您只使用下面的位图作为形状对象的填充,您可以将这些图像隐藏在其他闪光层或图像下面,有时只有很少的性能命中。

        1. 使用ImageDecodingPolicy.ON_LOAD。
        2. 评论:在我的游戏中,这本身几乎没有任何区别,但是当我将它与解决方案一混合时,它似乎有点帮助。这是代码:

          var loaderContext:LoaderContext = new LoaderContext(); 
          loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD 
          var loader:Loader = new Loader(); 
          loader.load(new URLRequest("gameLevel.swf"), loaderContext);
          

          我知道这通常用于加载位图,但它适用于swf,尽管只是略有不足。

          1. 在bitmapData对象上使用getPixel()将对象保留在内存中。
          2. 评论:我读过这对某些人有用,但对我来说绝对没有。这是非嵌入资产(Keeping Bitmaps Decompressed)代码中最重要的部分:

            var bmd:BitmapData;
            var timer:Timer = new Timer(1000);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, onTimer); 
            
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
            loader.load(new URLRequest("Adobe_Flash_Professional_CS5_icon.png"))
            
            function onLoaded(ev:Event): void
            {
                bmd = ((ev.target as LoaderInfo).content as Bitmap).bitmapData;
            }
            
            function onTimer(ev:TimerEvent): void
            {
                bmd.getPixel(0, 0);
            }
            

            如果你像我一样,并使用嵌入式图像,你可以使用以下内容调整代码:

            //be sure to set the library item on Flash Pro to be exported to ActionScript 3, 
            //and give it a class name, in this case Artwork.
            
            var Artwork:Class;
            Artwork = getDefinitionByName(Artwork) as Class;
            bmd  = new Artwork();
            

            然后只需每隔10秒调用一次getPixel()函数将图像回收到内存中。

            太糟糕了,它对我来说没什么意义!!

            1. 将Bitmap缓存为Bitmap,即使它已经是位图,也可以强制Flash播放器算法将其保留在内存中。
            2. 评论:这非常有效,几乎与伪解决方案" 2-3。帧速率不是很好,但它可以非常顺利地消除由于减压引起的打嗝。这当然可以通过代码来完成,例如instance.cacheAsBitmap = true;或者直接在渲染选项下直接使用Flash Pro。

              1. 将bitmapData复制到新的BitmapData实例中,然后将原始资源保留到垃圾收集器中。从复制数据中获取相对较小的一次性CPU命中,并且您将短暂地使用额外的内存来保存解压缩位图的两个副本。但是,一旦完成,压缩数据也可以被释放。
              2. 评论:也没为我做过一件事。我也不明白为什么它应该:

                var loadedBitmapData = event.target.content.bitmapData;
                var newBitmapData:BitmapData = new BitmapData(loadedBitmapData.width,loadedBitmapData.height);
                newBitmapData.copyPixels(loadedBitmapData,new Rectangle(0,0,loadedBitmapData.width, loadedBitmapData.height),new Point(0,0));
                

                这就是我所尝试过的,但正如你所能想象的那样,我对这些管道录音带很不满意。对我来说,这些看起来都是平庸的补丁,可能除了解决方案4和5之外,除了它们并不能为我做任何事情。

                所以,这是我的问题:

                • 您能否帮助我探索为什么解决方案5和7不会出现问题的答案。为我工作?我在代码中使用嵌入式图像选项,而不是使用计时器,在enterFrame调用的计数器++变量上50个刻度后调用它。

                • 您能提供其他解决方法吗?

1 个答案:

答案 0 :(得分:-1)

1)你显然没有在你的项目中使用Stage3D,否则你可以使用Adobe Texture Format,这在UI冻结问题上更加方便。

2)"如果您对此不熟悉,请注意Flash播放器会从内存中删除不需要"的图像,屏幕上不显示,并重新解压缩一旦你再次将它们移动到屏幕上。据报道,大约每10秒发生一次。"这看起来很怪异。将压缩图像解压缩为BitmapData后,由于您引用了BitmapData,因此GC无法收集它,因此世界上没有任何东西可以让您根据自己的意愿对其进行解压缩。从未听说过Flash Player这样做。

3)如果您从本地文件系统而不是从远程文件服务器加载图像,请尝试使用FileStream.openAsync将文件加载为bytearray,然后使用第三方PNGDecoder对其进行解码。不确定嵌入式资产。