Animation eines Sprites
Animation (von lat. animare, ?zum Leben erwecken?; animus, ?Geist, Seele?) ist im engeren Sinne jede Technik, bei der durch das Erstellen und Anzeigen von Einzelbildern für den Betrachter ein bewegtes Bild geschaffen wird. Die Einzelbilder können gezeichnet, im Computer berechnet, oder sie können fotografische Aufnahmen sein. Bei der Wiedergabe einer solchen Sequenz mit ca. 24 Bildern pro Sekunde entsteht beim Betrachter die Illusion einer annähernd flüssigen Bewegung.
Quelle: Wikipedia
Die Bilder die für die folgenden Tutorials benötigt werden:
[image img_id=”6232″ width=”320″ height=”320″][image img_id=”6228″ width=”320″ height=”320″]
Hierbei sehen wir, dass die Bilder in 4×4 Bilder aufteilbar sind. Das heißt die Breite und die Höhe eines Sprites ist nicht mehr die Breite der Bitmap sondern muss durch die Anzahl der Spalten bzw. der Zeilen geteilt werden.
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
Die Zeilen unterteilen die Richtung und die Spalten die Frames.
[image img_id=”6233″ width=”300″ height=”158″]
Nun müssen wir noch definieren wann welche Zeile Animiert werden soll. Dazu trennen wir den Bereich in vier Richtungen:
- Reihe 0 zwischen 3/4 Pi und 5/4 Pi
- Reihe 1 zwischen -1/4 Pi und 1/4 Pi
- Reihe 2 zwischen 1/4 Pi und 3/4 Pi
- Reihe 3 zwischen 5/4 Pi und 7/4 Pi
Um zu entscheiden welche Zeile in unserer App angezeigt werden soll, brauchen wir ein bisschen Mathematik:
// Richtung = 0 oben, 1 links, 2 unten, 3 rechts,
// sprite sheet = 2 oben, 0 links, 3 unten, 1 rechts
private int[] DIRECTION_TO_SPRITE_SHEET = { 2, 0, 3, 1 };
private int getAnimationRow() {
double directionDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2)+2);
int spriteDir = (int) Math.round(directionDouble) % BMP_ROWS;
return DIRECTION_TO_SPRITE_SHEET[spriteDir];
}
- Anlegen eines Arrays für die vier Richtungen.
- Erstellen der Methode getAnimationRow() in der wir mit Math.atan2(xSpeed,ySpeed) den Radianwinkel erhalten (-Pi bis Pi).
- Teilen dieses Wertes durch Pi/2 um einen double Wert zu erhalten der im Bereich -2 bis 2 liegt.
- Addieren von 2 um diesen Bereich auf 0-4 zu erhöhen und damit die beiden Arrays von den Positionen her übereinstimmen.
- Benutzen des Modulos der Anzahl unserer Reihen um den Bereich auf 0-3 zu verringern, da 0 und 4 in diesem Fall die gleiche Richtung sind.
Jetzt brauchen wir noch die passende Spalte(Frame). Diese erhalten wir indem wir in der bounceOff() Methode den folgenden Code anhängen:
currentFrame = ++currentFrame % BMP_COLUMNS;
Dieser Code besagt, dass der Frame der angezeigt werden soll, der nächste Frame in der Reihe sein soll. Damit nach dem Ereichen des letzten Frames in der Reihe kein Fehler auftritt, soll er wieder zum ersten Frame springen. Dafür verwenden wir den Modulo der Spaltenanzahl.
Nun muss die onDraw Methode noch so geändert werden, dass immer nur ein Frame pro Aufruf angezeigt wird.
Dazu legen wir Zwei Variablen an. sourceX welchem wir den x-Wert in unseren Spritesheet zuordnen, welches wir gerade brauchen. Also die Momentane Frame multipliziert mit der Breite des Spritesheets. Außerdem sourceY, welchem wir den y-Wert im Spritesheet zuordnen.
Mit hilfe dieser beiden Werte erzeugen wir ein Viereck, welches die passenden x- und y-Werte der 16 Bilder in unserem Spritesheet zugwiesen bekommt.
Das Viereck “destine” ist dafür da zu bestimmen welche Position das Bild nun in unserem Screen haben soll.
Dann zeichen wir das Ganze noch auf unseren Canvas und sind mit diesem Tutorial fertig.
int sourceX = currentFrame * width;
int sourceY = getAnimationRow() * height;
Rect source = new Rect(sourceX, sourceY, sourceX + width, sourceY + height);
Rect destine = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, source, destine, null);
Am Ende des Tutorials sollte die Sprite Klasse so aussehen
package com.panjutorials.lazypudding;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Sprite {
static final private int BMP_COLUMNS = 4;
static final private int BMP_ROWS = 4;
private int[] DIRECTION_TO_SPRITE_SHEET = { 2, 0, 3, 1 };
private int x = 0;
private int y = 0;
private int xSpeed;
private int ySpeed;
private int width;
private int height;
private Bitmap bmp;
private GameView theGameView;
private int currentFrame=0;
public Sprite(GameView theGameView, Bitmap bmp) {
this.theGameView = theGameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
Random rnd = new Random();
ySpeed = rnd.nextInt(10) - 4;
xSpeed = rnd.nextInt(10) - 4;
}
private void bounceOff() {
if (x > theGameView.getWidth() - width - xSpeed || x + xSpeed < 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y > theGameView.getHeight() - height - ySpeed || y + ySpeed < 0) {
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
public void onDraw(Canvas canvas) {
bounceOff();
int sourceX = currentFrame * width;
int sourceY = getAnimationRow() * height;
Rect source = new Rect(sourceX, sourceY, sourceX + width, sourceY + height);
Rect destine = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, source, destine, null);
}
private int getAnimationRow() {
double directionDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2)+2);
int spriteDir = (int) Math.round(directionDouble) % BMP_ROWS;
return DIRECTION_TO_SPRITE_SHEET[spriteDir];
}
}