text: Im vorläufig finalen Teil dieses Tutorials lernst Du ein schwebendes Head-up Display anzuzeigen.
  Spiel am Ende des Tutorials
  Teil 1 - Background Scrolling und Double buffering
  Teil 2 - Sprite Animation
  Teil 3 - Head-up Display und Performance Optimierung
  Variable Hintergrundgeschwindigkeit
  Um die Animation ein wenig lebhafter oder näher an der Realität zu gestalteten interpretierst Du nun eine Position rechts der Mitte als schnelles fliegen und links der Mitte als langsames fliegen. Dazu erweiterst Du onSensorChanged ein weiteres mal.
  float[] coords = getPlanePosition(y,z,maxAngle);
  int bgBaseSpeed = 12;
  int bgSpeed = (int) (bgBaseSpeed + ((24)*(y/maxAngle)));
  bgv.getBackgroundModel().setSpeed(bgSpeed < 3 ? 3 : bgSpeed);
  pv.getPlane().setPosition(coords);
  pv.invalidate();
  Listing 1: Berechnen der horizontalen Position des Flugzeuges
  In Zeile 6 sorgen wir dafür, dass die Geschwindigkeit des Hintergrundes nicht unter 3 geht, da dies die Illusion eines schwebenden Flugzeuges erwecken würde.
  Nun ändert sich die Hintergrundgeschwindigkeit in Abhängigkeit von der Position des Flugzeuges.
  5.1 Anzeigen der Geschwindigkeit als Hud
  Als ein Hud bezeichnet man ein Anzeigefeld das sich im Blick des Anwenders, in diesem Fall, des Spielers befindet.
  Um die aktuelle Geschwindigkeit als zusätzliche Information auf den Bildschirm zu bringen, musst Du die Information aus der Background Klasse holen, und diese auf das Display zeichnen. Dies machst Du in einem View.
  Man könnte dies in einen eigenen View auslagern, aber für dieses Tutorial ist es einfacher die Information auf die Ebene zu legen auf der sich das Flugzeug befindet.
  Dazu erweiterst Du die Klasse PlaneView um die markierten Felder.
  private final String textLabel = "Speed: ";
  Listing 2: Erweiterung der PlaneView-Klasse
  Im Konstruktor weist Du den Context, welchen wir zum Erzeugen des Views benutzt haben, dem erstellten Feld zu. Den Context benötigst Du später um die Textfarbe auflösen zu können.
  public PlaneView(Context context, Plane plane, Background bg) {
  Listing 3: PlaneView Konstruktor
  Im onDraw-Callback wird der anzuzeigende Text zusammen gebaut. Dieser besteht aus einem Label, das beschreibt um welche Art von Information es sich handelt, und die Information selbst. Dabei invertieren wir die Geschwindigkeit des Hintergrundes.
  Zeichne das Label und die Geschwindigkeit in die obere rechte Ecke des Bildschirms. Da Du die Größe des Textes nicht kennst, musst Du diese zuerst berechnen. Dazu gibst Du den Text, sowie ein Rect-Objekt an die Methode getTextBounds weiter. Danach steht in Rect die endgültige Größe des Textes, wenn er mit den in Paint spezifizierten Optionen gezeichnet wird.
  canvas.drawBitmap(plane.getImage(), plane.getX(), plane.getY(), null);
  String text = textLabel+(-bg.getSpeed());
  Paint paint = getPaint(30);
  canvas.drawText(text, (getWidth()-(int)(rect.width()*1.1)), rect.height(), paint);
  private Paint getPaint(float fontSize) {
  Typeface tf = Typeface.create("Droid Sans", Typeface.BOLD);
  paint.setColor(context.getResources().getColor(android.R.color.holo_green_light));
  Listing 4: Hud zeichnen
  Hud hinzugefügt
  5.2 Optimieren der Head-up Anzeige
  Beim Testen der App wirst Du feststellen, dass die Stellenzahl in der Anzeige der Geschwindigkeit variiert. Dies führt zu einem Springen des Textes. Wird die Geschwindigkeit einstellig, benötigt der Text weniger Platz. Da die Positionierung des Textes ebenfalls stetig neu gerechnet wird, wird die Position an die neuen Verhältnisse angepasst.
  Dies kannst Du dadurch beheben, dass Du die Information auf zwei verschiedene Zeichenoperationen verteilst.
  keepPlaneVisible(plane.getX(), plane.getY());
  canvas.drawBitmap(plane.getImage(), coords[0], coords[1], null);
  String speedText = ""+(-bg.getSpeed());
  paint.getTextBounds(speedText, 0, speedText.length(), rect);
  float speedTextX = getWidth()-(int)(rect.width()*1.1);
  canvas.drawText(speedText, speedTextX, rect.height(), paint);
  paint.getTextBounds(textLabel, 0, textLabel.length(), rect);
  canvas.drawText(textLabel,speedTextX-(int)(rect.width()*1.1),rect.height() , paint);
  Listing 5: Hud Anzeige mit zwei Labeln
  Jetzt ist der Text aufgeteilt, doch die Position des Labels ist noch von der Breite der Geschwindigkeitsanzeige abhängig. Das Label wird also wieder springen.
  Da die Geschwindigkeit so gewählt ist, dass sie niemals über zwei Stellen hinaus kommen kann und mit zwei Stellen startet, berechnest Du die Position des Labels einmalig beim ersten Zeichnen und merkst Dir im Folgenden die Position.
  paint.getTextBounds(textLabel, 0, speedText.length(), rect);
  yOffset = rect.height();
  if (speedXCoordinate == 0)
  speedXCoordinate = (getWidth()-rect.width())-10;
  canvas.drawText(textLabel, (speedXCoordinate-rect.width()-10), yOffset, paint);
  canvas.drawText(speedText, speedXCoordinate, yOffset, paint);
  Listing 6: Berechnung der Position der Hud Texte
  Die beiden Instanzvariablen yOffset und speedXCoordinate existieren noch nicht. Diese legt Dir Eclipse an, wenn du einen Rechtsklick auf die Variablen ausführst und dann die Option Create Field wählst.
  5.3 Verschiedene Dispalygrößen
  Da Du deine App auf möglichst vielen Geräten gleich darstellen möchtest, gibt es noch ein Problem zu lösen. Das Padding zwischen den beiden Texten wurde in Listing Zeile 16 und 19 durch eine Konstante 10 realisiert. Das führt aber in Abhängigkeit von der Displaygröße zu unterschiedlichen Ergebnissen. Das gleiche gilt für die an getPaint übergebene Fontsize in Zeile 7. Android selbst bietet eine relativ simple Lösung für dieses Problem.
  Im Projekt gibt es einen Ordner Values, und darin erzeugst Du eine dimens.xml Datei. Sollte diese noch nicht existieren, erstelle diese durch einen Rechtsklick auf den Ordner values und wähle die New>Android XML File. Im Folgenden Dialog gibst du den Dateinamen dimens.xml an und schließt den DIalog mit einem Klick auf finish.
  Die Datei sollte zu Beginn so aussehen:
  Listing 7: dimens.xml Datei
  Du ergänzt diese um die folgenden Einträge:
  <dimen name="labelPadding">10dp</dimen>
  <dimen name="speedFontSize">30sp</dimen>
  Listing 8: Dimen Einträge
  Nun kannst du die hinterlegten Werte im Code auslesen, dabei sind diese automatisch an die Displaygröße des jeweiligen Gerätes angepasst:
  int fontSize = context.getResources().getDimensionPixelSize(R.dimen.speedFontSize);
  Paint paint = getPaint(fontSize);
  Listing 9: Zugriff auf Ressourcen
  Diese Ergänzung bewirkt, dass die Darstellung des Textes auf allen Geräten gleich groß erscheinen wird, da Du keine absolute Größe angibst. Die für die Schriftgröße angegebenen 30sp werden vom System entsprechend der Displaygröße umgerechnet. Überarbeite entsprechend auch das Padding des Labels.
  speedXCoordinate = (getWidth()-rect.width()/2)- context.getRessources().getDimensionPixelSize(R.dimen.labelPadding);
  Listing 10: Padding abhängig von der Displaygröße
  5.4 Leistungsoptimierung
  Um gerade bei älteren Geräten eine bessere Performance zu erreichen, empfiehlt es sich, den Bildschirm zu "beschneiden". Anhand unserer Skizze können wir absehen, dass die zwei Bilder zusammen auf jeden Fall größer sind als der Bildschirm selbst. Daher empfiehlt es sich, den eigentlichen Zeichenbereich auf die Displaygröße zu reduzieren um die Rechenzeit zu minimieren. Ob Android bei einem SurfaceView über die Grenzen hinaus zeichnen würde, konnte ich nicht defintiv feststellen, daher mache ich das an dieser Stelle präventiv.
  Dies realisiest Du durch eine Modifikation der run-Methode des BackgroundViews.
  canvas.clipRect(0, 0, getWidth(), getHeight(), Region.Op.REPLACE);
  canvas.drawBitmap(bg.getBitmap(), bg.getX(),0, null);
  canvas.drawBitmap(bg.getBitmap(), (bg.getX()+bg.getBitmap().getWidth()),0, null);
  if (getDeltaTime(startTime) > 0.1) {
  Listing 11: Performance optimierung mit Clipping
  Starte die App und fliege durch die Wolken. Deine App sollte jetzt in etwa so aussehen.
  Gratulation, Du hast dieses Tutorial erfolgreich gemeistert. Im letzten Abschnitt findest Du noch einige Anregungen, wie Du das noch unfertige Spiel selbst erweitern kannst.
  Du hast also gelernt, wie Du einen sich bewegenden und reagierenden Hintergrund erzeugst. Einen Sprite darauf zeichnest, wie Du diesen manipulieren kannst und welche Möglichkeiten es gibt, dessen Steuerung zu verbessern.
  Wir haben in diesem Android Game Tutorial eine Ausgangsbasis für Actionspiele entwickelt. Von hier aus sind viele Erweiterungen und Verbesserungen möglich. Denkbar wäre es zum Beispiel gegnerische Flugzeuge einzuführen, welche auf das eigene Flugzeug schießen und damit kollidieren können. Es liegt nahe dem eigenen Flugzeug die gleichen Fähigkeiten zu geben. Möchte man den Schwierigkeitsgrad erhöhen, könnte man zusätzlich noch nicht zerstörbare Objekte einführen die in der Flugbahn des Flugzeuges auftauchen.
  Du könntest auch eine kleine Wolke oberhalb des Flugzeuges platzieren, sodass das Flugzeug für kurze Zeit in der Wolke verschwindet.
  Solche Hindernisse ermöglichen ebenfalls eine völlig andere Ausrichtung des Spieles. Geht es darum Hindernissen auszuweichen, könnte man auch ein Geschicklichkeitsspiel daraus machen, bei dem es darum geht den Kurs möglichst schnell zu absolvieren.