2010-03-13 2 views
7

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

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

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

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

ответ

8

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

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

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

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

+0

Возможно, вы столкнетесь с проблемами производительности, если вы неоднократно создаете растровое изображение. Вместо этого создайте его один раз, а затем передайте свою матрицу в 'canvas.drawBitmap()'. Кроме того, этот цикл while предотвратит анимацию анимации до завершения вашего хода. Попробуйте игровой цикл: http://www.koonsolo.com/news/dewitters-gameloop/ – idbrii

7

Вы хотите несколько независимых анимированных объектов? Если да, то вы должны использовать игровой цикл. (Один ведущий цикл, который постепенно обновляет все игровые объекты.) Here's a good discussion по различным реализациям цикла. (Я в настоящее время с помощью «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); 
    } 
} 

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

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

Посмотрите на lunarlander.LunarView in the Android docs, если вы еще этого не сделали.

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

interface CompletedTurnCallback { 
    void turnCompleted(Car turningCar); 
} 

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

Смежные вопросы