Ανάπτυξη ενός παιχνιδιού Android – Μάθημα 8: Sprite Animations

προγραμματισμός-android8 Εάν έχετε παρακολουθήσει τα μαθήματα μέχρι τώρα, θα ξέρετε πώς να διαχειρίζεστε τις πινελιές, να τοποθετείτε τις εικόνες και να τις κάνετε να κινούνται. Ωστόσο, η μετακίνηση των εικόνων είναι μία μάλλον βαρετή παράσταση από ορισμένες απόψεις, λαμβάνοντας υπόψη ότι πολλά αντικείμενα δεν κινούνται τυχαία, αλλά ακριβώς επειδή είναι κινούμενα. Σήμερα, στην πραγματικότητα, θα μιλήσουμε για κινούμενα σχέδια και, για να είμαστε ακριβείς, για Κινούμενα σχέδια Sprite. Φανταστείτε, για παράδειγμα, έναν άνδρα να περπατά. Προβάλλοντας το παράδειγμα στην οθόνη του smartphone, θα έχουμε ένα κινούμενο σχέδιο που αποτελείται από έναν ορισμένο αριθμό εικόνων, οι οποίες μπορούν να επαναληφθούν επ ‘αόριστον ή όχι.

Κινούμενα σχέδια Sprite

Ας πάρουμε το gif παρακάτω. Είναι, όπως μπορείτε να μαντέψετε, ένα κινούμενο σχέδιο α χαμηλό ρυθμό καρέ. Είναι απλώς ένα Sprite και, αν θέλαμε να το αναπαραγάγουμε, χρειαζόμαστε κάθε καρέ που αποτελεί το κινούμενο σχέδιο.

walk_elaine_anim

Τώρα, το ερώτημα έρχεται φυσικά: πόσες εικόνες υπάρχουν; Η απάντηση είναι πολύ απλή:

walk_elaine

Το επόμενο βήμα είναι να ταξινομήσετε, καθώς είναι λογικό και, ακόμη και σε αυτήν την περίπτωση, το πρόβλημα είναι πολύ ασήμαντο:

walk_elaine_frames

Η παραπάνω εικόνα, για να είμαι ειλικρινής, είναι ευρεία 150 εικονοστοιχεία αφού κάθε πλαίσιο είναι 30 εικονοστοιχεία. Για να αποκτήσουμε το animation μας με Android, θα πρέπει απλώς να φορτώσουμε το καθένα πλαίσιο ως ξεχωριστή εικόνα και δείτε κάθε μία από αυτές σε τακτά χρονικά διαστήματα. Μια άλλη μέθοδος είναι να φορτώσετε ολόκληρη την εικόνα με όλα τα καρέ και να χρησιμοποιήσετε το Μέθοδοι Android για να το κόψουμε (όπως γνωρίζουμε το μέγεθος κάθε καρέ), και αυτή είναι ακριβώς η διαδικασία που θα χρησιμοποιήσουμε. Η παρακάτω εικόνα δείχνει τον τρόπο επιλογής και περικοπής των πλαισίων.

walk_frames_cut

Τώρα που γνωρίζουμε τα βασικά, ας δημιουργήσουμε ένα νέο έργο στο Eclipse. Θα χρησιμοποιήσουμε τις γνώσεις που αποκτήθηκαν στο προηγούμενα μαθήματα (ιδίως σχετικά με τον κύκλο παιχνιδιού) για την ανάπτυξη των κινούμενων σχεδίων Sprite.

Ας προχωρήσουμε στον κώδικα

Πρώτα απ ‘όλα, θα χρειαζόμαστε ένα αντικείμενο για να κινούμαστε. Θα το χρησιμοποιήσουμε σωστά Elaine από το Monkey Island και θα δημιουργήσουμε την τάξη ElaineAnimated.java:

package it.androidblog.lessons;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

public class ElaineAnimated {

	private static final String TAG = ElaineAnimated.class.getSimpleName();

