2010-03-13 14 views
7

Me gustaría animar el movimiento en un SurfaceView. Idealmente, me gustaría recibir una notificación una vez que la animación haya terminado.Animación y rotación de una imagen en una vista de superficie

Por ejemplo: Podría tener un automóvil orientado al norte. Si quería animarlo para que mirase hacia el sur por una duración de 500 ms, ¿cómo podría hacerlo?

Estoy usando SurfaceView para que todas las animaciones se manejen manualmente, no creo que pueda usar XML o las clases de Animator de Android.

Además, me gustaría saber la mejor forma de animar algo de forma continua dentro de un SurfaceView (es decir. Un ciclo de paseo)

Respuesta

8

Rotación de imágenes de forma manual puede ser un poco de dolor, pero así es como he hecho eso.

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 

} 

Esto hará girar su carBitmap a cualquier ángulo que se especifique en el tiempo especificado + el momento de sacar el último fotograma. Sin embargo, hay una trampa. Esto rota tu carBitmap sin ajustar adecuadamente su posición en la pantalla. Dependiendo de cómo esté dibujando sus mapas de bits, podría terminar con su carBitmap girando mientras la esquina superior izquierda del mapa de bits permanece en su lugar. A medida que el automóvil gira, el mapa de bits se estirará y se ajustará para adaptarse al nuevo tamaño del automóvil, llenando los espacios a su alrededor con píxeles transparentes. Es difícil describir cómo se vería, así que aquí tiene un ejemplo que gira un cuadrado:

alt text

El área gris representa el tamaño del mapa de bits, y está lleno de píxeles transparentes. Para resolver este problema, debe usar la trigonometría. Es un poco complicado ... si esto termina siendo un problema para ti (no sé cómo estás dibujando tus mapas de bits en el lienzo por lo que podría no serlo), y no puedes resolver la solución, deja que Yo sé y publicaré cómo lo hice.

(No sé si esta es la forma más eficiente de hacerlo, pero funciona bien para mí siempre que el mapa de bits sea menor de 300x300. Tal vez si alguien sabe de una mejor manera, podrían ¡díganos!)

+0

Es probable que encuentre problemas de rendimiento si crea repetidamente su mapa de bits. En cambio, créelo una vez y luego pase su matriz a 'canvas.drawBitmap()'. Además, ese bucle while impedirá que se active nada más hasta que se complete su turno. Pruebe un bucle de juego: http://www.koonsolo.com/news/dewitters-gameloop/ – idbrii

7

¿Desea tener múltiples objetos animados independientes? Si es así, entonces debes usar un bucle de juego. (Un ciclo master while que actualiza incrementalmente todos los objetos del juego.) Here's a good discussion en varias implementaciones de bucle. (Actualmente estoy usando "FPS depende de la velocidad del juego constante" para mi proyecto de juego para Android.)

Así entonces su coche se verá algo como esto (las porciones de código que falta):

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

Usted Necesito cargar tu mapa de bits una vez. Entonces, si tiene varios autos, es posible que desee darles a cada uno el mismo objeto de mapa de bits (almacenar en caché el mapa de bits en su SurfaceView).

no tengo en animaciones a pie todavía, pero la solución más sencilla es tener varios mapas de bits y simplemente dibujar un mapa de bits diferente cada visualización de la hora se llama.

un vistazo a lunarlander.LunarView in the Android docs si no lo ha hecho.


Si desea recibir una notificación cuando la animación se complete, debe hacer una devolución de llamada.

interface CompletedTurnCallback { 
    void turnCompleted(Car turningCar); 
} 

Haga que su clase de lógica de poner en práctica la devolución de llamada y tienen llame a su coche cuando se completa el giro (en update()). Tenga en cuenta que obtendrá una ConcurrentModificationException si está iterando sobre una lista de Autos en update_game() e intenta eliminar un Coche de esa lista en su devolución de llamada. (Puede resolver esto con una cola de comandos.)

Cuestiones relacionadas