2010-03-13 17 views
7

Mi piacerebbe animare il movimento su un SurfaceView. Idealmente mi piacerebbe essere avvisato anche una volta che l'animazione è terminata.Animazione e rotazione di un'immagine in una vista di superficie

Ad esempio: Potrei avere una macchina rivolta a Nord. Se volessi animarlo in modo che fosse rivolto a Sud per una durata di 500 ms, come potrei farlo?

Sto usando un SurfaceView in modo che tutte le animazioni debbano essere gestite manualmente, non credo di poter usare XML o le classi di animatori Android.

Inoltre, mi piacerebbe conoscere il modo migliore per animare qualcosa continuamente all'interno di un SurfaceView (es. Un ciclo di camminata)

risposta

8

Rotazione delle immagini manualmente può essere un po 'di dolore, ma ecco come ho fatto esso.

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 

} 

Questo ruoterà il vostro carBitmap a che cosa angolo specificato nel tempo specificato + il tempo per disegnare l'ultimo fotogramma. Tuttavia, c'è un problema. Ruota carBitmap senza regolare correttamente la sua posizione sullo schermo. A seconda di come stai disegnando i tuoi bitmap, potresti ritrovare la rotazione di carBitmap mentre l'angolo in alto a sinistra della bitmap rimane al suo posto. Mentre l'auto gira, la bitmap si allungherà e si adatterà per adattarsi alla nuova dimensione dell'auto, riempiendo gli spazi attorno ad essa con pixel trasparenti. È difficile descrivere come questo sarebbe guardare, ecco un esempio ruotare un quadrato:

alt text

L'area grigia rappresenta la piena del bitmap, ed è riempito con i pixel trasparenti. Per risolvere questo problema, è necessario utilizzare la trigonometria. È un po 'complicato ... se questo finisce per essere un problema per te (non so come stai disegnando i tuoi bitmap sulla tela così potrebbe non esserlo), e non riesci a trovare la soluzione, lascia lo so e posterò come l'ho fatto.

(Non so se questo è il modo più efficiente per farlo, ma funziona senza problemi finché la bitmap è inferiore a 300x300 o giù di lì. Forse se qualcuno sa meglio, potrebbero dirci!)

+0

È probabile che si verifichino problemi di prestazioni se si crea ripetutamente la bitmap. Invece, creala una volta e poi passa la tua matrice in 'canvas.drawBitmap()'. Inoltre, il ciclo while impedirà ad altro di animare fino al completamento del turno. Prova un loop di gioco: http://www.koonsolo.com/news/dewitters-gameloop/ – idbrii

7

Vuoi più oggetti animati indipendenti? Se è così, allora dovresti usare un ciclo di gioco. (Un ciclo while master che aggiorna in modo incrementale tutti gli oggetti di gioco.) Here's a good discussion su varie implementazioni di loop. (Attualmente sto usando "FPS dipendente da velocità costante gioco" per il mio progetto di gioco Android.)

Allora la vostra auto sarà simile a questa (un sacco di codice mancante):

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

solo Tu è necessario caricare la bitmap una volta. Quindi, se si dispone di più auto, è possibile assegnare a ciascuna di esse lo stesso oggetto Bitmap (memorizzare la bitmap in SurfaceView).

Non ho ancora avuto a che fare con animazioni a piedi, ma la soluzione più semplice è avere più Bitmap e disegnare una bitmap diversa ogni volta che viene richiamato il display.

Dai un'occhiata allo lunarlander.LunarView in the Android docs se non l'hai già fatto.


Se si desidera ricevere una notifica al termine dell'animazione, è necessario effettuare una richiamata.

interface CompletedTurnCallback { 
    void turnCompleted(Car turningCar); 
} 

Avere la classe logica implementare il callback e avere la vostra auto chiamano quando completo del turno (in update()). Tieni presente che otterrai una ConcurrentModificationException se stai eseguendo un iterazione su un elenco di Automobili in update_game() e provi a rimuovere un'automobile da quell'elenco nella richiamata. (È possibile risolverlo con una coda comandi.)

Problemi correlati