Анимация и поворот изображения в режиме просмотра поверхности - PullRequest
8 голосов
/ 13 марта 2010

Я хотел бы анимировать движение на SurfaceView. В идеале я хотел бы также получать уведомления после завершения анимации.

Например: У меня может быть машина, обращенная на север. Если бы я хотел оживить его так, чтобы он был направлен на юг в течение 500 мсек, как я мог это сделать?

Я использую SurfaceView, поэтому вся анимация должна обрабатываться вручную, я не думаю, что смогу использовать XML или классы Android Animator.

Кроме того, я хотел бы знать, как лучше всего непрерывно анимировать что-либо внутри SurfaceView (т. Е. Цикл ходьбы)

Ответы [ 2 ]

8 голосов
/ 13 марта 2010

Поворот изображений вручную может быть немного болезненным, но вот как я это сделал.

private void animateRotation(int degrees, float durationOfAnimation){
    long startTime = SystemClock.elapsedRealtime();
    long currentTime;
    float elapsedRatio = 0;
    Bitmap bufferBitmap = carBitmap;

    Matrix matrix = new Matrix();

    while (elapsedRatio < 1){
        matrix.setRotate(elapsedRatio * degrees);
        carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
        //draw your canvas here using whatever method you've defined
        currentTime = SystemClock.elapsedRealtime();
        elapsedRatio = (currentTime - startTime) / durationOfAnimation;
    }

    // As elapsed ratio will never exactly equal 1, you have to manually draw the last frame
    matrix = new Matrix();
    matrix.setRotate(degrees);
    carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
    // draw the canvas again here as before
    // And you can now set whatever other notification or action you wanted to do at the end of your animation

}

Это повернет ваш carBitmap на любой угол, который вы укажете в указанное время + время рисования последнего кадра. Однако здесь есть одна загвоздка. Это вращает ваш carBitmap без правильной настройки его положения на экране. В зависимости от того, как вы рисуете свои растровые изображения, вы можете закончить вращением вашего carBitmap, в то время как верхний левый угол растрового изображения остается на месте. По мере вращения автомобиля растровое изображение будет растягиваться и корректироваться в соответствии с новым размером автомобиля, заполняя промежутки вокруг него прозрачными пикселями. Трудно описать, как это будет выглядеть, вот пример поворота квадрата:

alt text

Серая область представляет полный размер растрового изображения и заполнена прозрачными пикселями. Чтобы решить эту проблему, вам нужно использовать тригонометрию. Это немного сложно ... если это в конечном итоге станет для вас проблемой (я не знаю, как вы рисуете свои растровые изображения на холсте, чтобы этого не было), и вы не можете найти решение, Я знаю, и я опубликую, как я это сделал.

(Я не знаю, является ли это наиболее эффективным способом сделать это, но он работает для меня плавно, пока растровое изображение меньше, чем 300x300 или около того. Возможно, если кто-то знает о лучшем способе, они могли бы сказать, нам!)

7 голосов
/ 03 ноября 2010

Хотите несколько независимых анимированных объектов? Если это так, то вы должны использовать игровой цикл. (Один главный цикл while, который постепенно обновляет все игровые объекты.) Вот хорошее обсуждение различных реализаций цикла. (В настоящее время я использую «FPS в зависимости от постоянной скорости игры» для моего игрового проекта для Android.)

Итак, ваш автомобиль будет выглядеть примерно так (много кода отсутствует):

class Car {
    final Matrix transform = new Matrix();
    final Bitmap image;

    Car(Bitmap sprite) {
        image = sprite;  // Created by BitmapFactory.decodeResource in SurfaceView
    }
    void update() {
        this.transform.preRotate(turnDegrees, width, height);
    }
    void display(Canvas canvas) {
        canvas.drawBitmap(this.image, this.transform, null);
    }
}

Вам нужно только загрузить свое растровое изображение один раз. Поэтому, если у вас есть несколько автомобилей, вы можете назначить им один и тот же растровый объект (кэшируйте растровое изображение в вашем SurfaceView).

Я еще не знаком с анимацией ходьбы, но самое простое решение - иметь несколько растровых изображений и просто рисовать разные растровые изображения при каждом вызове дисплея.

Взгляните на lunarlander.LunarView в документации для Android , если вы еще этого не сделали.


Если вы хотите получать уведомления о завершении анимации, вы должны сделать обратный вызов.

interface CompletedTurnCallback {
    void turnCompleted(Car turningCar);
}

Пусть ваш класс логики реализует обратный вызов, а ваш автомобиль вызовет его, когда завершится поворот (в update()). Обратите внимание, что вы получите ConcurrentModificationException, если вы перебираете список автомобилей в update_game() и пытаетесь удалить автомобиль из этого списка в вашем обратном вызове. (Вы можете решить это с помощью очереди команд.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...