Apr 102013
 

In der letzten Lektion haben wir ein Interface für unser Android Spiel erstellt. In dieser Lektion werden wir nun zum zweiten Schritt übergehen: Die Implementierung.

Wenn wir nun das Skelett der letzten Lektion nehmen, werden wir nun die Brücke zwischen Android Code und unserem Spiel schließen.

Was ist Implementierung?

Wir werden wörtlich genommen die Interfaces implementieren, mit dem eingebauten Word implements. Wir werden also einige Android Klassen importieren und einige Android Methoden aufrufen.

Dies ist eine der wichtigsten Lektionen bisher, also nehmt euch Zeit.

Dieser Code steht unter der Apache 2.0 Lizenz: http://www.apache.org/licenses/LICENSE-2.0.txt

Erstellen der Implementierung

Erstellen des Pakets

In dem src Ordner erstellen wir ein neues Paket, wie folgt.

k4l6b1

Alle Implementierungen werden wir nun hier abspeichern.

Bedenkt das dieser Code für com.basteldroid.framework.implementation geschrieben wurde. Wenn ihr euren eigenen Code verwendet, müsst ihr dies anpassen.

Die AndroidGame Klasse

Unter dem neuen Paket erstellt ihr eine neue Klasse mit dem Namen AndroidGame. Diese Klasse ist das Rückgrat von eurem Spiel.

Wenn ihr diese Klasse erstellt, werden viele Fehler auftreten. Bitte Ignoriert diese, wir werden alle nach und nach beheben.

Bevor wir die weiteren Implementierungen programmieren, schauen wir uns diesen Code genauer an.

1. Android Libraries – Android Büchereien – die ersten 10 importier Statements fangen alle mit Android an. Das bedeutet, wir arbeiten hier mit Android Klassen, die in der SDK Platform gespeichert sind.

Ein paar dieser Klassen werden wir hier näher betrachten, die restlichen sind hier beschrieben: http://developer.android.com/reference

Ein Activity – Eine Aktivität ist normalerweise ein interaktives Window/Fenster. Innerhalb einer normalen App sehen wir dies häufig. So sehen wir meistens eine Login Seite, eine separate Einstellungsseite und so weiter.

Activities sind für Views/Ansichten erstellt wurden, so wie Bilder oder Text.

Bundle lässt uns Informationen zwischen einzelnen Aktivitäten austauschen. Wenn wir uns also auf der Login Seite einloggen, überprüft die nächste Aktivität ob diese Daten auch wirklich stimmen.

PowerManager.WackeLock hilft uns, dass Smartphone an zu lassen, so lange das Spiel läuft.

2. In dem zweiten Teil importieren wir unsere Interfaces. Dabei erstellen wir Objekte bei den Variablen. Des Weiteren erweitern wir AndroidGame extends Activity implements Game, damit implementieren wir unser Spiel Interface.

3. In unserem Code erstellen wir als erstes eine onCreate()-Methode. Um das genau zu verstehen, müssen wir als erstes das Android Activity Lifecycle – Android Aktivitäten Lebenszyklus – verstehen.

k4l6b2

Android ist eine Mobile Plattform, daher kann der momentane Stand unserer Aktivität pausiert oder fortgesetzt werden, erstellt gestoppt, zerstört oder neu gestartet werden. Wenn wir zum Beispiel ein Anruf erhalten, wir die App die wir in diesem Moment ausführen gestoppt. Genau das selbe passiert, wenn wir den Home Button drücken. Wenn wir die App danach wieder öffnen, wird diese fortgesetzt.

Deshalb benötigt unsere App diese Methoden um diese Übergangsphasen ohne Fehler, Abstürze oder Ähnliches zu überstehen.

Die onCreate()-Methode wird aufgerufen, wenn die App das erste mal startet. Da dort @Override steht, können wir erkennen, dass diese Methode zu einer Super Klasse gehört.

Normalerweise kann man in der onCreate()-Methode das Layout der Aktivität erkennen. In jedem Punkt des Activity Lifecycle rufen wir als erstes die Super Methode auf, das ist die Standart onCreat()-Methode. Normalerweise haben Apps eine Leiste Oben, wo der Name der App angezeigt wird. Wir schreiben als erstes, dass unsere App im Full Screen Modus ausgeführt werden soll.

