2010-03-13 6 views
7

Je souhaite animer un mouvement sur un SurfaceView. Idéalement, je voudrais aussi être informé une fois l'animation terminée. Par exemple: Je pourrais avoir une voiture face au nord. Si je voulais l'animer pour faire face au Sud pendant 500ms, comment pourrais-je faire ça? J'utilise un SurfaceView donc toute l'animation doit être manipulée manuellement, je ne pense pas que je puisse utiliser le XML ou les classes Android Animator.Animation et rotation d'une image dans une vue de surface

Aussi, je voudrais savoir la meilleure façon d'animer quelque chose en permanence dans un SurfaceView (ie. Un cycle de marche)

Répondre

8

images en rotation peuvent manuellement être un peu d'une douleur, mais voici comment je l'ai fait il.

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 

} 

Cela tournera votre carBitmap à quelque angle que vous spécifiez dans le temps spécifié + le temps de dessiner la dernière image. Cependant, il y a un hic. Ceci fait tourner votre carBitmap sans ajuster correctement sa position sur l'écran. Selon la façon dont vous dessinez vos bitmaps, vous pourriez vous retrouver avec votre carBitmap tournant alors que le coin supérieur gauche de l'image bitmap reste en place. Au fur et à mesure que la voiture tourne, l'image bitmap s'étire et s'ajuste pour s'adapter à la nouvelle taille de la voiture, en remplissant les espaces autour de celle-ci avec des pixels transparents. Il est difficile de décrire comment cela ressemblerait, voici donc un exemple de rotation un carré:

alt text

La zone grise représente la taille totale du bitmap, et est rempli de pixels transparents. Pour résoudre ce problème, vous devez utiliser la trigonométrie. C'est un peu compliqué ... si cela finit par être un problème pour vous (je ne sais pas comment vous dessinez vos bitmaps sur la toile, ce n'est peut-être pas le cas), et vous ne pouvez pas trouver la solution, laissez Je sais et je posterai comment je l'ai fait.

(Je ne sais pas si c'est la façon la plus efficace de le faire, mais cela fonctionne bien pour moi tant que l'image bitmap est inférieure à 300x300 ou si. Peut-être que si quelqu'un sait d'une meilleure façon, ils pourraient Dites-nous!)

+0

Vous risquez de rencontrer des problèmes de performances si vous créez plusieurs fois votre bitmap. Au lieu de cela, créez-le une fois, puis passez votre matrice dans 'canvas.drawBitmap()'. En outre, cette boucle empêchera toute autre chose d'animer jusqu'à ce que votre tour se termine. Essayez une boucle de jeu: http://www.koonsolo.com/news/dewitters-gameloop/ – idbrii

7

Voulez-vous plusieurs objets animés indépendants? Si oui, alors vous devriez utiliser une boucle de jeu. (Une boucle maître qui met à jour de manière incrémentielle tous les objets du jeu.) Here's a good discussion sur diverses implémentations en boucle. (Je suis actuellement en utilisant « FPS dépendant de la vitesse constante du jeu » pour mon projet de jeu Android.)

Alors votre voiture sera quelque chose comme ça (beaucoup de code manquant):

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

Vous ne besoin de charger votre bitmap une fois. Donc, si vous avez plusieurs voitures, vous voudrez peut-être leur donner le même objet Bitmap (cachez le bitmap dans votre SurfaceView).

Je n'ai pas encore d'animations de marche, mais la solution la plus simple est d'avoir plusieurs bitmaps et de dessiner un bitmap différent à chaque fois que l'affichage est appelé.

Jetez un oeil à lunarlander.LunarView in the Android docs si vous ne l'avez pas déjà fait.


Si vous souhaitez être averti lorsque l'animation est terminée, vous devez effectuer un rappel.

interface CompletedTurnCallback { 
    void turnCompleted(Car turningCar); 
} 

Demandez à votre classe logique de mettre en œuvre la fonction de rappel et que votre appel voiture quand complète de la tour (en update()). Notez que vous obtiendrez une exception ConcurrentModificationException si vous parcourez une liste de voitures dans update_game() et que vous essayez de supprimer une voiture de cette liste dans votre rappel. (Vous pouvez résoudre ceci avec une file d'attente de commandes.)

Questions connexes