	private Bitmap bitmap;		// La sequenza animata
	private Rect sourceRect;	// il rettangolo da disegnare 
	private int frameNr;		// il numero di frame nell'animazione
	private int currentFrame;	// il frame corrente
	private long frameTicker;	// il tempo passato dall'ultimo frame aggiornato
	private int framePeriod;	// ms tra ogni frame (1000/fps)

	private int spriteWidth;	// la larghezza della Sprite
	private int spriteHeight;	// l'altezza della Sprite

	private int x;				// la coordinata X dell'oggetto
	private int y;				// la coordinata Y dell'oggetto

	public ElaineAnimated(Bitmap bitmap, int x, int y, int width, int height, int fps, int frameCount) {
		this.bitmap = bitmap;
		this.x = x;
		this.y = y;
		currentFrame = 0;
		frameNr = frameCount;
		spriteWidth = bitmap.getWidth() / frameCount;
		spriteHeight = bitmap.getHeight();
		sourceRect = new Rect(0, 0, spriteWidth, spriteHeight);
		framePeriod = 1000 / fps;
		frameTicker = 0l;
	}

	public Bitmap getBitmap() {
		return bitmap;
	}
	public void setBitmap(Bitmap bitmap) {
		this.bitmap = bitmap;
	}
	public Rect getSourceRect() {
		return sourceRect;
	}
	public void setSourceRect(Rect sourceRect) {
		this.sourceRect = sourceRect;
	}
	public int getFrameNr() {
		return frameNr;
	}
	public void setFrameNr(int frameNr) {
		this.frameNr = frameNr;
	}
	public int getCurrentFrame() {
		return currentFrame;
	}
	public void setCurrentFrame(int currentFrame) {
		this.currentFrame = currentFrame;
	}
	public int getFramePeriod() {
		return framePeriod;
	}
	public void setFramePeriod(int framePeriod) {
		this.framePeriod = framePeriod;
	}
	public int getSpriteWidth() {
		return spriteWidth;
	}
	public void setSpriteWidth(int spriteWidth) {
		this.spriteWidth = spriteWidth;
	}
	public int getSpriteHeight() {
		return spriteHeight;
	}
	public void setSpriteHeight(int spriteHeight) {
		this.spriteHeight = spriteHeight;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}

	// Il metodo update per Elaine
	public void update(long gameTime) {
		if (gameTime > frameTicker + framePeriod) {
			frameTicker = gameTime;
			// incremento del frame
			currentFrame++;
			if (currentFrame >= frameNr) {
				currentFrame = 0;
			}
		}
		// definiamo l'area rettangolare da tagliare
		this.sourceRect.left = currentFrame * spriteWidth;
		this.sourceRect.right = this.sourceRect.left + spriteWidth;
	}

	// il metodo che disegna il corrispondente frame
	public void draw(Canvas canvas) {
		// dove disegnare la sprite
		Rect destRect = new Rect(getX(), getY(), getX() + spriteWidth, getY() + spriteHeight);
		canvas.drawBitmap(bitmap, sourceRect, destRect, null);
		canvas.drawBitmap(bitmap, 20, 150, null);
		Paint paint = new Paint();
		paint.setARGB(50, 0, 255, 0);
		canvas.drawRect(20 + (currentFrame * destRect.width()), 150, 20 + (currentFrame * destRect.width()) + destRect.width(), 150 + destRect.height(),  paint);
	}
}

Όλα τα ιδιωτικά χαρακτηριστικά σχολιάζονται, αλλά αξίζει να δαπανηθούν δύο λέξεις σε ορισμένες από αυτές:

  • bitmap Είναι η εικόνα που περιέχει όλα τα καρέ (όπως αυτό που είδαμε παραπάνω).
  • sourceRect Είναι το ορθογώνιο που “κόβει” κάθε πλαίσιο και κινείται στο επόμενο.
  • frameTicker είναι ο χρόνος που περνά από το τελευταίο ενημερωμένο πλαίσιο.
  • framePeriod είναι ο χρόνος σε χιλιοστά του δευτερολέπτου που περνά από το ένα καρέ στο άλλο (εάν ο κύκλος ολοκληρωθεί σε ένα δευτερόλεπτο, δηλαδή 5 καρέ, καθένα από αυτά θα εμφανίζεται κάθε 0,2 δευτερόλεπτα).