4. Als nächstes überprüfen wir die momentane Display Ausrichtung des Gerätes und setzen die Höhe und Breite unseres Spiels. Als nächsten nutzen wir folgenden Code: int frameBufferWidth = isPortrait ? 800: 1280;

Das ? ist eine Art Auswertung einer boolean. Wenn der boolean isPortait wahr ist, dann nimmt der frameBufferWidth 800 an. Ist er Falsch wird der Wert 1280 angenommen.

Hier können wir die Auflösung unseres Spiels einstellen. Wir werden 800×480 verwenden um auch schwächere Geräte zu unterstützen. Wir könnten hier auch mit IF Statements arbeiten um auf höher auflösenden Bildschirmen mit besserer Grafik zu arbeiten. In dieser Anleitung werden wir einen eine Größe passt allen Weg einschlagen.

5. Die App passt sich also automatisch an kleine und große Bildschirme an, was wir im nächsten Schritt programmieren.

6. Danach definieren wir jedes Interface, dazu erstellen wir neue Instanzen der Implementierungsklassen, welche wir noch erstellen.

7. Wir verwenden den PowerManager um die WakeLocks Variablen zu definieren. Wir erwerben und geben diese frei in der onResume und onPause Methode. Warum? Schaut euch nochmals genau den Android Activity Lifecycle an.

8. Der Rest der AndroidGame Klasse definiert viele zusätzliche Methoden um zu den verschiedensten Interfaces zurückzukehren. Des Weiteren definieren wir die setScreen und die getCurrentScreen Methode des Spiele Interfaces.

Ich hoffe ihr habt nun den Aufbau und das verhalten einer Android Activity verstanden? Versucht dies erst komplett zu verstehen wie AndroidGame Implementation und das Game Interface miteinander zusammenarbeiten. Habe ich eventuell etwas nicht vollkommen klar Erläutert oder eurer Meinung nach falsch, dann bitte berichtigt mich. Dies ist ein wichtiger Schritt hin zur Android Entwicklung.

Die AndroidGraphics Klasse

Hier werden wir einige abstrakte Methoden implementieren, welche wir in dem Graphics Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

In der Graphics Klasse erläutert sich das meiste von selbst.

1. Bitmap erlaubt uns ein Bild Objekt zu erstellen.

2. Canvas ist die Leinwand unserer Bilder. Wir zeichnen Bilder auf diese Leinwand, welche dann auf dem Bildschirm gezeigt werden.

3. Paint wird dazu verwendet, dass was wir auf den Bildschirm wieder geben zu zeichnen.

Wenn wir ein Bild auf dem Bildschirm anzeigen lassen, wird dieses als erstes im Arbeitsspeicher gespeichert. Jedes mal, wenn wir nun dieses Bild aufrufen, wird es aus dem Speicher aufgerufen. Es ist dabei egal wie viel Arbeitsspeicher ein Gerät hat, jeder App steht nur der sogenannte „Heap“ zu. Das kann bei einigen Geräten nur 16MB sein. Daher muss man mit der Speicherbelastung sehr kritisch umgehen.

Aus diesem Grund müssen wir ein paar Erfahrungen mit ImageFormats sammeln. Ein Pixel eines Bildes verbraucht 1 Bit, was 1/8 Byte entspricht. Nun können wir die Größe eines Bildes berechnen, indem wir einfach Länge mal Breite nehmen. Es gibt aber einen weiteren Faktor, die Bildtiefe und genau hier kommt ImageFormats ins Spiel.

In dem Graphics Interface haben wir die folgenden 3 ImageFormats programmiert. Diese 3 kann man verwenden, wenn wir Bilder im Arbeitsspeicher hinterlegen.

Das erste ist RGB565, dies benötigt den geringsten Speicher, normalerweise. Rot, Grün und Blau haben eine Tiefe von 5, 6 und 5. Hierbei können wir aber keinen Transparenten Wert festlegen.

