25

I'm trying to learn how to make an animated sprite in android and couldn't figure out how to go about organising my bitmaps. I have a sprite sheet of my character walking to the Right: a bitmap of five copies of a character, equally spaced (every 45px), in a walk cycle.

I planned to draw each frame by drawing a tiny section of my sprite sheet bitmap at a time by going:

Rect sourceRect = new Rect(0, 0, 45, 75);
canvas.drawBitmap(spriteSheetBitmap, sourceRect, new Rect(0, 0, 45, 75), null);

Then for the next frames, increment "sourceRect.x" by 45, then redraw and so forth.

However, I'm now not sure how to go about making my sprite walk to the Left. I had initially thought I could just mirror my rectangle that I am drawing from to get a flipped picture. Something like:

sourceRect = new Rect(45, 0, 0, 75);

which doesn't seem to work (not sure what actually happens here, but nothing gets drawn to my surface).

Searching online, it seems I should make a copy of my original bitmap, mirror it with a transform matrix, then use that bitmap for drawing when walking to the left. However I've also found implementations where many smaller bitmap objects get created out of the original sprite sheet, stored (and transformed for the mirrored motion), then used as needed.

So I'm wondering what would be the best in this case or if there is really any difference (performance/memory):

Method 1: Load in my original sprite sheet, make a new bitmap instance, mirror it,, then calculate all the rectangles and use those + two entire sheets to draw from (admittedly there is some extra bitmap space where the sprite sheet is unused).

Method 2: Load in my original sprite sheet, for every frame create a new two bitmap objects (1 mirrored, 1 normal) and store those to draw from.

Method 3: Other better ways?

mitim
  • 3,169
  • 5
  • 21
  • 25

3 Answers3

77

Method 2 would be way too expensive, and you don't need a canvas to flip a bitmap. Simply create another bitmap with a Matrix applied, like so:

BitmapDrawable flip(BitmapDrawable d)
{
    Matrix m = new Matrix();
    m.preScale(-1, 1);
    Bitmap src = d.getBitmap();
    Bitmap dst = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), m, false);
    dst.setDensity(DisplayMetrics.DENSITY_DEFAULT);
    return new BitmapDrawable(dst);
}
user999717
  • 1,424
  • 11
  • 8
  • From what you say then, it seems better to go with method 1? Better then to keep 2 instances of 'large' main bitmap, then to have many bitmap instances: two bitmap instances at 225px by 75px compared to ten bitmap instances at 45px by 75px – mitim Oct 28 '11 at 22:07
  • Have many small bitmap instances, so there's less data to be read at each frame. – user999717 Oct 29 '11 at 04:37
  • 3
    I fixed the mirror effect with `matrix.preScale(1, -1)`. For some reason `matrix.preScale(-1, 1)` mirrored the image vertically. – Cat Nov 29 '14 at 01:44
17

To mirror your sprite simply apply the following transform on the Canvas: scale(-1, 1). You will have to offset the sprite by its width too.

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • I did think about that too and for this specific case it could work, since there is only one sprite. But if I had multiple sprites pre-drawn on the canvas and sprites to be drawn after, I imagine everything would get flipped? – mitim Oct 28 '11 at 05:50
  • Just use save()/restore() to apply/un-apply the mirroring effect. – Romain Guy Oct 28 '11 at 06:28
  • +1 for pointing out that the bitmap needs an offset (its width) then! – caw Apr 28 '12 at 18:17
  • I'm confused why you need the width offset. – Ifrit Nov 03 '13 at 15:40
  • 1
    @JaySoyer because when you scale by -1 while the pivot is at 0, your right most pixel's x coordinate will be multiplied by -1 so it will be negative (it will be -width). That is why you need to move all your pixels back to the 0 origin. And that is done by adding the width to the coordinates. – Radu Simionescu Oct 03 '14 at 09:23
  • 1
    this is definitely the way to go. learn to use matrixes for transformations - they are used on every platform I know of, they are the way the gpu computes stuff. You don't want to create a bitmap for every transformed sprite. The general flow is this, you draw using the normal (usually the identity) matrix and then when you want to rotate/flip/scale etc a sprite, you apply a new matrix, draw the sprite, and return to your previous matrix. Just to be clear: your previous drawn elements will not be affected by this. – Radu Simionescu Oct 03 '14 at 09:40
4

To draw a vertical mirrored bitmap bmp on a canvas:

Matrix m = new Matrix();
// Mirror is basically a rotation
m.setScale( -1 , 1 );
// so you got to move your bitmap back to it's place. otherwise you will not see it
m.postTranslate(canvas.getWidth(), 0);
canvas.drawBitmap(bmp, m, p);
PiTheNumber
  • 22,828
  • 17
  • 107
  • 180