Hexboard上的Android Laggy onDraw()

时间:2012-12-12 18:00:32

标签: android performance lag hexagonal-tiles

我一直在用android开发一款使用六角板的棋盘游戏,但当我移动棋盘时,整个'地图'或几十个实体开始滞后。我相信它是使用for循环的原因,但我不知道如何解决它。我使用螺纹绘图的方法,不知道它是否会影响。 我在移动电路板时可以清楚地看到手机上的滞后。

我的游戏课程:

public class Game extends SurfaceView implements SurfaceHolder.Callback {
// Game Vars

int mapWidth = 150, mapHeight = 150;
public static double hexagonSideLength = 80;
public static double cellWidth = 2 * hexagonSideLength, cellHeight = Math
        .sqrt(3) * hexagonSideLength;
public static double downwardShift = (0.5) * (cellHeight);
public static double rightShift = hexagonSideLength / 2;
public static int boundaryWidth = 0, boundaryHeight = 0;
public static int error = (int) ((hexagonSideLength) * (0.06));
public static int buffer = 2;
public static int draws = 0;

// Touch Handle

// Offset to the upper left corner of the map
private int xOffset = 0;
private int yOffset = 0;

// last touch point
private int _xTouch = 0;
private int _yTouch = 0;

// scrolling active?
private boolean _isMoving = false;

public Cell[][] map;
private GameThread thread;
static String TAG = Game.class.getSimpleName();
Bitmap image[] = new Bitmap[100];
Paint paint;

public Game(Context context) {
    super(context);
    Log.i(TAG, "Loaded Game");
    // adding the callback (this) to the surface holder to intercept events
    getHolder().addCallback(this);
    // make the GamePanel focusable so it can handle events
    thread = new GameThread(getHolder(), this);
    map = new Cell[mapWidth][mapHeight]; // Create new Map
    boolean isShiftedDownwards = false;
    for (int i = 0; i < mapWidth; i++) {
        for (int j = 0; j < mapHeight; j++) {
            map[i][j] = new Cell(j, i, isShiftedDownwards);
        }
        if (isShiftedDownwards == true)
            isShiftedDownwards = false;
        else
            isShiftedDownwards = true;
    }

    if (mapWidth % 2 != 0) {
        boundaryWidth = (int) ((((mapWidth - 1) / 2) * hexagonSideLength)
                + ((mapWidth / 2) * cellWidth) + (2) * hexagonSideLength);
    } else {
        boundaryWidth = (int) (((((mapWidth - 1) / 2) * hexagonSideLength) + ((mapWidth / 2) * cellWidth)) + (1.5) * hexagonSideLength);
    }
    boundaryHeight = (int) (mapHeight * cellHeight + 0.5 * cellHeight);
    setFocusable(true);
    image[0] = Bitmap.createBitmap(BitmapFactory.decodeResource(
            this.getResources(), R.drawable.hexagonrgb));
    image[1] = Bitmap.createScaledBitmap(image[0], (int) cellWidth + error,
            (int) cellHeight + error, false);
    Log.i(TAG, "Got Resources");
    paint = new Paint();
    Log.i(TAG, "Prepared paint");

}

// called every Frame
@Override
protected void onDraw(Canvas canvas) {
    Log.i(TAG, "onDraw Called");
    // BG
    canvas.drawColor(Color.BLACK);

    // Resize

    // Redraw Map
    draws = 0;
    for (int column = updateArea(0); column < updateArea(1); column++) {
        for (int row = updateArea(2); row < updateArea(3); row++) {
            canvas.drawBitmap(image[1], map[column][row].x - xOffset,
                    map[column][row].y - yOffset, paint);
            paint.setColor(Color.WHITE);
            canvas.drawText(row + "," + column, map[column][row].x
                    - xOffset + 80, map[column][row].y - yOffset + 80,
                    paint);
            draws++;
        }
    }

    /** Log */
    paint.setColor(Color.WHITE);
    paint.setTextSize(20);
    canvas.drawText("xOffset: " + xOffset, 0, 30, paint);
    canvas.drawText("yOffset: " + yOffset, 0, 50, paint);
    canvas.drawText("activeTitlesX: " + updateArea(0) + " - "
            + updateArea(1), 0, 70, paint);
    canvas.drawText("activeTitlesY: " + updateArea(2) + " - "
            + updateArea(3), 0, 90, paint);
    canvas.drawText("DimX: " + MainActivity.DimX, 0, 110, paint);
    canvas.drawText("DimY: " + MainActivity.DimY, 0, 130, paint);
    canvas.drawText("Draws: " + draws, 0, 150, paint);

    Log.i(TAG, "Cleared canvas");
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

// called by thread
public static void update() {
    Log.i(TAG, "Updated Game");

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    thread.setRunning(true);
    thread.start();
    Log.i(TAG, "Thread Started");

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = true;
    while (retry) {
        try {
            thread.join();
            retry = false;
        } catch (InterruptedException e) {
            // try again shutting down the thread
        }
    }
    Log.i(TAG, "Thread Destroyed");
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // touch down
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        // start of a new event, reset the flag
        _isMoving = false;
        // store the current touch coordinates for scroll calculation
        _xTouch = (int) event.getX();
        _yTouch = (int) event.getY();
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
        // touch starts moving, set the flag
        _isMoving = true;

        // get the new offset
        xOffset += _xTouch - (int) event.getX();
        yOffset += _yTouch - (int) event.getY();

        // secure, that the offset is never out of view bounds
        if (xOffset < 0) {
            xOffset = 0;
        } else if (xOffset > boundaryWidth - getWidth()) {
            xOffset = boundaryWidth - getWidth();
        }
        if (yOffset < 0) {
            yOffset = 0;
        } else if (yOffset > boundaryHeight - getHeight()) {
            yOffset = boundaryHeight - getHeight();
        }

        // store the last position
        _xTouch = (int) event.getX();
        _yTouch = (int) event.getY();
    } else if (event.getAction() == MotionEvent.ACTION_UP) {
        /*
         * // touch released if (!_isMoving) { // calculate the touched cell
         * int column = (int) Math.ceil((_xOffset + event.getX()) /
         * _cellSize) - 1; int row = (int) Math.ceil((_yOffset +
         * event.getY()) / _cellSize) - 1; Cell cell =
         * _mapCells.get(row).get(column); // show the id of the touched
         * cell Toast.makeText(getContext(), "Cell id #" + cell._id,
         * Toast.LENGTH_SHORT).show(); }
         */
    }
    return true;
}

public int updateArea(int i) {
    switch (i) {
    case 0: // Left
        return Math.max(
                (int) (xOffset / (cellWidth - rightShift)) - buffer, 0);
    case 1: // Right
        return Math
                .min((int) (xOffset / (cellWidth - rightShift) + (int) (MainActivity.DimX / (cellWidth - rightShift)))
                        + buffer, mapWidth);
    case 2: // Up
        return Math.max((int) (yOffset / cellHeight) - buffer, 0);
    case 3: // Down
        return Math.min(((int) (yOffset / cellHeight))
                + (int) (MainActivity.DimY / cellHeight) + buffer,
                mapHeight);
    }
    return 0;
}

/* CELL CLASS */
class Cell {
    int x, y;
    boolean isShiftedDown;

