3

六角形グリッド ベースのゲームの実装に問題があります。ゲームには 91 セルの 16 進数のボードが必要なので、下の単純なボードのように、ユーザーがズーム/ピンチでボードを拡大縮小し、パンで移動できるようにしたいと考えました。ただし、スケーリングと移動の実装では、次のことを同時に行うことはできません。

1) 一貫した境界。各セルを構成する Drawables にピースをドラッグ アンド ドロップできます。

2) セルが下の同じ構成で互いに隣り合ったままになることを可能にする、一貫した相対的な配置。

3) スムーズなスケーリングとパンにより、ゲームをすばやく実行し、他のアプリと同様のズーム/ピンチ エクスペリエンスを実現できます。

91セルの六角ボード

私が試したいくつかのこと(LunarLanderの例のように、Activity -> SurfaceView -> Threadを使用してすべて行われています):

  1. ビットマップへの描画、マトリックスを使用したビットマップのスケーリング、キャンバスの変換。ポイント 2 と 3 を処理しますが、セルの境界を一定に保つ方法がわかりません。HexCell は、1 つのセルの Drawable を保持するクラスであり、2 次元配列のボードには HexCell が含まれています。

    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. マトリックスを使用して 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 が不足しています。さらに、マトリックス pos​​tScale を pivotPoints と一緒に使用していないため、セルは現在の場所の中央に留まり、移動せずに小さく/大きくなります。他の。

    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);
    }
    

私は何をすべきか?最終的にピースをボードに配置できるように、スケーリングおよび移動中に境界を更新するにはどうすればよいですか? スケーリングとパンに対する欲求を捨て、代わりに GridView などを使用してボードを実装する必要がありますか?


編集:

これにもう少し取り組んで、オプション 1 が最善の方法であると判断しました。それははるかに高速で、細胞を一貫した形成に保ちます。キャンバスに適用された変換を反転し、それをタッチ イベントの座標に適用すると、セルの元の境界に戻ることができるため、セルを適切に選択できることがわかりました。

ただし、変換を正確に反転するのに問題があります。

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

は、次の作業反転ではありません:

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

適切に反転する方法を知っている人はいますか?

4

1 に答える 1

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();

ビューの 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() メソッドの使用を避けるための提案があれば、それは素晴らしいことです:)

于 2013-07-25T01:57:35.417 に答える