7

I have written a simple Android application that draws a maze using a custom view derived from SurfaceView. It follows the model of the LunarLander sample application and performs all calculation and drawing using a background thread directly into the SurfaceHolder object.

All well and good and it's running well for small/medium mazes, however if I set the maze cell size to be 8 pixels there are lots of cells in the maze the application crawls along.

The code is doing something I don't like in that is draws every cell even if it hasn't changed and this is required to avoid screen flickering from the SurfaceView double buffer (in previous iterations of the application I was drawing just what changed and that resulted in a jumpy mess).

What I want then is the ability to use SurfaceView but be more selective about what gets drawn. Is this possible? If not, what are the alternatives? How about keeping an offscreen bitmap, and selectively drawing into that first?

EDIT: I implemented an offscreen Bitmap and Canvas combination, written to by my timer-driven state machine, drawing only those areas affected during carving/solution. I then simply draw the whole offscreen bitmap onto the SurfaceView within the run() method and this has solved my problem; I am able to drop the cell size to 5 pixels and performance is fine.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • 1
    While this is old, a SurfaceView that uses the standard Thread-SurfaceHolder can specify a Rect in `lockCanvas`; when this is done only that region needs to be updated. In some situations it can save a good bit of redraw but it requires also managing the dirty region .. –  Jan 10 '13 at 11:50

1 Answers1

5

About double-buffering issues:

Take a look at this tutorial series. Do you see any difference in the way you handle drawing? https://web.archive.org/web/20121109162356/http://www.droidnova.com/playing-with-graphics-in-android-part-iii,176.html

About optimizing your drawing:

The following link, explains some approaches:

http://developer.android.com/guide/topics/graphics/opengl.html

http://developer.android.com/reference/android/opengl/GLSurfaceView.html

Continuous rendering versus render-when-dirty

Most 3D applications, such as games or simulations, are continuously animated. But some 3D applications are more reactive: they wait passively until the user does something, and then react to it. For those types of applications, the default GLSurfaceView behavior of continuously redrawing the screen is a waste of time. If you are developing a reactive application, you can call GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY), which turns off the continuous animation. Then you call GLSurfaceView.requestRender() whenever you want to re-render.

Also, in 2D games it's particulary easy to calculate what is being seen by the user so refrain from drawing objects out of the visible scene.

One final note:

You said

All well and good and it's running well for small/medium mazes, however if I set the maze cell size to be 8 pixels there are lots of cells in the maze the application crawls along.

Does this means that you are computing the maze's solution? If so, you shouldn't do it in the same thread where you draw it. You should solve it in another thread. (I might have understood you wrong)

Community
  • 1
  • 1
Pedro Loureiro
  • 11,436
  • 2
  • 31
  • 37
  • Thanks for the reply. No, the first example you linked to isn't like the way my view currently draws; mine more closely resembles the LunarLander sample. Also the second link and the section about Continuous rendering vs render-when-dirty seem to relate to OpenGL, so I'm not sure how that relates my application. As far as solving the maze is concerned, I'm sure that makes no difference to performance - the solution is stepped by a timer and it's very simple. – trojanfoe Feb 14 '11 at 21:00
  • Although I have got the improved performance I was after using an offscreen bitmap, I have now also implemented your idea of performing UI update and maze carving/solution in separate threads. This wasn't for performance reasons, but merely as it was confusing having both in the same thread and class - one in the `run()` loop and other being timed. – trojanfoe Feb 15 '11 at 18:46
  • 1
    It was related because you are drawing every frame again and again. Maybe you could update the UI when something moves. To have further improvements, in your draw method, avoid drawing objects outside the visible area. – Pedro Loureiro Feb 15 '11 at 19:01