    public Cell(int row, int col, boolean isShifted) {
        if (col % 2 != 0) {
            isShiftedDown = true;
            y = (int) (row * Game.cellHeight + Game.downwardShift);
            x = (int) (col * Game.cellWidth - col * Game.rightShift);
            Log.i("Shift", "Shifted" + Game.downwardShift);
        } else {
            isShiftedDown = false;
            y = (int) (row * Game.cellHeight);
            x = (int) (col * Game.cellWidth - col * Game.rightShift);
            Log.i("Shift", "Not Shifted");
        }
    }
}

}

提前致谢:)

1 个答案:

答案 0 :(得分:1)

基本算法分析显示您正在执行此操作:

map[i][j] = new Cell(j, i, isShiftedDownwards);

22500次。您是否真的需要每次都创建一个新对象,或者只是更改现有对象中的变量?


更新

for (int column = updateArea(0); column < updateArea(1); column++) {
    for (int row = updateArea(2); row < updateArea(3); row++) {
        canvas.drawBitmap(image[1], map[column][row].x - xOffset,
                map[column][row].y - yOffset, paint);
        paint.setColor(Color.WHITE);
        canvas.drawText(row + "," + column, map[column][row].x
                - xOffset + 80, map[column][row].y - yOffset + 80,
                paint);
        draws++;
    }
}

所以这是双重for循环问题。我将假设这需要在运行时运行多次。可以将循环语句中的函数调用简化为循环之前的变量(它们是用每个循环计算的)吗?不应在每次迭代时调用此paint.setColor(Color.WHITE);。如果您需要在第一次绘制后更改为白色,只需在启动时创建第二个绘制对象,然后在进入循环之前更改它。

如果这没有帮助,您需要确定是否可以迭代较小的区域。


更新2 像这样重写你的for循环

int minCol = updateArea(0);
int maxCol = updateArea(1);
int minRow = updateArea(2);
int maxRow = updateArea(3);
for(int column = minCol; column < maxCol; column++)
    for (int row = minRow; column < maxRow; row++)
 ....

这将代表每次迭代中操作的显着减少。