By using a SurfaceView, I'm trying to do a fade effect for my objects that move in the canvas. Then I have a background that on each frame it will be drawn into the canvas with an alpha value (so all that was drawn before will be faded), and then draw the next position of the objects.
The problem I have though, is that when the background is drawn multiple times with an alpha value, the colors get discrete. Some images; the top one there's the first frame that's with continuous colors, and on the bottom one there's the same but many frames later (~50), where the colors get discrete.
I put some of my code. Init part:
// Inited somewhere in the start of the app
Bitmap bmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas bmpCanvas = new Canvas(bmp);
Paint backgroundPaint = new Paint();
Bitmap background = Bitmap.createBitmap(width, height, Config.ARGB_8888);
// Draw the background image into background
bmpCanvas.drawBitmap(background, 0, 0, backgroundPaint);
backgroundPaint.setAlpha(0x10);
Then I have a thread that in his run method it sets the framerate to 30, and calls the doDraw(Canvas c)
method to draw all the stuff in the bmpCanvas
. Then it draws its bitmap (bmp
) into the scene canvas (If i don't do it this way then I get jitter because of SurfaceView's double buffer)
private void doDraw(Canvas c){
c.drawBitmap(background, 0, 0, backgroundPaint);
// Draw all the objects
}
I tried solving it by changing the backgroundPaint
's Xfermode by trying all of the PorterDuffXFermode, but no one seems to work for me.
============== SOLUTION =========================
Inspired by Lorne Laliberte answer what I did was a double buffer in order to make it faster.
Basically I create the background as a Bitmap. Then I set up 2 empty bitmaps with the same width and height as the background and create 2 Canvases for it. I also keep an index telling me what canvas should I draw to (call it iCanvas
).
There's no need for another bitmap to avoid the SurfaceView's double buffer now, since I'll be drawing everything again (so there's no flicker).
Then what I do is in each frame, clear the actual
canvas, and draw the previous
with a Paint
with some alpha (0xE0 for instance), and draw the objects over this canvas.
Then just draw to the SurfaceView
's canvas the background and then the actual
canvas. Finally just switch the index iCanvas
.
I think this is way faster than having to remember all the previous positions of the objects and drawing them again with different alphas. And this works 100%, as in each frame, the objects that were drawn get faded away and we're not redrawing a semitransparent background over the same background.