在Android中绘制大型位图

5
我不知道这个问题是否被解决。至少我没有找到答案。
以下是事情的描述:我正在制作一款太空主题的2D游戏,使用Android模拟器进行测试,屏幕大小为2560x1600。在这个游戏中,有一个场景,太空飞船在其中飞行。当然,这个场景必须有一个高分辨率美丽的背景图。我的背景图分辨率为4500x4500。我希望我的图像相对于相机移动方向相反移动,因此我不能使用小的静态图像。目前只有这个图像的一部分可见:

Example 1

当我尝试绘制它时,我的帧率为1-2(当然由于图像大小而低):
canvas.drawBitmap(getBigImage(), -x, -y, null); 
/* getBigImage() method does nothing but returning 
a Bitmap object (no calculation or decoding is performing in there) */

我试图从大图片中剪裁所需的图像,但fps仍然很低:

Bitmap b = Bitmap.createBitmap(getBigImage(), x, y, sw, sh);
canvas.drawBitmap(b, 0, 0, null);

如何以高帧率绘制这个大位图?
2个回答

3

尝试

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

这个功能会从源图像中取出一组像素,以矩形的形式显示在画布上。我曾经在制作滚动游戏时发现这样做更快。


它只是将源矩形中的图像绘制到画布矩形中。它不会删除源位图中的像素。如果源矩形大于源位图,那么肯定会出现异常。快试一下,看看它是否能提高你的FPS。 - Craig C.
尝试使用与屏幕大小相同的背景图像,2560 x 1600,并查看您获得的帧率。如果仍然很低,那么可能是模拟器性能不佳。 - Craig C.
使用Renderscript可以获得比原来快很多倍的速度。参考http://stackoverflow.com/a/35877894/5148048获取灵感。 - Settembrini
这非常有趣。我唯一的建议是尝试使用OpenGL来处理你的图形,但它更加复杂,我不能保证性能会提高,因为我自己也没有尝试过。 - Craig C.
我思考了很久,想到了一个写一个对象的主意,当解码时将大位图分成小块,然后保存到数组中。因此,当我想要绘制它时,我只需要从该数组中取出可见的块并绘制它们。希望这有所帮助。唯一不确定的是存储所有块所需的内存是否足够。这是一个好方法吗? - GV_FiQst
显示剩余2条评论

3
我思考了很多,想出了一个将输入位图分成小块并将它们保存到数组中的方法。因此,现在只需绘制可见的块即可绘制该位图。
图片:

enter image description here

大黑色矩形表示输入位图,绿色矩形表示视口,红色矩形表示可见的块被绘制。我编写了一个对象来完成所有这些工作(但我还没有检查它是否有错误:/)。我已经测试过它,可以以约45 fps绘制3000x3000位图。我认为这种方式非常有效。这个对象本身可能需要更多的开发,但我认为这个功能对我的需求来说已经足够了。希望能帮助到某些人:)附注:https://dev59.com/xWIj5IYBdhLWcg3w8ZYF#25953122-用于灵感:)
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;

public final class DividedBitmap {
    private final Bitmap[][] mArray;    // array where chunks is stored

    private final int mWidth;           // original (full) width of source image
    private final int mHeight;          // original (full) height of source image
    private final int mChunkWidth;      // default width of a chunk
    private final int mChunkHeight;     // default height of a chunk

    /* Init */

    public DividedBitmap(Bitmap src) {
        this(new Options(src, 100, 100));
    }

    public DividedBitmap(Options options) {
        mArray = divideBitmap(options);

        mWidth = options.source.getWidth();
        mHeight = options.source.getHeight();
        mChunkWidth = options.chunkWidth;
        mChunkHeight = options.chunkHeight;
    }

    /* Getters */

    public int getWidth() {
        return mWidth;
    }

    public int getHeight() {
        return mHeight;
    }

    public Bitmap getChunk(int x, int y) {
        if (mArray.length < x && x > 0 && mArray[x].length < y && y > 0) {
            return mArray[x][y];
        }

        return null;
    }

    /* Methods */

    /**
     *  x, y are viewport coords on the image itself;
     *  w, h are viewport's width and height.
     */
    public void draw(Canvas canvas, int x, int y, int w, int h, Paint paint) {
        if (x >= getWidth() || y >= getHeight() || x + w <= 0 || y + h <= 0)
            return;

        int i1 = x / mChunkWidth;           // i1 and j1 are indices of visible chunk that is
        int j1 = y / mChunkHeight;          // on the top-left corner of the screen
        int i2 = (x + w) / mChunkWidth;     // i2 and j2 are indices of visible chunk that is
        int j2 = (y + h) / mChunkHeight;    // on the right-bottom corner of the screen

        i2 = i2 >= mArray.length ? mArray.length - 1 : i2;
        j2 = j2 >= mArray[i2].length ? mArray[i2].length - 1 : j2;

        int offsetX = x - i1 * mChunkWidth;
        int offsetY = y - j1 * mChunkHeight;

        for (int i = i1; i <= i2; i++) {
            for (int j = j1; j <= j2; j++) {
                canvas.drawBitmap(
                        mArray[i][j],
                        (i - i1) * mChunkWidth - offsetX,
                        (j - j1) * mChunkHeight - offsetY,
                        paint
                );
            }
        }
    }

    /* Static */

    public static Bitmap[][] divideBitmap(Bitmap bitmap) {
        return divideBitmap(new Options(bitmap, 100, 100));
    }

    public static Bitmap[][] divideBitmap(Options options) {
        Bitmap[][] arr = new Bitmap[options.xCount][options.yCount];

        for (int x = 0; x < options.xCount; ++x) {
            for (int y = 0; y < options.yCount; ++y) {
                int w = Math.min(options.chunkWidth, options.source.getWidth() - (x * options.chunkWidth));
                int h = Math.min(options.chunkHeight, options.source.getHeight() - (y * options.chunkHeight));
                arr[x][y] = Bitmap.createBitmap(options.source, x * options.chunkWidth, y * options.chunkHeight, w, h);
            }
        }

        return arr;
    }

    public static final class Options {
        final int chunkWidth;
        final int chunkHeight;
        final int xCount;
        final int yCount;
        final Bitmap source;

        public Options(Bitmap src, int chunkW, int chunkH) {
            chunkWidth = chunkW;
            chunkHeight = chunkH;

            xCount = ((src.getWidth() - 1) / chunkW) + 1;
            yCount = ((src.getHeight() - 1) / chunkH) + 1;

            source = src;
        }

        public Options(int xc, int yc, Bitmap src) {
            xCount = xc;
            yCount = yc;

            chunkWidth = src.getWidth() / xCount;
            chunkHeight = src.getHeight() / yCount;

            source = src;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接