如何调整多个Drawable的大小并以快速,一致的方式更新其边界

时间:2013-07-23 01:47:57

标签: android android-layout user-interface 2d-games

我对基于六边形网格的游戏的实现存在问题。因为游戏需要一个91格的六角形板,就像我下面的简单板一样,我希望用户能够通过缩放/缩放来缩放电路板,并通过平移来移动它。但是,我的缩放和移动实现都没有让我同时拥有:

1)一致的界限,使我能够将碎片拖放到构成每个单元格的Drawables上。

2)一致的相对定位,允许细胞在下面相同的配置中保持彼此相邻。

3)平滑缩放和平移,让游戏快速运行,并具有类似于其他应用程序的缩放/捏合体验。

A 91-cell hex board

我尝试过的一些事情(全部使用活动完成 - > SurfaceView - >线程,就像在LunarLander示例中一样):

  1. 绘制到位图,使用矩阵缩放位图,翻译画布。处理第2点和第3点,但我无法弄清楚如何保持单元格的边界一致。 HexCell是一个包含单个单元格的Drawable的类,而二维数组board包含HexCells。

    public void drawBoard(Canvas c, int posX, int posY, float scaleFactor, float pivotPointX, float pivotPointY, boolean firstDraw) {
        for(int i = 0; i < board.size(); i++) {
            for(int j = 0; j < board.get(i).size(); j++) {
                board.get(i).get(j).draw(bitmapCanvas);
            }
        }
        if(firstDraw) {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            float scale;
            if(canvasWidth < canvasHeight) {
                scale = ((float) canvasWidth) / width;
            }
            else {
                scale = ((float) canvasHeight) / height;
            }
            Matrix matrix = new Matrix();
    
            // Resize the bit map
                matrix.postScale(scale, scale);
    
            // Recreate the new Bitmap
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
            c.drawBitmap(bitmap, matrix, null);
        }
        c.save();
        c.translate(posX, posY);
        Matrix matrix = new Matrix();
        matrix.postScale(scaleFactor, scaleFactor, pivotPointX, pivotPointY);
        c.drawBitmap(bitmap, matrix, null);
        c.restore();
    }
    
  2. 使用Matrix修改Drawable的边界。这会更新第1点的边界,并且通过一些调整我认为我可以获得2和3,但我不确定如何使缩放停止为“粘性”,这意味着不像第一种方法那样平滑。此外,当大量缩放细胞时,它们中的一些会变成不同的大小,并开始相对于其他细胞移出位置。

    public void drawBoard(Canvas c, int posX, int posY, float scaleFactor, float pivotPointX, float pivotPointY, boolean firstDraw) {
        for(int i = 0; i < board.size(); i++) {
            for(int j = 0; j < board.get(i).size(); j++) {
                Rect bounds = board.get(i).get(j).getBounds();
                RectF boundsF = new RectF(bounds.left, bounds.top, bounds.right, bounds.bottom);
                matrix.mapRect(boundsF);
                bounds = new Rect((int)boundsF.left, (int)boundsF.top, (int)boundsF.right, (int)boundsF.bottom);
                board.get(i).get(j).setBounds(bounds);
                board.get(i).get(j).draw(c);
            }
        }
    }
    
  3. 直接修改Drawable的边界。这会更新点1的边界,但缺少第2点和第3点。此外,因为我没有使用带有pivotPoints的矩阵postScale,所以单元格保持居中的位置并变小或变大,而不会移动到每个单元格旁边其他

    public void resize(int dx, int dy, float scaleFactor) {
        xPos += dx;
        yPos += dy;
        width *= scaleFactor;
        height *= scaleFactor;
        cell.setBounds(xPos, yPos, xPos + width, yPos + height);
    }
    
  4. 我该怎么办?如何在缩放和移动时更新边界,以便最终可以在棋盘上放置碎片?我是否应该放弃缩放和平移的愿望,而是使用GridView或类似的东西来实现电路板?


    编辑:

    更多地研究这个问题,我已经确定选项1是最好的方法。它更快,并使细胞保持一致的形态。我发现如果你反转应用于画布的变换并将其应用于触摸事件的坐标,你可以回到单元格的原始边界,因此适当地选择它们。

    但是,我无法准确地反转转换。

    x /= scaleFactor;
    y /= scaleFactor;
    x -= posX + pivotPointX;
    y -= posY + pivotPointY;
    

    不是以下的工作反转:

    canvas.save();
    canvas.translate(posX, posY);
    canvas.scale(scaleFactor, scaleFactor, pivotPointX, pivotPointY);
    

    有谁知道如何恰当地反转它?

1 个答案:

答案 0 :(得分:1)

在drawBoard()方法中,我做了:

canvas.save();
canvas.translate(posX, posY);
canvas.scale(scaleFactor, scaleFactor, pivotPointX, pivotPointY);
canvas.getMatrix(canvasMatrix); // Save the matrix that has the transformations so we can invert it
for(int i = 0; i < board.size(); i++) {
    for(int j = 0; j < board.get(i).size(); j++) {
         board.get(i).get(j).draw(c);
    }
}
canvas.restore();

在View I中的onTouchEvent(MotionEvent ev)方法中:

float x = ev.getX();
float y = ev.getY();

float[] pts = {x, y};
Matrix canvasMatrix = boardThread.getCanvasMatrix(); // get the matrix with the transformations
Matrix invertMatrix = new Matrix();
canvasMatrix.invert(invertMatrix); // invert the matrix
invertMatrix.mapPoints(pts); // map the inversion to the points x and y
boardThread.selectHex((int)pts[0], (int)pts[1]);

这就是诀窍!现在,如果有人有任何建议,以避免使用已弃用的canvas.getMatrix()方法,那将是伟大的:)