ARGB4444 ist unser zweites Format mit einer Tiefe von 16. Dieses sollte man verwenden, wenn man ein transparentes Bild  benötigt.

ARGB8888 ist das Format mit der größten Tiefe von 32. Wenn es möglich ist, sollte man darauf verzichten. ARGB4444 sollte ausreichen.

Je Höher wir die Tiefe eines Bildes wählen desto mehr Qualität haben wir. Wollen wir für etwas schwächere Geräte entwickeln, können wir dadurch schnell an den Heap stoßen. Ein Bild mit 1000×1000 hat bei einer Tiefe von 32 genau 32.000.000 Bits Arbeitsspeicher belegt, das sind rund 4MB. Wenn wir also 4 solcher Bilder haben, ist unser Gerät mit 16MB Heap überlastet und wir bekommen einen Out of Memory Exception und unser Spiel funktioniert nicht mehr. Das würde bedeuten, dass wir sonst nichts anderes im Speicher haben, was nicht möglich ist.

In der AndroidGraphics Klasse finden wir eine menge Methoden, die das Zeichnen für uns übernehmen. Hier sind auch viele Try, Catch und Finally Statements untergebracht. Macht euch darüber keine Gedanken, diese erledigen für uns die Arbeit.

Die AndroidFileIO Implementation

Hier werden wir einige abstrakte Methoden implementieren, welche wir in dem FileIO Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Hier ergeben sich einige Fehler, wenn wir aber fertig sind mit dieser Lektion, werden alle verschwunden sein. Da die Klasse sich von selbst erklärt, vorausgesetzt ihr habt alle Kapitel durchgearbeitet, werde ich diese nicht weiter erläutern. Falls ihr dennoch etwas Hilfe benötigt, könnt ihr diese hier finden: http://developer.android.com/reference

Die AndroidAudio Implementation

Hier werden wir einige abstrakte Methoden implementieren, welche wir in dem Audio Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

SoundPool ist die Klasse, die die Handhabung der Musik vom Arbeitsspeicher oder aus dem Dateisystem bewerkstelligt.

Kurze Musik die immer und immer wieder auftauchen, können wir im Arbeitsspeicher hinterlegen, dies nimmt viel Arbeit vom Prozessor. Lange Musikstücke die den Arbeitsspeicher voll schreiben würden, können wir direkt vom Dateisystem abgespielt werden.

Daher benötigen wir die nächsten 2 Implementations-: Sound und Music.

Die AndroidSound Interface

Hier werden wir einige abstrakte Methoden implementieren, welche wir in dem Sound Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Hier werden die kurzen Sounds gemanagt, abgespielt und aus dem Arbeitsspeicher wieder entfernt.

Die AndroidMusic Implementation

Hier werden wir einige abstrakte Methoden implementieren, welche wir in dem Music Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Hier werden einige Methoden definiert, die zum Abspielen von Musik notwendig sind.

Das wichtigste Objekt ist der MediaPlayer, hier werden Audio und Video Abspielung kontrolliert. Des Weiteren finden wir auch einige Listeners, welche den momentanen Stand der Abspielung überprüfen. Diese kann man mit den KeyListeners aus Kapitel 2 und 3 vergleichen.

Die AndroidFastRenderView Klasse

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Weiter oben haben wir uns mit Aktivitäten auseinandergesetzt. Dabei habe ich von einem Window gesprochen, hier wiird eine Klasse SurfaceView erstellt. Diese können wir dazu verwenden grafisch basierende Benutzerumgebung zu programmieren, die sehr schnell sich aktuallisiert.

Diese Klasse gibt unser Spiel auf dem Bildschirm wieder. Hier finden sich die update() und paint()-Methode wieder. Auch deltaTime können wir hier finden.

Bildfrequenz unabhängige Bewegung

In unserem Spiel aus Kapitel 2 und 3 hatten wir eine Bewegung des Roboters, welche von der Bildfrequenz abhängig war. Wir haben sie erst einmal auf 60 gesetzt. Wenn nun der Computer stark ausgelastet war, hätte sich dadurch die Frequenz verringern können. Gehen wir davon aus, dass durch eine hohe Auslastung der CPU unsere Bildfrequenz sich halbiert hätte auf 30. Das würde auch bedeuten, unser Roboter bewegt sich nur noch halb so schnell. All das macht unseren Computer aber eigentlich nichts aus und wird so bei unserem Spiel auch nicht passieren.

