3

我有一个由 42 帧组成的大精灵表 (3808x1632)。我会用这些帧呈现一个动画,然后我使用一个线程来加载一个包含所有帧的位图数组,并用一个初始屏幕等待它的结束。我没有使用 SurfaceView(和画布的绘制功能),我只是在我的主布局中的 ImageView 中逐帧加载。我的做法类似于Loading a large number of images from a spritesheet 完成实际上需要将近15秒,不能接受。

我使用这种功能:

for (int i=0; i<TotalFramesTeapotBG; i++) {
            xStartTeapotBG = (i % framesInRowsTeapotBG) * frameWidthTeapotBG; 
            yStartTeapotBG = (i / framesInRowsTeapotBG) * frameHeightTeapotBG;
            mVectorTeapotBG.add(Bitmap.createBitmap(framesBitmapTeapotBG, xStartTeapotBG, yStartTeapotBG, frameWidthTeapotBG, frameHeightTeapotBG));
        }

framesBitmapTeapotBG 是大精灵表。更深入地看,我在logcat中读到createBitmap函数需要很多时间,可能是因为spritesheet太大了。我找到了可以在大精灵表上创建一个窗口的地方,使用 rect 函数和画布,创建要加载到数组中的小位图,但不是很清楚。我说的是那个帖子:cut the part of bitmap

我的问题是:如何加快 spritesheet 切割的速度?

编辑:我正在尝试使用这种方法,但我看不到最终动画:

    for (int i=0; i<TotalFramesTeapotBG; i++) {
        xStartTeapotBG = (i % framesInRowsTeapotBG) * frameWidthTeapotBG; 
        yStartTeapotBG = (i / framesInRowsTeapotBG) * frameHeightTeapotBG;
        Bitmap bmFrame = Bitmap.createBitmap(frameWidthTeapotBG, frameHeightTeapotBG, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmFrame); 
        Rect src = new Rect(xStartTeapotBG, yStartTeapotBG, frameWidthTeapotBG, frameHeightTeapotBG); 
        Rect dst = new Rect(0, 0, frameWidthTeapotBG, frameHeightTeapotBG);  
        c.drawBitmap(framesBitmapTeapotBG, src, dst, null);         
        mVectorTeapotBG.add(bmFrame);
    }

可能,位图 bmFrame 未正确管理。

4

4 回答 4

6

简短的回答是更好的内存管理。

您正在加载的精灵表很大,然后您将其复制成一堆小位图。假设精灵表不能更小,我建议采用以下两种方法之一:

  1. 使用单独的位图。这将减少内存副本以及 Dalvik 必须增长堆的次数。但是,这些好处可能会受限于需要从文件系统中加载许多图像,而不仅仅是一个。在普通计算机中会出现这种情况,但 Android 系统可能会得到不同的结果,因为它们会耗尽闪存。
  2. 直接从您的精灵表中进行 Blit。绘制时,只需使用类似Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint). 这会将您的文件负载减少到一个可能只需要在您的活动生命周期中发生一次的大型分配。

我认为第二个选项可能是两者中更好的一个,因为它在内存系统上会更容易并且对 GC 的工作更少。

于 2011-09-07T22:23:42.130 回答
3

感谢 stevehb 的建议,我终于明白了:

for (int i = 0; i < TotalFramesTeapotBG; i++) {
    xStartTeapotBG = (i % framesInRowsTeapotBG) * frameWidthTeapotBG; 
    yStartTeapotBG = (i / framesInRowsTeapotBG) * frameHeightTeapotBG;
    Bitmap bmFrame = Bitmap.createBitmap(frameWidthTeapotBG, frameHeightTeapotBG, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bmFrame);  
    Rect src = new Rect(xStartTeapotBG, yStartTeapotBG, xStartTeapotBG+frameWidthTeapotBG, yStartTeapotBG+frameHeightTeapotBG); 
    Rect dst = new Rect(0, 0, frameWidthTeapotBG, frameHeightTeapotBG);  
    c.drawBitmap(framesBitmapTeapotBG, src, dst, null);         
    mVectorTeapotBG.add(bmFrame);
}

计算时间下降得令人难以置信!:)

于 2011-09-09T10:20:01.533 回答
1

使用LevelListDrawable。将精灵切割成单独的帧并将它们放在您的可绘制资源目录中。以编程方式或通过基于xml 的级别列表可绘制对象创建您的可绘制对象。然后使用ImageView.setImageLevel()来选择你的框架。

于 2011-09-07T22:16:47.110 回答
1

我使用基于行和列的切片方法。但是,您的精灵表相当大。您必须认为您正在将整张纸放入记忆中。3808x1632x4 是内存中图像的大小。

无论如何,我要做的是拍摄一张图像(假设是 128x128),然后告诉它 Sprite(bitmap, 4, 2) 构造函数中有 4 列和 2 行。然后你可以根据它进行切片和切块。bitmap.getWidth() / 4 等...非常简单的东西。但是,如果您想做一些真正的事情,请使用 OpenGL 并使用纹理。

哦,我也忘了提到有一些 onDraw 需要发生的事情。基本上,您保留一个索引计数器并从位图中切出一个矩形,然后将其从源矩形绘制到画布上的目标矩形。

于 2012-07-18T21:34:32.517 回答