Ας μιλήσουμε τώρα για τον κατασκευαστή. Υποθέτοντας ότι κάθε πλαίσιο έχει το ίδιο πλάτος, μπορούμε να αντλήσουμε το πλάτος του ορθογωνίου διαιρώντας εκείνο της εικόνας με τον αριθμό των καρέ που περιέχει. Φυσικά, η Elaine θα χρειαστεί επίσης μια μέθοδο για την ενημέρωσή της, ως κινούμενο αντικείμενο και, καθώς ο χρόνος ενημέρωσης του κύκλου παιχνιδιού είναι διαφορετικός από αυτόν του Elaine, θα περάσουμε στοενημέρωση () του πρωταγωνιστή μας τον πραγματικό χρόνο παιχνιδιού ως μεταβλητή, έτσι ξέρουμε πότε δείτε το επόμενο καρέ.

Στο πλαίσιο του παιχνιδιού (MainGamePanel.java) αυτή θα είναι η μέθοδος ενημέρωσης:

public void update() {
	elaine.update(System.currentTimeMillis());
}

Η λειτουργία είναι απλή, το πλαίσιο αυξάνεται μόνο εάν περάσει ο χρόνος (System.currentTimeMillis ()) είναι μεγαλύτερο από frameTicker συν framePeriod, η έννοια της οποίας σε αυτό το σημείο πρέπει να είναι σαφής σε όλους. Εάν το προηγούμενο πλαίσιο είναι πέρα ​​από το τελευταίο, ο κύκλος επαναφέρεται.

Μόλις καθοριστεί η περιοχή που θα κοπεί (sourceRect, απλώς πρέπει να του δώσουμε έναν προορισμό (destRect) και σχεδιάστε το (ρίξτε μια ματιά στη μέθοδο σχεδιάζω από την Elaine). Το τελευταίο τεκμηριώνεται στον κατασκευαστή του πίνακα περνώντας τις απαραίτητες παραμέτρους (μερικές αγνοούνται, αλλά είναι χρήσιμες για την πραγματοποίηση αλλαγών στον κώδικα), μεταξύ των οποίων Αριθμός FPS και αριθμός καρέ.

Στη μέθοδο κλήρωσης του Elaine, δημιουργούμε επίσης ένα αντικείμενο Χρώμα για να σχεδιάσετε το τρέχον πλαίσιο πάνω του. Με τη μέθοδο setARGB δημιουργούμε ένα ημιδιαφανές πράσινο χρώμα. Μετά από όλα αυτά, ζωγραφίζουμε ένα ορθογώνιο το μέγεθος ενός πλαισίου στην αρχική εικόνα, έτσι ώστε να μπορούμε να δούμε ποιο πλαίσιο εμφανίζεται κατά τη διάρκεια της κινούμενης εικόνας.

Όσο για τα μαθήματα Κύριο νήμα, Κύρια δραστηριότητα και τα υπόλοιπα MainGamePanel, μπορείτε να τα βρείτε στον πλήρη κώδικα (με δυνατότητα λήψης εδώ), αλλά εξακολουθούν να είναι τα ίδια με τα προηγούμενα μαθήματα. Η εικόνα είναι walk_elaine.png και μπορείτε να το βρείτε res / drawable-mdpi.

Όταν ξεκινάτε την εφαρμογή, το αποτέλεσμα θα είναι το ακόλουθο:

Στιγμιότυπο οθόνης από το 2014-02-19 13:20:28