Spritesheet programmatically cutting: best practices

I have a big spritesheet (3808x1632) composed by 42 frames. I would present an animation with these frames and I use a thread to load a bitmap array with all the frames, with a splash screen waiting for its end. I'm not using a SurfaceView (and a draw function of a canvas), I just load frame by frame in an ImageView in my main layout. My approach is similar to Loading a large number of images from a spritesheet The completion actually takes almost 15 seconds, not acceptable.

I use this kind of function:

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 is the big spritesheet. Looking more deeply, I've read in the logcat that the createBitmap function takes a lot of time, maybe because the spritesheet is too big. I found somewhere that I could make a window on the big spritesheet, using the rect function and canvas, creating small bitmaps to be loaded in the array, but it was not really clear. I'm talking about that post: cut the portion of bitmap

My question is: how can I speed the spritesheet cut?

Edit: I'm trying to use this approach but I cannot see the final animation:

    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);
    }

Probably, the Bitmap bmFrame is not correctly managed.


The short answer is better memory management.

The sprite sheet you're loading is huge, and then you're making a copy of it into a bunch of little bitmaps. Supposing the sprite sheet can't be any smaller, I'd suggest taking one of two approaches:

  • Use individual bitmaps. This will reduce the memory copies as well as the number of times Dalvik will have to grow the heap. However, these benefits may be limited by the need to load many images off the filesystem instead of just one. This would be the case in a normal computer, but Android systems may get different results since they're run off flash memory.
  • Blit directly from your sprite sheet. When drawing, just draw straight from sprite sheet using something like Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) . This will reduce your file loads to one large allocation that probably only needs to happen once in the lifetime of your activity.
  • I think the second option is probably the better of the two since it will be easier on the memory system and be less work for the GC.


    Thanks to stevehb for the suggestion, I finally got it:

    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);
    }
    

    The computation time falls incredibly! :)


    Use a LevelListDrawable. Cut the sprites into individual frames and drop them in your drawable resource directory. Either programmatically or through an xml based level-list drawable create your drawable. Then use ImageView.setImageLevel() to pick your frame.

    链接地址: http://www.djcxy.com/p/68954.html

    上一篇: 在画布中心画圈

    下一篇: Spritesheet以编程方式切割:最佳做法