Aber wir wollen für Android entwickeln und da gibt es sehr große Unterschiede zwischen den einzelnen Geräten. Des Weiteren bekommen die Geräte beim spielen Nachrichten, E-Mails und noch viel mehr. All dies belastet die CPU und die meisten Geräte sind auch nicht dafür ausgelegt 60 Bilder die Sekunde darzustellen, daher haben wir eine sehr stark schwankende Bildfrequenz.

Um uns von der Bildfrequenz unabhängig zu machen, benutzen wir die Variable deltaTime. Diese überprüft, wie viel Zeit seit dem letzten Update vergangen ist. Wenn also nun doppelt soviel Zeit vergangen ist seit dem letzten Update, verdoppelt sich unsere deltaTime. Wir unterziehen deltaTime durch unsere update-Methode immer wieder der Überprüfung, so das unsere Spielfigur immer den selben Weg zurücklegt in der selben Zeit.

Natürlich kann das zu vielen Problemen führen. Wir können von 1 Pixel pro Sekunde auf bis zu 10 kommen. Dies würde unsere Kollision Methoden komplett überfordern und dazu führen, dass unser Spiel nicht spielbar ist. Aus diesem Grund ist deltaTime nach oben nicht offen und ist bei 3,15 gedeckt. Falls also unser Spiel erheblich langsamer wird, benutzen wir wieder eine Bildfrequenz, so dass nicht unser Spiel abstürzt. Dies ist die Priorisieren bei der Arbeit.

Damit kommen wir nun zur Eingabe.

Die AndroidInput Implementation

Hier werden viele der abstrakten Methoden verwendet, welche wir in dem Input Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Diese Implementierung benötigt 3 andere Klassen, welche wir gleich erstellen werden. Kurze Info nebenbei:

In Android 2.0 wurde Multi-Touch eingeführt. In dieser Implementierung überprüfen wir die SDK Build Version und implementieren den erforderlichen Touch Handler. SDK Version 5 ist Android 2.0.

Die TouchHandler Klasse

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Diese einfache Klasse übernimmt das Touch geschehen, es überprüft für touchDown die X und Y Koordinaten.

Die SingleTouchHandler Klasse

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Die MultiTouchHandler Klasse

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Die letzten beiden Klassen haben sehr oft auf die Pool Klasse zugegriffen. Da wir mit dieser Klasse nichts viel anfangen können, spare ich aus Zeitgründen eine Erleuterung.

Die AndroidImage Implementation

Dies ist die letzte Klasse die wir erstellen. Hier werden wir einige der abstrakten Methoden implementieren, welche wir im Image Interface erstellt haben.

Denkt daran den Paket Namen zu ändern, falls ihr euren eigenen benutzt.

Das ist auch unsere letzte Klasse, diese Klasse erklärt sich von alleine, oder?

Damit haben wir das Grundgerüst abgeschlossen und wir sind bereit unser erstes Spiel zu programmieren.

Falls ihr Fragen habt, immer raus damit, ich helfe euch sehr gerne. Hinterlasst bitte einfach einen Kommentar.

Teilt diese Seite mit euren Freunden und besucht uns mal auf Facebook und auf Google+, dass würde dieser Seite wirklich weiterhelfen, Danke sehr. Oder ein Klick auf die Werbung, hilft dabei diese Seite am laufen zu halten.

Source Code

Falls einer hier einsteigen möchte oder nicht den ganzen Code abtippen möchte, habe ich hier das Projekt exportiert und ihr könnt diesen bei euch einfügen. Unter der Kategorie Eclipse und Import und Export habe ich erläutert wie ihr dies macht.

AndroidSpielGrundgerüst

Quelle: Original Anleitung auf englisch von Kilobolt Studios

Lektion 5 – Grundgerüst eines Android Spiels Teil 1 Lektion 7 - Erstellen eines Spiels von a bis z