1

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

我在我的游戏(2D 横向卷轴)中遇到了这个问题。帧率非常平滑(50+),除非当 scout 显示图像解压缩事件时,它会下降到 2 - 15 fps。它是可怕的。我添加的图像(屏幕上的图块)越多,这种情况就越多。

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

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

让我们从显而易见的和我的评论开始:

  1. 在 Flash Pro 上,任何导入(嵌入)的图像都应在其属性面板上设置为无解压/无损 PNG/GIF

评论:这确实有帮助,但解压仍然会导致通常的延迟问题。

  1. 与其拥有多个图块或图像,不如将它们合并为更大的图块或游戏或应用程序的每个“级别”单个图像。

评论:这也有很大帮助,原因很明显。图像更大,因此显示在整个屏幕上,或者在任何给定时间显示更多,因此 Flash 无法摆脱它。这确实是一个丑陋的解决方案,原因很明显:导入大图像时 Flash 崩溃,存在尺寸限制,并且通常在设计关卡或图形应用程序时很难处理大图像,而不是瓦片。但是,有时这可能会奏效。

  1. 有多个图像或图块,但将它们添加到屏幕上(必须具有 .visible = true),Flash 被迫将它们保存在内存中。

评论:它也可以工作,但比上面的解决方案更丑(如果它甚至可以被称为),它实际上只是一种解决方法,以防止 Flash 在导入大图像或达到最大尺寸时崩溃。不过,它确实有效。如果您只使用下面的位图作为形状对象的填充物,您可以将这些图像隐藏在其他 Flash 层或图像下面,有时对性能的影响很小。

  1. 使用 ImageDecodingPolicy.ON_LOAD。

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

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() 将对象保留在内存中。

评论:我读到这对某些人有效,但对我完全没有任何作用。这是非嵌入式资产代码中最重要的部分(保持位图解压缩):

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-3 一样。帧率不太好,但对我来说非常顺利地消除了由于解压而导致的打嗝。这当然可以通过代码来完成,例如 instance.cacheAsBitmap = true; 或者直接从 Flash Pro 的渲染选项下。

  1. 将 bitmapData 复制到新的 BitmapData 实例中,然后将原始资源留给垃圾收集器。从复制数据中获得相对较小的一次性 CPU 占用,并且您会短暂地使用额外的内存来保存解压缩位图的两个副本。但是,一旦你完成了,压缩数据也可以被释放。

评论:也没有为我做任何事情。我也不明白为什么它应该:

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 调用上的 counter++ 变量上的 50 个滴答声后调用它。

  • 你能提供另一种解决方法吗?

4

1 回答 1

-1

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

2)“如果您对此不熟悉,请注意,flash player 会从内存中删除不需要的、未显示在屏幕上的图像,并在您再次将它们移动到屏幕时重新解压缩它们。这据报道,大约每 10 秒发生一次。” 这似乎很奇怪。一旦您将压缩图像解压缩为 BitmapData,并且由于您引用了该 BitmapData,因此 GC 无法收集它,因此世界上没有任何事情可以让您违背自己的意愿对其进行解压缩。从来没有听说过 Flash Player 这样做。

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

于 2014-12-09T16:14:17.837 回答