绘制基于图块的地图

时间:2012-01-03 16:17:19

标签: java android bitmap drawable

此脚本绘制控件,英雄,曲面和地图:

public void render(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);

        Drawable myImage;

        int tileWidth = 50;
        int tileHeight = 50;

        int rowBaseX = 0;
        int rowBaseY = 0;

        int[][] board = new int[][] {
                {0,0,0,0,0,0,2,0,0,0,},
                {0,0,0,0,0,2,2,0,0,0,},
                {0,0,0,0,0,2,0,0,0,0,},
                {0,0,0,0,0,2,0,0,0,0,},
                {0,0,0,2,2,2,0,0,0,0,},
                {0,0,0,2,0,0,0,0,0,0,},
                {0,0,0,2,0,0,0,0,0,0,},
                {0,0,2,2,0,0,0,0,0,0,},
                {0,0,2,0,0,0,0,0,0,0,},
                {0,0,2,0,0,0,0,0,0,0,}
                };
        int mapWidth = 10;
        int mapHeight = 10;

        for (int row = 0; row < mapHeight; row++)
        {

        for (int col = 0; col < mapWidth; col++)
        {
        Resources res = this.getContext().getResources();

        switch(board[row][col])
        {
        case 0:
        myImage = res.getDrawable(R.drawable.tile1);
        break;
        case 1:
        myImage = res.getDrawable(R.drawable.tile2);
        break;
        default:
        myImage = res.getDrawable(R.drawable.tile3);
        break;
        }

        int curL = rowBaseX + (col * tileWidth);
        int curU = rowBaseY + (row * tileHeight);
        int curR = curL + tileWidth;
        int curD = curU + tileHeight;

        myImage.setBounds(curL,curU,curR,curD);
        myImage.draw(canvas);
        }
        }

        droid.draw(canvas);
        butt.draw(canvas);
        butt1.draw(canvas);
        butt2.draw(canvas);
        butt3.draw(canvas);
        buttz.draw(canvas);
        buttz1.draw(canvas);
        buttz2.draw(canvas);
        buttz3.draw(canvas);
        buttx.draw(canvas);
    }

有一个英雄,当玩家用控件移动他时必须重新绘制,所有其他drawable也必须重新绘制。问题是绘制地图是一个漫长的过程,因此我创建的地图越大,英雄移动速度越慢,因为地图的每个地块都必须绘制。有没有办法在其他方法中将所有切片放到一个位图中,并在canvas方法中绘制一个位图?

2 个答案:

答案 0 :(得分:3)

如果无法在应用程序外创建静态地图,则可以将静态内容的绘制与动态内容分开。

创建Bitmap,用它创建Canvas并在Canvas上绘制地图。你只需要这样做一次。在另一个Canvas上每帧渲染一次动态内容。 然后在Bitmap的“真实”Canvas上绘制SurfaceView个。它看起来像这样:

每个地图一次的部分:

Bitmap mapBitmap = Bitmap.createBitmap(width, height, myConfig);
Canvas c = new Canvas(mapBitmap);
//draw map on c

......和每帧一次的部分:

//draw dynamic stuff    
Canvas canvas = getHolder().lockCanvas();
    canvas.drawBitmap(mapBitmap, null, targetRect, null);
    canvas.drawBitmap(heroBitmap, null, targetRect, null);
    getHolder().unlockCanvasAndPost();

修改

您可以像以前一样使用myImage.draw(canvas)绘制切片,但是将mapBitmap - Canvas作为参数而不是“真实”画布。 myConfig必须是Bitmap.Config。取RGB_565,因为它是内部格式。

答案 1 :(得分:2)

最佳选择是仅绘制地图上可在屏幕上看到的部分。这样,无论整个地图变得多大,该地图的绘制总是不变的。由于你在网格系统上,你可以很容易地找出英雄所在的单元格:

heroGridX = hero.x % mapWidth;
heroGridY = hero.y % mapHeight;

从那里你可以使用画布的宽度和高度以及网格单元的宽度和高度的恒定大小来计算你想要绘制的玩家周围的单元格数:

leftGrid = heroGridX - (canvas.getWidth() / tileWidth) / 2;
topGrid = heroGridY - (canvas.getHeight() / tileHeight) / 2;
rightGrid = heroGridX + (canvas.getWidth() / tileWidth) / 2;
bottomGrid = heroGridY + (canvas.getHeight() / tileHeight) / 2;

您可以使用数据结构来存储这些独立于英雄的值,并且只有在玩家靠近边缘时才移动它们以滚动地图。这样,英雄在不滚动地图的情况下上下移动,直到他们将X或Y像素到达图块的边缘。而不是在渲染例程中计算这些。

这将使用比将整个地图绘制成一个大位图少得多的内存。绘制到一个大位图可以节省更多的内存使用时间,减少CPU时间。随着地图变大,绘制该地图所需的内存也随之增大。此算法仅保持绘制地图不变,因为屏幕大小在运行时不会更改。并且,与其他选项相比,随着地图变大,内存使用量不会增大(与在画布中绘制更多切片相比,它的增长非常小)。关于这一点的一个重要事实是,如果你确实获得了更大的屏幕(比如平板电脑和手机)。此算法也会正确放大,以便玩家可以看到更多地图的周围地形。