0
\$\begingroup\$

Firstly, I'm not asking anyone to read my code. It is only posted as a reference just in case you want to. I am asking for general tips on how to get my game running at higher FPS on android, for people who have had the same problem before.

I've been looking all over the web to a specific fix to my problem, but it seems its too generic of a problem to fix, so I thought i'd ask here and see if anyone has experience with this sort of problem. I'm developing a game on android using the native libraries only. my rendering cycle is taking 1/5th of a second to complete, which is ludicrous and drops my frame rate to 5. My game uses very simple PNG graphics i made in GIMP, and i only have a total of 10 images. It doesn't make sense for the game to be running this slow.

Things that I've tried from the web:

-Load each image once and then retrieve them from a cache - done.

-Diagnose using DDMS/MAT to fix memory leaks - there were none.

-Get a sampled size of the image instead of full image - no effect

-Draw onto a off-screen, mutable bitmap, then draw that bitmap onto your main canvas - no effect

-reduce the capped frames/second in my main game loop to around "20" - no effect

The only thing I haven't done is use completely non-scaled images, which i don't see as being practical since every android device has different resolutions and screen sizes.

Does anyone have any other things I should try? If i can't figure this out I'm at a complete loss, because this is crippling the game and making it unplayable. If anyone has steps I can take, please help. In case you'd like to view my code, I've posted the relevant code below and my basic loop (a copy of which can be found online under "basic android loops" search term):

My Input/Output Handler Class:

public abstract class FileIO{....

public static synchronized Bitmap getImage(String imageName, Context context){

    for (int i = 0; i < bitmapList.size(); i++){
        if (fileNameList.get(i).equals(imageName)){
            return bitmapList.get(i);
        }
    }
    Bitmap bitmapReturn = null;
    try {
        assetManager = context.getAssets();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        inputStream = assetManager.open(imageName);
        bitmapReturn = BitmapFactory.decodeStream(inputStream, null, options);

.......
    }
    fileNameList.add(imageName);
    bitmapList.add(bitmapReturn);
    return bitmapList.get(bitmapList.size()-1);
}

}

My "Drawable Sprite" Base Class:

public class Physical {

public void draw(){ 
        ImageBuffer.bufferCanvas.drawBitmap(FileIO.getImage(imageName, GameLoop.context), null, getRect(), null);
        }
}

My Main Loop:

public class Loop extends Activity{

static Canvas canvas;
public final static int MAX_FPS = 45;
public final static int MAX_FRAME_SKIPS = 5;
public final static int FRAME_PERIOD = 1000 / MAX_FPS;
public final static int GAME_STATE_TITLE_SCREEN = 1;
public static Context context;
public RenderView renderView;

 @Override
    protected void onCreate(Bundle savedInstanceState) {

        context = this;
        super.onCreate(savedInstanceState);
        renderView = new RenderView(this);
        setContentView(renderView);
    }

    public void renderAll(){

        //In this method, I have a call to all my "Physical" objects to draw() themselves.
    }

    public class RenderView extends SurfaceView implements Runnable {

        public Thread renderThread = null;
        public SurfaceHolder holder;
        public volatile boolean running = false;

        public RenderView(Context context) {
            super(context);
            holder = getHolder();
        }

        public void onSizeChanged (int w, int h, int oldw, int oldh){

            if (ImageBuffer.bufferCanvas == null) new ImageBuffer();
        }

        public void resume() {
            running = true;
            renderThread = new Thread(this);
            renderThread.start();
        }


        public void run() {

            long beginTime;
            long timeDiff;
            int sleepTime;
            int framesSkipped = 0;

            sleepTime = 0;

            while (running){

                canvas = holder.lockCanvas();
                canvas.drawRGB(0, 0, 0);

                beginTime = System.nanoTime();
                framesSkipped = 0;

                updateAll();
                renderAll();   

                timeDiff = System.nanoTime() - beginTime;
                sleepTime = (int)(FRAME_PERIOD - (timeDiff/1000));

                if (sleepTime > 0) {
                    try {
                    Thread.sleep(sleepTime);
                }

                while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
                    updateAll();
                    sleepTime += FRAME_PERIOD; 
                    framesSkipped++;
                }

                ImageBuffer.flipBuffer();
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

This code is post-image buffer implementation (which did nothing). I was drawing directly to the main canvas before. In the "renderAll()" method inside the main loop, I just have a call to all of my "Physical" objects to ".draw()" themselves.

Does anyone know what is wrong with my game??

\$\endgroup\$

closed as too broad by MichaelHouse Apr 29 '14 at 13:23

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ What are the values of timeDiff and sleepTime? In your RenderView run method? Maybe your thread is sleeping too long because of a wrong nanotime calculation or value casting? Maybe you need to divide timeDiff by 1000000 (milisec) instead of 1000 (microsec) \$\endgroup\$ – Ello Apr 28 '14 at 13:49
  • \$\begingroup\$ Please narrow the scope of the question. Including all your code shouldn't be required. Profile the code to find what's making it run slow, then if you can't find out how to fix that one slow part, post only that section of code along with your analysis of the situation. \$\endgroup\$ – MichaelHouse Apr 28 '14 at 14:07
  • \$\begingroup\$ you should move getImage() to some other place. draw() function is no good for file access. \$\endgroup\$ – tp1 Apr 28 '14 at 14:51
  • \$\begingroup\$ My game has about 30 classes. this is only 3 classes which are connected and I believe are the root of my problem. As i said in my post, the "renderAll()" method is what is causing the delay. I slimmed down the code to make it more precise. \$\endgroup\$ – Beginner001 Apr 29 '14 at 7:46
  • \$\begingroup\$ Ignoring the code, asking for general tips on how to make your game faster is too broad. And while you might say we should ignore the code, the implementation is almost certainly the problem with your game. That's in the code. As I said in my last comment, use a profiler, find out exactly what the problem is, then you can ask about solving that problem, instead of having people guess at what the problem might be. \$\endgroup\$ – MichaelHouse Apr 29 '14 at 13:25
2
\$\begingroup\$

You seem to be loading the images in memory from the storage every frame when you draw them. This is very slow and is most likely the main reason for the slowdown you are experiencing. You need to reuse the previously loaded image to get the proper draw speed you are looking for. Never load the images on every frame again and again, that will just kill the framerate.

You currently have the following code:

public class Physical {
    public void draw(){ 
        ImageBuffer.bufferCanvas.drawBitmap(FileIO.getImage(imageName, GameLoop.context), null, getRect(), null);
    }
}

You can improve this by storing the bitmap reference, and checking you have loaded it before drawing. Something like this:

public class Physical {
    Bitmap bitmap = null;
    public void draw(){
        if(bitmap == null) {
            bitmap = FileIO.getImage(imageName, GameLoop.context);
        }
        ImageBuffer.bufferCanvas.drawBitmap(bitmap, null, getRect(), null);
    }
}
\$\endgroup\$
  • \$\begingroup\$ Can you explain a little further? I thought I was only loading the images from assets once. \$\endgroup\$ – Beginner001 Apr 29 '14 at 7:41
  • \$\begingroup\$ @Beginner001 I improved the answer. \$\endgroup\$ – Lasse Apr 29 '14 at 11:29
  • \$\begingroup\$ Well, currently I am doing that inside the FileIO.getImage() method. I am saving the references in an ArrayList that holds the bitmaps, and only Loading from assets if the bitmap is not already in the Array List. \$\endgroup\$ – Beginner001 Apr 29 '14 at 12:01
  • \$\begingroup\$ So it seems. I missed that when there still was all your code visible. Have you verified that it actually is working? Also, I prefer to use dictionary instead of two lists, file name as key and bitmap as value. It is harder to get it wrong. \$\endgroup\$ – Lasse Apr 29 '14 at 12:58
  • \$\begingroup\$ @Beginner001 I would still try his suggestion. You may not be doing file IO every frame, but walking the list and doing string comparisons on file names for every element drawn is not what I would call "High performance". I would reexamine your code anywhere you have searches for things that could be simple references like the above getImage. If the search is really necessary I would see if a different data structure could help like a binary search tree. \$\endgroup\$ – stonemetal Apr 29 '14 at 14:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.