Анимируйте Drawable в пользовательском представлении - PullRequest
1 голос
/ 08 октября 2011

Я пытаюсь анимировать ShapeDrawable в пользовательском представлении. Но я не уверен, что лучший способ решить эту задачу.

Должен ли я попытаться нарисовать пешку на пути и вызывать invalidate(), пока она не достигнет квадрата назначения? Или есть какой-то лучший способ, используя AsyncTask или Handler?

Вот мой код, я опустил много методов и переменных, чтобы сделать его читаемым.

public class CheckerBoard extends View {

    public enum State implements Parcelable {
        EMPTY(0), WHITE(1), BLACK(2);
    }

        private final State[][] boardStates = new State[SIZE][SIZE];

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(bgColor);
        for (int y = 0; y < SIZE; y++) {
            for (int x = 0; x < SIZE; x++) {
                if ((y % 2 == 0 && x % 2 != 0) || (y % 2 != 0 && x % 2 == 0)) {
                    drawRect(x, y, canvas);
                    drawPawn(x, y, canvas);
                }
            }
        }
    }

    private void drawRect(int x, int y, Canvas c) {
    }

    private void drawPawn(int x, int y, Canvas c) {
    }

    private void init() {
        setupBoard();
        pawnLinePaint.setStyle(Paint.Style.STROKE);
        wPawnDrawable.getPaint().setColor(wColor);
        wPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
        bPawnDrawable.getPaint().setColor(bColor);
        bPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
        playerState = startState;
    }

    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int x = (int) (event.getX() / tileSize);
                int y = (int) (event.getY() / tileSize);
                if (selection[0] >= 0) { // A tile is already selected
                    if (isValidMove(selection[0], selection[1], x, y)) {
                        makeMove(x, y);
                        clearSelection();
                        switchPlayer();
                        invalidate();
                    }

                } else { // New selection
                    if (isValidSelection(x, y)) {
                        selection[0] = x;
                        selection[1] = y;
                        invalidate();
                    }
                }

                return true;
            default:
                return super.onTouchEvent(event);
        }
    }

    private void makeMove(int x, int y) {
        // Move the pawn to the new square
        boardStates[y][x] = boardStates[selection[1]][selection[0]];
        // Old square is now empty
        boardStates[selection[1]][selection[0]] = State.EMPTY;  
    }

    private void switchPlayer() {
        playerState = playerState == State.WHITE ? State.BLACK : State.WHITE;
    }

    public CheckerBoard(Context context) {
        super(context);
        init();
    }

    public CheckerBoard(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CheckerBoard(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }


    private class Pawn extends ShapeDrawable {
        public Pawn() {
            super(new OvalShape());
        }

        public void drawWithCircles(Canvas canvas, float x, float y){
            super.draw(canvas);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding,
                    pawnLinePaint);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 6,
                    pawnLinePaint);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 8,
                    pawnLinePaint);
        }
    }

}

Спасибо за вашу помощь.

порча

1 Ответ

1 голос
/ 08 октября 2011

Вы должны создать две темы для своего приложения. Один поток - это поток пользовательского интерфейса, который рисует плату только в ее текущем состоянии. Другой поток - игровой движок или поток анимации, который перемещает предметы на доске.

Первый поток работает с любой желаемой частотой кадров, а второй поток должен работать значительно быстрее. Таким образом, вам на самом деле не нужно обрабатывать анимацию самостоятельно, поскольку поток пользовательского интерфейса просто рисует доску в том виде, в каком она есть в данный момент. В вашей ветке движка вы обновляете состояние игры, доски, шахматных фигур, каждого цикла ветки.

Выполнение таких действий имеет несколько преимуществ. Во-первых, частота кадров в вашей игре не упадет, если поток Engine застрянет в каком-то вычислении. Во-вторых, это позволяет абстрагировать рисунок от игры таким образом, чтобы сделать отладку намного проще.

Возьмите индикатор выполнения, например. Допустим, вы пытались создать загрузчик файлов с индикатором выполнения, но имели только один поток. Итак, вы запускаете индикатор выполнения, а затем начинаете загрузку файла. Если процесс загрузки блокируется, вам нужно подождать, пока файл завершит загрузку, прежде чем вы сможете обновить индикатор выполнения, по существу делая индикатор выполнения бесполезным. Но если вы сделали это с двумя потоками, то вы можете настроить его так, чтобы один поток просто обновлял графику индикаторов выполнения на основе некоторой общей переменной. Другой шаг отвечает за выполнение действия и обновление переменной прогресса.

Проверьте эти ссылки для получения дополнительной информации:

http://obviam.net/index.php/the-android-game-loop/

http://www.rbgrn.net/content/54-getting-started-android-game-development

http://www.helloandroid.com/tutorials/using-threads-and-progressdialog

...