4
\$\begingroup\$

I'm just trying to figure out the best approach for running a scolling background on an android device. The method I have so far.... its pretty laggy. I use threads, which I believe is not the best bet for android platforms

@Override
    public void run() {
        // Game Loop
        while(runningThread){
            //Scroll background down
            bgY += 1;

            try {
                this.postInvalidate();
                t.sleep(10);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

where postinvalidate in the onDraw function simply pushings the background image down

canvas.drawBitmap(backgroundImage, bgX, bgY, null);

Thanks in advance


UPDATE & SOLUTION

Thank you for everyone helping me. I came across this:

post https://stackoverflow.com/questions/1430741/how-to-draw-lots-of-bitmaps-on-screen-in-an-android-game-without-slow-performance

Helped my problem a lot. However, Seemed I was creating bitmaps in the onDraw every time is was caused, meaning that was doing 95% of the slowing down. oops :)

Below is my inner class in my surfaceview for reference purposes

class MapThread extends Thread{
    private Map map;
    private SurfaceHolder holder;
    private boolean run = false;

    public MapThread(Map map, SurfaceHolder holder){
        this.holder = holder;
        this.map = map;
        setRunning(true);
    }

    public void setRunning(boolean run){
        this.run = run;
    }

    @Override
    public void run(){
        while(run){
            try{
                Canvas c = null;

                 try {
                       c = holder.lockCanvas(null);
                       synchronized (holder) {
                            map.onDraw(c);
                     }
                 } finally {

                     if (c != null) {
                         holder.unlockCanvasAndPost(c);
                     }
                 }
        }
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ Maybe this link will help? droidnova.com/… \$\endgroup\$ Commented Feb 4, 2011 at 19:45
  • \$\begingroup\$ See the SurfaceView class (used in JetBoy and LunarLander examples) developer.android.com/reference/android/view/SurfaceView.html \$\endgroup\$
    – f20k
    Commented Feb 7, 2011 at 16:56
  • \$\begingroup\$ I realize this is old, but instead of having the solution in the question, you should copy your solution and put it in an answer and accept it. \$\endgroup\$
    – Nate
    Commented Feb 8, 2013 at 21:36

4 Answers 4

3
\$\begingroup\$

There could be a variety of things causing your background scrolling to be choppy.

  1. Your image could be very large causing canvas.drawBitmap(); to be slow
  2. Your loop could be firing slowly or inconsistently. I could be wrong, and maybe there are extenuating circumstances, but generally a sleep(); call is never good in a game loop, or any loop for that matter. It could quite easily be the a contributor to your choppiness. I'd remove it to see what happens.
  3. Other code you've stripped out from the example could be taking up lots of milliseconds in your loop.

I highly recommend you track the number of milliseconds between each iteration of your loop. You can use this data to determine how far to move your background based on how long the last loop took. This should smooth out your scrolling for the most part.

If the issue is because your image is so large that drawing it is taking up too much time, you may need to break the image up into smaller parts and "stream" it across the screen based on the scrolling position.

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Actually a sleep call is good in every game loop, but as you pointed out it should be a variable time based on how long the rest of the loop took. But especially in a mobile device, a tight CPU loop will only drain the battery that much faster. No need to run at 200 FPS when the screen can only really update at 60 (or 30, or whatever rate it updates) - you'll just get complaints about draining battery life. \$\endgroup\$
    – Ricket
    Commented Feb 4, 2011 at 22:14
  • \$\begingroup\$ I agree with you. I've read (specifically about .NET's implementation, I thought it applied more generally as well) that sleep(); calls only promise to sleep for at least the specified time, maybe longer. Since we're talking about milliseconds in a game loop depending on how much longer it sleeps it could be an issue. \$\endgroup\$
    – Nate
    Commented Feb 4, 2011 at 23:37
  • 1
    \$\begingroup\$ Usually sleeping to 1ms (or less) before you need to wake up and then busy-looping for a short period is safe enough. If sleep doesn't wake you up to within millisecond precision, the system is overloaded and you will be starved for resources anyway. \$\endgroup\$
    – user744
    Commented Feb 5, 2011 at 0:17
3
\$\begingroup\$

You might want to take a look at the Android Examples, specifically JetBoy:

http://developer.android.com/resources/samples/JetBoy/index.html

I believe they have scrolling backgrounds, specifically Parallax Scrolling (which you can look up here: http://en.wikipedia.org/wiki/Parallax_scrolling)

But if you just want one background scroll, you could get a pretty good feel for how to do it from this game example.

(NOTE: I believe this game has scrolling backgrounds, correct me if I am wrong and I will edit this Answer)

EDIT:

You should definitely handle the drawing in a separate thread from the user input. Also depending on what version of Android you are building for, you might want to sleep in the input handling method for a couple milliseconds. You would want to do this because in earlier versions of Android, pressing the screen would result in a flood of inputs which would slow down the processing of an application. This was more acute in games. Check out the Replica Island code for more information on what I'm talking about.

Specifically if you look at: http://code.google.com/p/replicaisland/source/browse/trunk/src/com/replica/replicaisland/AndouKun.java on line: 344

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mGame.isPaused()) {
                mGame.onTouchEvent(event);

                final long time = System.currentTimeMillis();
                if (event.getAction() == MotionEvent.ACTION_MOVE && time - mLastTouchTime < 32) {
                        // Sleep so that the main thread doesn't get flooded with UI events.
                        try {
                            Thread.sleep(32);
                        } catch (InterruptedException e) {
                            // No big deal if this sleep is interrupted.
                        }
                        mGame.getRenderer().waitDrawingComplete();
                }
                mLastTouchTime = time;
        }
        return true;
    }

Chris sleeps the input thread for 32 milliseconds which is approximately 30 sleeps per second (which matches 30 fps for the game). This makes sense because if you are only calling your update method once per frame, you don't need to have the input thread produce any more than 1 input for a touch event.

\$\endgroup\$
4
  • \$\begingroup\$ thanks, that helped. but how can I split the touch actions that results in its own draw. Ontop of the current draw. for example. map is scrolling from top to bottom. where u touch moves your character. at the moment everything is drawing in one section. \$\endgroup\$
    – Stevanicus
    Commented Feb 23, 2011 at 21:50
  • \$\begingroup\$ @Stevanicus I'm not completely sure what you are asking but the basic idea is you want to separate your drawing calls and your update calls. You should take input and process everything in an update method and after the update method has finished processing everything for the frame, you should draw the frame by calling draw. In the draw method is when you draw everything in opposite order you want it to show up on the screen. (You want to draw your background first). Not sure if this answered your question, if it didn't, can you give me a little more specifics? \$\endgroup\$
    – jluzwick
    Commented Feb 24, 2011 at 1:56
  • \$\begingroup\$ Thanks for your comment. How can I separate the drawing from the user input in the surfaceview? And would u say the above thread is best way for handling drawing? \$\endgroup\$
    – Stevanicus
    Commented Feb 24, 2011 at 23:37
  • \$\begingroup\$ @Stevanicus I'm editing my answer for additional information that you are requesting, check it out. \$\endgroup\$
    – jluzwick
    Commented Feb 25, 2011 at 2:21
2
\$\begingroup\$

if you're still looking for a solution to the timing:

Read this article, specifically how the class FPSTimer is used in the draw thread to time the drawing loop. I've used this example to write my own surfaceview-based game. It also provides a good basis for handling key event inputs. For handling touch events, you would want to override the View.OnTouchListener for DOWN, MOVE, and UP events.

\$\endgroup\$
1
\$\begingroup\$

Don't use Sleep in the onTouch! On some devices, this will stall and crash because of the "sticky keys" function.

    if (startH == 0)
    startH = System.currentTimeMillis();

    // Keep speed down.. in time based style! 8-)
    if((System.currentTimeMillis()-startH)>=30 && startH != 0)
    {
        timeToProcess = true;
        startH = 0;
    }

That might be the problem.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .