How to draw lots of bitmaps on screen in an Android game without slow performance

一笑奈何 提交于 2019-11-30 05:04:29
RMorrisey

It looks like you are creating a new instance of each bitmap image for every tile rendered. Maybe instead of doing that, you could create one instance for each tile type? ex:

private Bitmap wallTile = BitmapFactory.decodeResource(getResources(), R.drawable.walla);
private Bitmap floorTile = BitmapFactory.decodeResource(getResources(), R.drawable.floore);

Then reuse the same tile instance each time the tile is drawn. If this doesn't work, you should put in some kind of performance measurement to see what part of the code is taking the longest time, and minimize the amount of times that code is run, or try to slim it down.

Disclaimer: I am not an Android programmer

The problem is pretty obvious. You are just leaking a hell lot of memory. Take a look in the LogCat and you'll see what I mean. 1. NEVER allocate strings each frame. They are immutable so every operation with a strings equals memory leaking. Use instead a simple char[] object that you modify. 2. Stop creating bitmap objects over and over again. I suppose that the DecodeBitmap method internally allocates a bitmap object for each call. It's bad to do that every frame.

As a rule of thumb -> leaking memory and it's buddy the GC are very expensive operations that be avoided when drawing.

I've never programmed for Android before, so I'm not 100% sure about what's going on underneath the covers there, but assuming that:

BitmapFactory.decodeResource(getResources(), R.drawable.walla);

this bit of code goes and loads up a bitmap into memory, it would appear that you're reloading each bitmap as you draw it.

What I've done when developing small games in the past, is when you go to load a level, work out all of the resources that you'll need then load them up into memory once, then reuse them.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MapLoader extends SurfaceView implements SurfaceHolder.Callback,
    Runnable {

SurfaceHolder holder;
Thread thread;

Bitmap grass = BitmapFactory.decodeResource(getResources(),
        R.drawable.tilemapdemo);
boolean running = false;

int[][] grassCoords = new int[][] { { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 } };

public MapLoader(Context context, int width, int height) {
    super(context);

    holder = getHolder();
    holder.addCallback(this);
}

public MapLoader(Context context, AttributeSet attrs) {
    super(context, attrs);

    holder = getHolder();
    holder.addCallback(this);
}

public MapLoader(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    holder = getHolder();
    holder.addCallback(this);
}

public void pause() {
    running = false;

    while (running) {
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        break;
    }
    thread = null;
}

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

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {

    running = true;
    thread = new Thread(this);
    thread.start();

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Canvas c = holder.lockCanvas();
    draw(c);
    holder.unlockCanvasAndPost(c);

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}

@Override
public void run() {

    while (running == true) {

        // performs drawing to the canvas
        if (!holder.getSurface().isValid()) {

            continue;
        }

        Canvas c = holder.lockCanvas();

        int x = 0;
        int y = 0;

        for (x = 0; x < grassCoords.length; x += grass.getWidth()) {

            for (y = 0; y < grassCoords.length; y += grass.getHeight()) {

                c.drawBitmap(grass, x, y, null);
            }

        }

        holder.unlockCanvasAndPost(c);

    }

}

}

another thought, from a non programmer, is maybe create a large tile background that scrolls, etc.. and a second top layer where moveable items (players, npc, items) are drawn on top of the background. therefore scrolling should be faster and less overall (re)rendering. I imagine this might be more resource intensive than referencing already rendered tiles (as mentioned in another suggestion above).. but it might not be, you'd have to give it a shot and see. :-)

How about moving the whole view when the user scrolls. When you scroll in windows, you actually move the window in the opposite direction that you perceive. You scroll down, the windows moves up..

I am quite sure you could collect all the elements in a view (grid) and move the whole view.. Render images off screen (faster) and move them up as needed..

There are examples available.. I know you can get all the code for the home screen, and it scrolls left to right. Might be something to look into. I'm quite sure they did that app right.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!