Java ME
Transcrição
Java ME
Fachhochschule Fulda Angewandte Informatik – Applied Computer Science Ausarbeitung M3G auf Symbian OS (Java ME) – mit ergänzender schwerpunktmäßiger Betrachtung der 2D Spieleentwicklung auf Java ME Betreuer : Prof. Dr. Werner Heinzel Bearbeitet von: Christian Burmeister Abgabetermin: 07.01.2009 I NHALT 1. Kurzzusammenfassung......................................................................................3 2. Einleitung.............................................................................................................3 3. Java für mobile Endgeräte.................................................................................4 3.1 Konfigurationen, Profile und optionale Pakete ..................................................................... 4 3.1.1 Konfigurationen ........................................................................................................... 5 3.1.1.1 CLDC (Connected Limited Device Configuration) ....................................................... 5 3.1.1.2 CDC (Connected Device Configuration) ..................................................................... 5 3.1.2 Profile.......................................................................................................................... 5 3.1.3 optionale Pakete .......................................................................................................... 6 3.2 MIDlet-Grundlagen .............................................................................................................. 6 3.3 Erste Schritte mit Java ME .................................................................................................. 7 3.4 Entwicklungswerkzeuge ...................................................................................................... 8 3.5 Installation auf mobilem Endgerät ..................................................................................... 10 4. Mobile 3D Graphics API (M3G)......................................................................11 4.1.1 Immediate Mode ........................................................................................................ 12 4.1.2 Retained Mode .......................................................................................................... 12 5. 2D Spieleprogrammierung...............................................................................13 5.1 Einführung in die Spieleprogrammierung .......................................................................... 5.1.1 Grundgerüst mit Spielschleife ................................................................................... 5.1.2 Animation .................................................................................................................. 5.1.3 Tastensteuerung........................................................................................................ 5.1.4 Erstellung eines Levels .............................................................................................. 5.1.5 Scrolling des Levels ................................................................................................... 5.1.6 Zeichnen des Levels .................................................................................................. 5.1.7 Kollisionserkennung im Level .................................................................................... 5.1.8 Kollisionserkennung bei Objekten ............................................................................. 5.2 Beispielprogramme ............................................................................................................ 13 13 14 18 19 20 21 22 24 25 6. Abschluss..........................................................................................................27 6.1 Anmerkungen zur Ausarbeitung ....................................................................................... 27 6.2 Schlusswort....................................................................................................................... 27 7. Literatur und Verzeichnisse.............................................................................28 7.1 Literaturverzeichnis ........................................................................................................... 28 7.2 Internetquellen .................................................................................................................. 28 7.3 Abkürzungsverzeichnis ...................................................................................................... 30 8. Anhang...............................................................................................................31 8.1 Einrichten von Eclipse ...................................................................................................... 31 8.1.1 Installation des Java SE Development Kit ................................................................. 31 8.1.2 Installation des Sun Java Wireless Toolkit for CLDC ................................................. 31 8.1.3 Installation von Eclipse .............................................................................................. 31 8.1.4 Installation von EclipseME ......................................................................................... 31 8.1.5 EclipseME einrichten ................................................................................................. 31 8.1.6 Anlegen eines JavaME-Projekes in Eclipse .............................................................. 34 8.2 Erstellen einer Karte mit Tile Studio .................................................................................. 38 8.3 Beispielprogramme (Anwenderdokumentation) ................................................................. 45 8.3.1 JavaME_01_HelloWorld ............................................................................................ 45 8.3.2 Game_01_GameLoop ............................................................................................... 46 8.3.3 Game_02_WalkMario ................................................................................................ 47 8.3.4 Game_03_WalkMarioTiles ........................................................................................ 48 8.3.5 Game_04_WalkMarioTilesCollision ........................................................................... 49 8.3.6 Game_05_SuperMarioBros ....................................................................................... 50 8.4 Zeitaufwand ....................................................................................................................... 52 8.5 Inhalt der CD-Rom ............................................................................................................. 53 Christian Burmeister Anhang 3 1.Kurzzusammenfassung Wie bereits aus dem Titel dieser Ausarbeitung zu entnehmen ist, soll im Rahmen dieser Ausarbeitung auf M3G sowie auf die 2D-Spieleprogrammierung eingegangen werden. Dies kommt daher, weil zunächst das Thema M3G ausgearbeitet werden sollte, dann aber relativ schnell festgestellt wurde, dass Herr Werder [WERM3G] dieses Thema schon in aller Ausführlichkeit behandelt hatte. Daher wurde in Absprache mit Prof. Dr. Werner Heinzel beschlossen, dass diese Ausarbeitung schwerpunktmäßig das Thema 2D-Spieleprogrammierung behandelt, aber dennoch sehr kurz auf das Thema M3G eingegangen werden muss. Daher wird im Rahmen dieser Ausarbeitung zunächst auf das Thema JavaME eingegangen, welches für beide Themengebiete relevant ist, da beide JavaME voraussetzen. Dabei wird zunächst auf das modulare Konzept von JavaME eingegangen, welches sich aus Konfigurationen, Profilen und optionalen Paketen zusammensetzt. Danach werden die Grundlagen einer JavaMEAnwendung beschrieben, welche danach in einem praktischen Beispiel demonstriert werden sollen. Abschließend wird noch auf die notwendigen Entwicklungswerkzeuge für JavaME eingegangen. Nach diesem einführenden Teil wird kurz auf M3G eingegangen, danach beginnt der eigentliche Hauptteil dieser Ausarbeitung. In diesem Teil sollen die Grundlagen der 2D-Spieleprogrammierung vermittelt werden. Unter anderem wird beschrieben, wir man eine Spielfigur animieren und mithilfe der Tastatur über den Bildschirm bewegt kann. Anschließend wird auf das Erstellen, Scrollen und Zeichnen eines Levels eingegangen, in dem sich die zuvor erstellte Spielfigur bewegen kann. Abschließend soll noch auf das Thema Kollisionserkennung eingegangen werden. 2.Einleitung Anfang der 90er Jahre begann der Siegeszug des Mobiltelefons, oder ganz allgemein der mobilen Endgeräte. Zunächst waren die verfügbaren Endgeräte noch sehr groß, schwer und unhandlich, doch dies änderte sich im Zuge des technischen Fortschrittes recht schnell. Heutzutage sind mobile Endgeräte aus unserem Alltag kaum mehr wegzudenken. Dabei werden sie längst nicht mehr nur zum Telefonieren genutzt. Mobile Endgeräte stellen heute eher Multimediazentrale im Miniaturformat da, mit der es möglich ist Emails zu schreiben, im Internet zu surfen, Musikdateien abzuspielen, Termine zu verwalten und sogar Spiele zu spielen. Gerade der Spielebereich ist ein interessanter Markt, denn fast jeder Mensch in der westlichen Welt besitzt mindestens ein Mobiltelefon. Von diesen Verbreitungszahlen können Spielekonsolenhersteller zurzeit nur träumen. Daher wird es mit der zunehmenden Leistungsfähigkeit der mobilen Endgeräte immer interessanter für diesen Markt Spiele zu entwickeln. Momentan dominieren noch 2D-Spiele den Markt, doch mit zunehmender Rechenleistung werden sich wahrscheinlich 3D-Spiele immer weiter durchsetzen. Stellt sich nur die Frage, in welcher Programmiersprache man diese Spiele entwickeln soll? Dabei bietet sich Java an, da Java bereits im Desktop und Server-Bereich weiter Verbreitung befunden hat. Dabei muss aber auf eine spezielle Edition von Java zurückgegriffen werden, die sich JavaME nennt. JavaME ist dabei eine speziell für mobile Endgeräte angepasste Java Edition, die der beschränkten Leistungsfähigkeit der Endgeräte Rechnung trägt. Sie bietet dabei, genau wie die größeren Editionen vom Java, den Vorteil, dass sie nahezu Plattformunabhängig ist und damit die zu entwickelnde Anwendung auf allen JavaME unterstützten Plattformen lauffähig sind. Dies ist gerade im Bereich der mobilen Endgeräte sehr wichtig, da fast jeder Hersteller sein eigenes Betriebssystem verwendet. Eines dieser Betriebssysteme ist zum Beispiel Symbian OS der Firma Nokia. JavaME bietet dabei sowohl eine Unterstützung für 2D, wie auch für die 3DSpieleprogrammierung. Für die 3D Unterstützung wird aber eine Erweiterung namens „Mobile 3D Graphics“ (M3G) benötigt. Eigentlich sollte auf diese 3D-Erweiterng, im Rahmen dieser Ausarbeitung, eingegangen werden. Nach ersten Recherchen stellte sich aber heraus, dass bereits eine sehr ausführliche Ausarbeitung zu diesem Thema von Herrn Werder [WERM3G] existiert und so wurde in Absprache mit Herrn Prof. Dr. Werner Heinzel beschlossen, dass schwerpunktmäßig das Thema 2DSpieleprogrammierung bearbeitet wird. Christian Burmeister Anhang 4 3.Java für mobile Endgeräte Java erfreut sich in den letzten Jahren immer größerer Beliebtheit, mit der zunehmenden Leistungsfähigkeit von mobilen Endgeräten, wie etwa Mobiltelefone oder PDAs, wird auch der Einsatz der Java-Technologie auf diesen Geräten immer attraktiver. Dabei ist allerdings zu beachten, dass mobile Endgeräte eine Reihe von Einschränkungen gegenüber normalen DesktopSystemen besitzen. Die Speicherkapazität und Rechenleistung ist im Vergleich zu aktuellen Desktop-Systemen sehr gering. Die Ein- und Ausgabemöglichkeiten auf mobilen Endgeräten muss aufgrund von Platz-, Gewichts- und Energiespargründen eingeschränkt werden. Daher besitzen mobile Endgeräte meist nur kleine Displays und wenige Tasten zur Eingabe. Da mobile Endgeräte nur über einen Akku zur Energieversorgung verfügen, muss sehr sparsam mit der zur Verfügung stehenden Energie umgegangen werden. Aus den erwähnten Einschränkungen erscheint es nur konsequent, dass auf mobilen Endgeräten nicht die gleiche Java-Laufzeitumgebung wie auf Servern oder Desktops zum Einsatz kommt. Aus diesem Grunde existieren drei verschiedene Editionen von Java, die von der Firma Sun kostenlos zur Verfügung gestellt werden. Java Enterprise Edition (JavaEE) – für den Einsatz auf Serversystemen Java Standard Edition (JavaSE) – für den Einsatz auf Desktopsystemen Java Micro Edition (JavaME) – für den Einsatz auf ressourcenbeschränkten Geräten Die Java Micro Edition (JavaME) oder auch die früher Bezeichnung Java 2 Micro Edition (J2ME) ist eine Java-Edition, die speziell für die Anforderungen auf mobilen Endgeräten angepasst wurde. Dabei wurde besonderen Wert auf eine ressourcenschonende Implementierung gelegt. Wie man vielleicht vermuten könnte, stellt JavaME keine Teilmenge von JavaSE/JavaEE da. Es wurden zwar einige bekannte Klassen aus JavaSE übernommen, diese wurden aber an die speziellen Anforderungen mobiler Geräte angepasst. Weiterhin wurden zusätzliche Klassen hinzugefügt, die im Namensraum javax.microedition.* angesiedelt sind. 3.1Konfigurationen, Profile und optionale Pakete Die J2ME-Architektur basiert auf einem Konzept, das sich aus Konfiguration, Profil und optionalen Pakten zusammensetzt. In Abbildung 3.1 ist eine Übersicht über die einzelnen Module gegeben, auf die im Folgenden noch näher eingegangen werden soll. Christian Burmeister Anhang 5 Abbildung 3.1 Quelle: [SUN1] Der Grund für diese Aufspaltung, die nur in JavaME vorgenommen wird, ist, dass mobile Endgeräte, im Unterschied zu normalen Computern, sehr unterschiedliche Leistungsklassen besitzen. Zum einen sind es ganz einfache Mobiltelefone mit nur sehr wenigen Zusatzfunkionen und zum anderen die High-End PDAs, die leistungsfähige Mikroprozessoren und mehrere Gigabyte Speicher besitzen. Daher entschied man sich für ein modulares Konzept, da so die Softwarefähigkeiten der Java-API sehr gut an die Hardwarefähigkeiten des Gerätes angepasst werden können. 3.1.1Konfigurationen Die Konfiguration stellt sozusagen das Basismodul von JavaME dar. Es stellt zum einen die grundlegenden Java-Funktionalitäten zur Verfügung und zum andern die virtuelle Maschine, in der der Java-Code ausgeführt werden kann. Das darüber angesiedelte Profil und die optionalen Pakete setzen wiederum auf dieses Basismodul auf. Zurzeit unterscheidet man zwischen zwei Konfigurationen: CLDC und CDC. 3.1.1.1CLDC (Connected Limited Device Configuration) Wie das Wort „Limited“ im Namen schon andeutet, ist diese Konfiguration für Ressourcen beschränkte Endgeräte, wie z.B. Mobiltelefone und Einstiegs-PDAs, gedacht. Um der geringen Leistungsfähigkeit Rechnung zu tragen, wird die virtuelle Maschine in dieser Konfiguration auch „K(ilobyte) Virtual Machine“ (KVM) genannt. Wie man erahnen kann, ist diese stark eingeschränkt gegenüber der JVM in der JavaSE oder JavaEE Edition. Momentan existieren zwei Versionen der CLDC-Konfiguration, zum einen die CLDC 1.0 [JSR30] und zum andern die CLDC 1.1 [JSR139]. Der wohl größte Unterschied zwischen beiden Versionen ist die fehlende Fließkommaunterstützung (float, double) in der 1.0 Version.. 3.1.1.2CDC (Connected Device Configuration) Die CDC-Konfiguration ist im Gegensatz zur CLDC-Konfiguration für leistungsfähigere Endgeräte entwickelt worden, z.B. High-End PDAs und TV Set-Top-Boxen. Eine CDC-Implementierung unterstützte daher eine weitaus größere Menge der Klassenbibliothek der JavaSE Edition, daher erfordert die CDC auch eine nahezu vollwertige JVM. Zurzeit sind zwei Versionen verfügbar, sowohl Version 1.0 (JSR36) als auch Version 1.1.2 (JSR218). Da diese Konfiguration sehr selten auf den heutigen Mobiltelefonen zum Einsatz kommt, soll im Nachfolgenden nicht weiter auf diese Konfiguration eingegangen werden. In ein paar Jahren könnte dies aber schon ganz anders aussehen. 3.1.2Profile Die beschriebenen Konfigurationen werden mithilfe von Profilen erweitert. Dabei stellt das MIDP (Mobile Information Device Profile) eines der wichtigsten Profile da. Es setzt auf die CLDC- Christian Burmeister Anhang 6 Konfiguration auf und stellt zusammen mit dieser die Kernfunktionen für mobile Anwendungen, durch eine standardisierte Ablaufumgebung und Java APIs, zur Verfügung. Momentan existieren zwei Versionen von MIDP, zum einen die Version 1.0 [JSR37] und zum andern die Version 2.0 [JSR118], dabei kann die MIDP-Version unabhängig von der CLDC-Version verwendet werden. Das MIDP ist unter anderem für folgende Aufgagen zuständig: Benutzerschnittstelle, Ereignisverarbeitung, Management der Installation und Steuerung des Lebenszyklus von Anwendungen. Das MIDP gibt den sogenannten MIDlets auch ihren Namen, auf diese wird im Abschnitt 3.2 noch näher eingegangen. 3.1.3optionale Pakete Je nach Ausstattung des mobilen Endgerätes kann die bestehende Kombination aus Konfiguration und Profil noch durch optionale Pakete erweitert werden. Diese optionalen Pakete werden, genau wie auch alle anderen Module von einer JCP-Expertengruppe in einem JSP (Java Specificaton Request) spezifiziert. Eine kleine Auswahl dieser optionalen Pakete ist im Folgenden aufgelistet: Java APIs for Bluetooth (JSR82), Mobile Media API (JSR135), M3G (JSR184) Auf das optionale Paket „Mobile 3D Graphics“ (M3G) wird in Abschnitt 4 noch näher eingegangen. 3.2MIDlet-Grundlagen JavaME-Anwendungen, die für ein MIDP-Profil entwickelt werden, nennen sich MIDlets. Jedes Endgerät, auf dem ein MIDlet ausgeführt werden soll, benötigt eine Umgebung, die es erlaubt ein MIDlet zu starten, auszuführen und zu beenden. Diese Umgebung wird Application Management Software (AMS) genannt. Die AMS übernimmt dabei die komplette Ablaufsteuerung eines MIDlets. Deshalb verfügen MIDlets auch über keine Main-Methode, da es der AMS so nicht möglich wäre, in den Programmablauf einzugreifen. MIDlets werden daher über einen Zustandsautomaten gesteuert, der aus den drei Zuständen: active, paused, destroyed besteht. Im „active“-Zustand läuft das MIDlet aktiv im Vordergrund und kann auf die bereitgestellten Ressourcen zugreifen. Im „paused“-Zustand ist das MIDlet zwar initialisiert, aber es ist nicht möglich aktiv auf Ressourcen zuzugreifen, daher sollten diese ggf. vorher freigegeben werden. Wenn ein MIDlet beendet werden soll, wird es in den „destroyed“-Zustand versetzt. Im Folgenden ist der erwähnte Zustandsautomat abgebildet. Abbildung 3.2 Quelle: [KARBACHER] Über die abgebildeten Methoden (startApp(), destroyApp(), pauseApp()) steuert die AMS den Programmablauf des MIDlets. Die Methoden werden dabei jeweils vor einem Zustandsübergang aufgerufen. Um sicherzustellen, dass jedes MIDlet diese Methoden bereitstellt, muss jedes MIDlet von der abstrakten Klasse MIDlet (javax.microedition.midlet.MIDlet) abgeleitet werden. Christian Burmeister Anhang 7 Ein MIDlet kann durch die Methoden „notifyPaused()“ und „notifyDestroyed()“ auch von sich aus versuchen, dass die AMS ein Zustandsübergang durchführt. Die „notifyDestroyed()“-Methode ist dabei die einzige Möglichkeit für ein MIDlet sich ordnungsgemäß zu beenden. Durch diese zustandsbasierte Programmsteuerung ist es nun möglich auf asynchron auftretende Ereignisse z.B. ein Telefonanruf oder SMS zu reagieren, da die AMS die Kontrolle über den Programmablauf eines MIDlets besitzt. 3.3Erste Schritte mit Java ME Da wir nun die Grundlagen eines MIDlets kennengelernt haben, soll nun beschrieben werden wie man ein einfaches MIDlet erstellt. Am besten für solche Zwecke eignet sich ein klassisches „Hello World“-Programm. Um dies zu realisieren, wurden die beiden Klassen „MyMIDlet“ und „MyCanvas“ erstellt, die in Quelltext 3.1 bzw. Quelltext 3.2 abgebildet sind. Wie man in der Abbildung 3.1 erkennen kann, wurde die Klasse „MyMIDlet“ von der Klasse „MIDlet“ abgeleitet, dadurch mussten auch die drei bereits erwähnten Methoden (startApp(), destroyApp(), pauseApp()) implementiert werden. Für unser kleines Beispiel ist dabei nur die Methode „startApp()“ von Interesse. In dieser Methode wird in Zeile 3 die Referenz auf das Handydisplay gespeichert, dies geschieht durch den Aufruf der statischen Methode „getDisplay()“ der Display-Klasse. In Zeile 4 wird eine Leinwand erstellt, dem Konstruktor wird dabei eine Referenz auf das MIDlet übergeben, damit die Anwendung später ordnungsgemäß beendet werden kann. Um die Leinwand nun auf dem Display anzuzeigen, muss es der Methode „setCurrent()“, des Display-Objektes, übergeben werden. Quelltext 3.1 (Programm: „JavaME_01_HelloWorld“) Wie man erkennen kann, dient die Klasse „MyMIDlet“ nur dazu, eine Leinwand-Objekt auf dem Display anzuzeigen. Das eigentliche Zeichnen auf die Leinwand findet dagegen in der Klasse „MyCanvas“ statt. Christian Burmeister Anhang 8 Quelltext 3.2 (Programm: JavaME_01_HelloWorld) Die Klasse „MyCanvas“ ist ebenfalls von einer abstrakten Klasse abgeleitet, in diesem Fall aber von „Canvas“. Daher muss die Methode „paint()“ implementiert werden (Zeile 7 – 10), die für das Zeichen unseres „Hello World“ Textes verantwortlich ist. Durch den Methodenaufruf „setCurrent()“ in Quelltext 3.1, Zeile 4 wird einmalig die paint-Methode aufgerufen und ein Graphics-Objekt übergeben, dieses Objekt stellt Methoden bereit um auf die Leinwand zu zeichnen. Durch die Methode „drawString()“, des Graphics-Objektes, wird nun der String „Hello World!“ auf das Display gezeichnet, der 2. und 3. Parameter geben dabei die X und Y-Koordinate ausgehend von der oberen linken Ecke (4. Parameter) an. Die Koordinaten werden jeweils in Pixeln angegeben. Über die beiden Methoden „getWidth()“ und „getHeight()“ kann die jeweilige Pixelgröße der Leinwand abgefragt werden, dabei ist diese jeweils abhängig vom eingesetzten Endgerät. Um die größtmögliche Zeichenfläche zu erlangen, wurde im Konstruktor der MyCanvas-Klasse die Methode „setFullScreenMode()“ aufgerufen, dadurch verschwindet der am unteren Displayrand befindliche Softkey-Balken. Um das MIDlet ordnungsgemäß beenden zu können, wird im Konstruktor eine Referenz auf das MIDlet gespeichert (Zeile 4). In Zeile 11 – 14 wird überprüft, ob die *-Taste gedrückt wurde. Wenn dies der Fall ist, wird die Methode „motifyDestroyed()“ des MIDlet-Objektes aufgerufen, und damit das MIDlet beendet. 3.4Entwicklungswerkzeuge Im Gegensatz zu JavaEE und JavaSE Programmen können JavaME Programme nicht direkt auf dem Gerät entwickelt werden, auf dem sie später ausgeführt werden sollen. Aus diesem Grund benötigt man zusätzlich zur eigentlichen Entwicklungsumgebung auch einen Emulator, der die KVM des mobilen Endgerätes auf dem Entwicklungs-Computer emuliert. Somit findet die komplette Entwicklung auf dem Entwicklungs-Computer statt, und erst nach der Fertigstellung wird das JavaME-Programm auf das mobile Endgerät übertragen. Um nun ein JavaME-Programm zu entwickeln, werden eigentlich nur 3 Komponenten benötigt. - Java SE Development Kit (JDK) [SUNJDK] - Sun Java Wireless Toolkit for CLDC (WTK) [SUNWTK] - Einfacher Texteditor Das JDK legt den Grundbaustein für die Java-Programmierung, dabei enthält es noch keine JavaME spezifischen Komponenten. Erst mit der Installation des WTK werden die zusätzlichen Klassen für JavaME (javax.microedition.*) installiert. Das WTK stellt aber nicht nur eine einfache Erweiterung für JavaME-Klassen dar, es ist vielmehr eine komplette Entwicklungsumgebung. Es beinhaltet sowohl die erwähnten Emulatoren und auch eine einfache grafische Oberfläche zum Christian Burmeister Anhang 9 Erstellen von JavaME-Programmen. Der Nachteil des WTKs ist, dass es keine vollwertige integrierte Entwicklungsumgebung (IDE) ist, denn es enthält weder einen Texteditor, noch eine Möglichkeit Quellcode zu debuggen. Es ist natürlich möglich einen einfachen Texteditor zu verwenden, doch dies ist meist wenig komfortabel. Daher bieten die meisten IDEs Erweiterungen an, um das WTK innerhalb der IDE verwenden zu können. Im Folgenden sind zwei IDEs mit den erforderlichen Erweiterungen aufgelistet. - Eclipse [ECLIPSE] o - Erweiterung für WTK: EclipseME [ECLIPSEME] Netbeans [NETBEANS] o Erweiterung für WTK: Mobility Packs (in „Java“ Edition von Netbeans enthalten) Der Einsatz einer solchen IDE bietet gegenüber der Verwendung des reinen WTK natürlich erhebliche Vorteile, da es viele Hilfestellungen bei der Entwicklung und Fehlersuche bietet. Aus diesem Grunde empfiehlt es sich fast immer eine solche IDE einzusetzen. Im Anhang 8.1 wird daher anhand des Beispielprogramms „HelloWorld“ gezeigt, wie man Eclipse, unter Verwendung der Erweiterung EclipseME, mit dem WTK verwenden kann. Außer der Firma Sun bieten aber noch einige andere Hersteller Software Development Kit (SDK) für JavaME an. Zu ihnen zähnen meist Firmen, die selbst JavaME fähige Mobiltelefone herstellen. Als Beispiel sei hier die Firma Nokia genannt, die unter der Webadresse [NOKIASDK] ihr eigenes SKD kostenlos zur Verfügung stellt. In diesem SKD sind wie beim WTK zum einen die Emulatoren enthalten und zum andern die Erweiterungen für JavaME, die aber auch Hersteller spezifische Erweiterungen enthalten. Christian Burmeister Anhang 10 3.5Installation auf mobilem Endgerät Nachdem man ein JavaME-Programm erstellt hat, stellt sich bald die Frage, wie man das Programm auf dem mobilen Endgerät installiert. Die Installation unterscheidet sich etwas zu konventionellen Installationen, denn bei JavaMEProgrammen wird die eigentliche Installationsdatei auf zwei Dateien aufgesplittet. Zum einen in eine JAD-Datei (Java Application Descriptor) und zum anderen in eine JAR-Datei (Java Archive). Die JAD-Datei teilt dabei dem Mobiltelefon Vorabinformationen über das zu installierende Programm mit. In der JAR-Datei befindet sich das eigentliche Programm. Doch warum diese Aufsplittung? Dies liegt daran, das JavaME-Programme meist über die Luftschnittstelle („Over the Air“) installiert werden. Da über diesen Wege die Übertragung von Daten meist relativ teuer und langsam ist, wird zunächst nur eine einfach Textdatei übermittelt (JAD-Datei) in der Programminformationen gespeichert sind. Dies ermöglicht es dem Mobiltelefon vorab festzustellen, ob es über die geforderten Anforderungen verfügt, wie z.B. genügend Speicherplatz, Unterstützung für Konfiguration und Profil der Anwendung. In der nachfolgenden Abbildung ist die JAD-Datei des HelloWorld-Programms abgebildet. Quelltext 3.3 (JAD-Datei des HelloWorld-Programms) Wie man erkennen kann, ist in Zeile 2 die Größe des Programms angegeben und in Zeile 7 und 8 die erforderliche Konfiguration und das Profil. Um nun ein JavaME Programm zu installieren, benötigt man zunächst die JAD-Datei. Das Mobiltelefon überprüft dann zuerst die Angaben und installiert, wenn alle Bedingungen erfüllt sind, die unter Zeile 3 angegebene JAR-Datei. So muss die JAR-Datei nur übertragen werden, wenn sie auch wirklich auf dem Mobiltelefon ausgeführt werden kann. Um ein Programm ohne Luftschnittstelle installieren zu können, benötigt das Mobiltelefon eine Datenschnittstelle z.B. Bluetooth oder eine Anschlussmöglichkeit für ein Datenkabel. Für die meisten Mobiltelefone stellen die Hersteller auf ihren Webseiten entsprechende Programme bereit, die es erlauben auf den internen Speicher zuzugreifen. Damit ist es dann sehr einfach und sogar kostenlos möglich JavaME-Programme zu installiere. Dazu kopiert man einfach die erstellten JAD und JAR-Dateien auf das Mobiltelefon und installiert sie. Wie man die Anwendung installieren kann, hängt dabei vom jeweiligen mobilen Endgerät ab. Wie man an die beiden Dateien gelangt, hängt jeweils von der eingesetzen Entwicklungsumgebung ab. Im Falle von Eclipse werden sie bereits automatisch erstellt, da der Emulator mit genau diesen beiden Dateien gestartet wird. Um an die beiden Dateien zu gelangen, muss man, nachdem man ein JavaME-Projekt erstellt und das Programm mindestens einmal im Emulator ausgeführt hat, in das Projektverzeichnis wechseln, welches sich im Eclipse-WorkspaceOrdner befindet. Die beiden Dateien befinden sind nun im Unterordner „.eclipseme.tmp\emulation“. Christian Burmeister Anhang 11 4. Mobile 3D Graphics API (M3G) Wie bereits im Abschnitt 3.1.3 erwähnt, stellt M3G ein optionales Paket für JavaME dar. Wie alle optimalen Pakete setzt es auf die vorhandene Kombination aus Konfiguration (CLDC) und Profil (MIDP) auf und erweitert dadurch die vorhandene API um zusätzliche Funktionalitäten. Im Fall von M3G sind dies 3D Funktionen, die im Namensraum „javax.microedition.m3g“ untergebracht sind. Um M3G nutzen zu können, ist mindestens die Konfiguration CLDC 1.1 benötigt, da erst ab dieser Version die Fließkommaunterstützung implementiert wurde. M3G wurde von einem unabhängigen Komitee in einem „Java Community Process“ entwickelt und standardisiert. Zu diesem Komitee gehörten insgesamt 26 Mitglieder, zu denen unter anderm Sun Microsystems, Sony Ericsson, Symbian, Motorola, ARM, Cingular Wireless und Nokia gehörten [SUNM3G]. Die Ergebnisse dieses Prozesses wurden in [JSR184] festgehalten und beschreibt die Version 1.0 und 1.1 von M3G. Zurzeit ist Version 2.0 in Entwicklung und wird unter dem Namen [JSR297] standardisiert werden. Bei der Entwicklung des JSR184 Standards wurden vom Standardisierungskomitee einige Anforderungen festgelegt, die die API erfüllen sollte [SUNM3G]. Die API soll zwei Modi unterstützen, den „retained-mode“ (high-level Schnittstelle mit Scene-Graphen) und den „immediat-mode“ (low-level Schnittstelle, die ähnlich oder gleich der von OpenGL ES sein sollte). Dabei sollte es möglich sie, die Modi einzeln, wie auch in Kombination nutzen zu können. Die API darf keine optionalen Teile enthalten; alle Methoden müssen implementiert werden. Um die Programmierarbeit zu reduzieren, benötigt die API Importer für Schlüsseldatentypen, wie Meshes, Texturen und Scene-Graphen. (M3G-Dateiformat) Die Daten müssen für eine kompakte Speicherung und Übertragung in einem Binärformat codiert werden. Es muss möglich sein, auch ohne Hardwareunterstützung für Fließkommaberechnungen, effizient auf OpenGL ES aufzusetzen. Die API muss den Fließkomma-Datentyp von Java benutzen und soll keinen eigenen Datentyp dafür einführen. Weil der Einsatz von Integer-Arithmetik schwierig und fehleranfällig ist, sollen FließkommaWerte überall dort eingesetzt werden, wo es möglich ist. Der benötige Rom und Ram sollte sehr gering sein; die API sollte mit lediglich 150KB auf einem Gerät implementierbar sein. Die API soll eine minimale „garbage collection“ zur Verfügung stellen. Die API muss korrekt mit andern Java APIs interagieren, speziell MIDP. Im Folgenden soll noch kurz auf die beiden erwähnten Modi, „immediate mode“ und „retained mode“, eingegangen werden. Christian Burmeister Anhang 12 4.1.1Immediate Mode Der „immediate mode“ stellt „low-level“ 3D-Funktionalitäten für JavaME zur Verfügung, dabei baut es weitgehend auf dem 3D-Standard OpenGL-ES der Firma Khronos auf. OpenGL-ES (OpenGL for Embedded Systems) ist eine Teilmenge von OpenGL die speziell an die Bedürfnisse von ressourcenschwachen Geräten angepasst wurde. Der Modus wird deshalb „immediate“ (deut. direkt, umgehend) genannt, weil alle Objekte direkt gerendert und danach gezeichnet werden. Dadurch ist der Programmierer zwar in der Lage auf alle Teile seiner Anwendung direkten Einfluss zu nehmen, wie z. B. die Erzeugung von Objekten, setzen des Lichtes, ändern der Kameraposition und das rendern einzelner Objekte, aber dies ist meist mit sehr viel Arbeit verbunden, da man jeden Schritt detailliert festlegen muss. Ein sehr schönes Tutorial zum „immediate mode“ lässt sich unter [IBMM3G] finden. 4.1.2Retained Mode Der „retained mode“, stellt dagegen „high-level“ 3D-Funktionalitäten zur Verfügung. Der Vorteil dieses Modus ist der, dass Objekte nicht direkt gerendet und gezeichnet werden müssen, sondern die Objekte zunächst in einer Datenstruktur, dem sogenannten „Scene Graph“, abgespeichert werden. Daher stammt auch der Name „retainted“ (deut. zurückbehalten) dieses Modus. Die Datenstruktur ist dabei in Art eines Baumes aufgebaut, wobei jedes 3D-Objekt ein Knoten darstellt. Die Wurzel dieses Baumes bildet die Klasse „World“, unterhalb der Wurzel werden dann Kamera, Licht und andere 3D-Objekte platziert. In Abbildung 4.1 ist ein Beispiel dieser Baumstruktur zu sehen. Abbildung 4.3 Quelle: [IBMM3G] Ein weiter Vorteil dieser Baumstruktur ist, dass man Objekte gruppieren kann und sie dadurch gemeinsam ansprechbar sind. In der Abbildung 4.1 ist dies am Beispiel von acht Würfeln demonstriert. Durch Ansprechen der Gruppe 1 können alle acht Würfel gemeinsam rotiert werden, durch Ansprechen der Gruppen 2 und 3 können dagegen je vier Würfel getrennt voneinander angesprochen werden, im Beispiel ist dies anhand einer Skalierung demonstriert. Um alle 3DObjekte zu rendern und zu zeichnen muss lediglich die Wurzel des „Scene Graph“, also die Klasse „World“, übergeben werden, den Rest der Arbeit übernimmt M3G. Eine ausführliche Beschreibung des Beispiels ist unter [IBMM3G] zu finden. Ein weiterer Vorteil, den der „retainted mode“ bietet, ist die Unterstützung für ein eingenes Dateiformat zum Importieren von 3D-Objekten. Dies bietet die Möglichkeit komplexe Scenen mit einem 3D-Werkzeug, wie z. B. Lightwave oder Maya, zu erstellen und dann in M3G zu importieren. Als Dateierweiterung kommt dabei „.m3g“ zum Einsatz. Um die erstellte 3D-Scene mit M3G anzeigen zu können, muss sie lediglich mit der „Loader“-Klasse geladen werden. Nach diesem kleinen Ausflug in die 3D-Welt soll sich nun mit der Spieleprogrammierung in der 2DWelt beschäftigt werden. Christian Burmeister Anhang 13 5.2D Spieleprogrammierung Dieser Abschnitt beschäftigt sich nun mit der Entwicklung von einfachen 2D-Spielen. Im Abschnitt 5.1 soll zunächst anhand der Programme „Game_01_GameLoop“, „Game_02_WalkMario“, „Game_03_WalkMarioTiles“ und „Game_04_WalkMarioTilesCollision“ schrittweise gezeigt werden, wie man einfache 2D-Spiele selbst entwickeln kann. Im Abschnitt 5.2 soll danach das Programm „Game_05_SuperMarioBros“ kurz vorgestellt werden, welches die zuvor gezeigten Techniken innerhalb eines komplexeren Spieles umsetzt, aus Platzgründen kann dieses Programm aber leider nicht ausführlich beschreiben werden. Eine kurze Anwenderbeschreibung der erwähnten Programme ist auch im Abschnitt 8.3 zu finden. Es sei noch erwähnt, dass die grundlegenden Ideen für die Algorithmen aus dem Buch „Mobile Games“ von Thomas Lucka [LU08MGAME] übernommen wurden. 5.1Einführung in die Spieleprogrammierung In den folgenden acht Abschnitten sollen nun schrittweise die Grundlagen der 2DSpieleprogrammierung erläutert werden. Begonnen wird dabei in Abschnitt 5.1.1 mit dem Grundgerüst eines 2D-Spieles, danach wird in Abschnitt 5.1.2 und 5.1.3 beschrieben wie man eine animierte Spielfigur, mithilfe der Tastatur, über den Bildschirm bewegen kann. Danach wird in den Abschnitten 5.1.4, 5.1.5 und 5.1.6 erläutert, wie man ein Level erstellen, scrollen und zeichnen kann. In den beiden letzen Abschnitten soll dann noch kurz auf die Kollisionserkennung eingegangen werden. 5.1.1 Grundgerüst mit Spielschleife Um ein 2D-Spiel für JavaME zu entwickeln, benötigt man, wie bei allen JavaME-Programmen, eine Klasse die von MIDlet abgeleitet ist. In Abschnitt 3.3 wurde bereits der Aufbau einer solchen Klasse am Beispiel der MyMIDlet-Klasse beschrieben, daher soll diese Klasse hier übernommen werden und als Ausgangsbasis für unser Spiel dienen. Um kenntlich zu machen, dass es sich bei unser Leinwand-Klasse um eine Spieleleinwand handelt, soll die Klasse MyCanvas aber in GameCanvas umbenannt werden. Die neue Klasse GameCanvas wird dabei ebenfalls von der abstrakten Klasse Canvas abgeleitet, und muss dadurch ebenfalls die Methode „paint(Graphics g)“ implementieren. Wie bereits beim „Hello World“-Programm erwähnt, wird diese paint-Methode aber nur ein einziges Mal aufgerufen. Dies ist für Spiele nicht besonders zweckmäßig, da ähnlich wie bei einem Film, die Bewegung durch die schnelle Abfolge von Einzelbildern (Frames) erzeugt wird. Daher muss zunächst eine Schleife entwickelt werden, die es ermöglicht die paint-Methode öfter aufzurufen. Diese Schleife wird meistens Game Loop oder Spielschleife genannt, da sie ein zentraler Bestandteil des Spieles ist. Um den Eindruck einer flüssigen Bewegung zu erreichen, sollte die Spielschleife ca. 25 – 30 mal pro Sekunde die paint-Methode aufrufen. Wenn die Anzahl der Aufrufe von diesem Wert abweicht, wird das Spiel entsprechend langsamer oder schneller. In Quelltext 5.1 ist ein Beispiel für eine solche Spielschleife gegeben. Um zu gewährleisten, dass keine ungewollten Verzögerungen durch andere Methoden entstehen, wird die Spielschleife in einem eigenen Thread realisiert. Dazu muss unsere Leinwand-Klasse das Interface „Runnable“ implementieren, welches die Implementierung der „run()“ Methode erzwingt. Da nur ein ThreadObjekt als Thread laufen kann, wird in Zeile 5 ein neues Objekt dieser Klasse erzeugt, als Parameter für den Konstruktor wird unser GameCanvas-Objekt übergeben. Durch den Aufruf der start-Methode wird nun die implementierte run-Methode durch den erzeugten Thread aufgerufen. In der run-Methode befindet sich nun die erwähnt Schleife (Zeile 10 – 19). Um zu gewährleisten, dass die paint-Methode nur höchstens 30-mal pro Sekunde aufgerufen wird, wird am Anfang der Schleife (Zeile 11) die aktuelle Zeit gespeichert und am Ende der Schleife (Zeile 15) wird die benötigte Ausführungszeit ermittelt. In Zeile 16 wird überprüft, ob die Ausführungszeit schneller als die vorgegebene Ausführungszeit ist, wenn dies der Fall ist, wartet der Thread bis zum Erreichen der vorgegebenen Ausführungszeit. Die Ausführungszeit kann dabei indirekt über die Konstante „MAX_FRAMES_PER_SECOND“ vorgegeben werden, wobei der Thread sich in Zeile 8 aus dieser Konstante die maximale Ausführungszeit pro Frame errechnet z. B. 1000 / 30 Frames per Secund = 33,3 ms. Innerhalb der eigentlichen Schleife (Zeile 12 – 14) werden nun 3 Methoden aufgerufen. Christian Burmeister Anhang 14 Die erste Methode ist die repaint-Methode, die intern wiederum die paint-Methode mit einem neuen Graphics-Objekt aufruft. Dabei kommt ein sogenannter "Double Buffer" zum Einsatz, welcher verhindern soll, dass der Bildschirm anfängt zu flackern. Die serviceRepaints-Methode sorgt dafür, dass die repaint-Methode auch wirklich sofort ausgeführt wird. Die letzte der drei Methoden „Thread.yield()“ sorgt dafür, dass kurzzeitig ander Threads ausgeführt werden dürfen, die sonst vielleicht nicht zum Zuge kommen würden. Quelltext 5.4 (Programm: Game_01_GameLoop) Mit dieser Spielschleife ist nun sichergestellt, dass die paint-Methode höchstens 30 mal pro Sekunde aufgerufen wird. Zu beachten ist aber, dass die Leistungsfähigkeit einiger Endgeräte nicht ausreichen könnte, um die paint-Methode 30 mal pro Sekunde aufrufen. Innerhalb der paint-Methode muss jetzt aber zuerst die alte Leinwand „übermalt“ werden, bevor neue Elemente gezeichnet werden können. Dies wird mittels der clearDisplay-Methode realisiert die aus Platzgründen hier nicht abgebildet wurde. Innerhalb dieser Methode wird einfach ein gefülltes Rechteck (fillRect()) über die komplette Leinwand gezeichnet Der komplette Quelltext, zu diesem und allen folgenden Beispiel, ist jeweils auf der beiliegenden CD unter „Beispiele/Game_<PROGRAMM>/src“ zu finden. 5.1.2Animation Im Folgenden soll nun schrittweise am Beispiel des Programms „Game_02_WalkMario“ gezeigt werden, wie man eine animierte Spielfigur mithilfe der Tastatur über den Bildschirm bewegen kann. In diesem Abschnitt soll zunächst auf die Animation der Spielfigur eingegangen werden, im Abschnitt 5.1.3 wird dann auf die Steuerung per Tastatur eingegangen. Bei den meisten 2D-Spielen sind die Spielfiguren (sog. Sprites) nicht statisch, sondern verändern ihr Haltung in Abhängigkeit von der momentanen Bewegungsrichtung, z. B. wenn eine Figur nach links geht, schaut sie auch in diese Richtung und bewegt die Beine dabei entsprechend. Um diesen Effekt in 2D-Spielen nachzuahmen, könnte man jeden einzelnen Frame in Echtzeit rendern lassen, dies ist aber meist aufgrund der geringen Rechenleistung der Endgeräte nicht Christian Burmeister Anhang 15 wünschenswert. Deshalb werden im Vorhinein mehrere Frames erstellt, die die Spielfigur in unterschiedlichen Haltungen darstellen. Um den Eindruck einer flüssigen Bewegung zu erreichen, werden für eine Bewegungsrichtung meist mehre Frames erstellt, die dann schnell hintereinander eingeblendet werden. Im der nachfolgenden Abbildung ist ein Beispiel für die Spielfigur „Mario“ gegeben. Die Abbildung besteht dabei aus 20 Frames, die jeweils eine Größe von 16 x 32 Pixel besitzen. Abbildung 5.4 Quelle: [MARIOSP] (Programm: Game_02_WalkMario) Wie man in der Abbildung erkennen kann, werden mit den 20 Frames insgesamt vier Bewegungsrichtungen realisiert. Es werden also immer 5 Frames zu einer Gruppe zusammengefasst. Daher lassen sich die folgenden Gruppen von links nach rechts identifizieren: RECHTS, OBEN, UNTEN und LINKS. Alle 20 Frames werden dabei in einer einzelnen PNG-Datei gespeichert, dies spart nicht nur Platz (nur ein Datei-Header), sonder auch Zeit beim Laden der Grafiken. PNG-Dateien werden bei der Spieleprogrammierung bevorzugt eingesetzt, da sie nicht nur auf fast allen mobilen Endgeräten unterstützt werden, sonder auch die Möglichkeit bieten Pixel transparent darzustellen. Die Transparenz wird dabei über den sogenannten Alphakanal realisiert, der zusätzlich zu den drei anderen Farbkanälen (rot, grün, blau) gespeichert wird. Da Grafiken immer rechteckig sind, ist es nun möglich, den umgebenden Bereich, der nicht zum Sprite gehört, mit dem maximalen Alphawert zu belegen, und dadurch mittels des Alpha Blendings den Hintergrund durchscheinen zu lassen. Dieser Effekt wird auch bei der „Mario“-Spielfigur verwendet. Nach diesem kleinen Abschweif, wollen wir uns damit beschäftigen, wie wir diese 20 Frames passend zu der aktuellen Bewegungsrichtung anzeigen lassen können. Ziel soll es dabei sein, dass z. B. wenn die Spielfigur nach oben geht, die Gruppe „OBEN“ ausgewählt wird und bei jedem Aufruf der paint-Methode ein Frame aus der Gruppe ausgewählt und gezeichnet wird. Um dieses Ziel zu erreichen, benötigen wir eine Technik, mit der es uns mögliche ist einen einzelnen Frame aus dem Bildstreifen auf die Leinwand zu zeichnen. Die Technik um dieses zu erreichen nennt sich Clipping. Das Graphics-Objekt welches der paint-Methode übergeben wird, stellt dazu die Methode „setClip (int x, int y, int width, int height)“ zu Verfügung. Durch den Aufruf dieser Methode wird festgelegt, in welchem Bereich gezeichnet werden darf. Die folgende Abbildung soll dies veranschaulichen. Abbildung 5.5 Die ersten beiden Parameter der setClip-Methode legen die X und Y-Position (xc,yc) des ClippingBereiches fest, die beiden Letzten legen die Breite und Höhe fest. In unserm Fall stellt der Punkt (xc,yc) die Position da, an der die Spielfigur gezeichnet werden soll. Die Breite und Höhe des Clipping-Bereiches ergibt sich aus den Abmessungen der Spielfigur (16 x 32 Pixel), daher würde Christian Burmeister Anhang 16 der Methodenaufruf in etwa wie folgt lauten „g.setClip(marioX,marioY,16,32);“. Damit haben wir nun festgelegt, dass nur im Clipping-Bereich (in Abbildung 5.2 weiß dargestellt) gezeichnet werden darf. Um die Figur nun zu zeichnen, wird der Bildstreifen so verschoben, dass der entsprechende Frame sich genau über dem Clipping Bereich befindet. Die Y- Koordinate (y‘) des Bildstreifens bleibt dabei unverändert, die X- Koordinate (x‘) wird nach der folgenden Formel errechnet: xc -(FrameNummer * FrameBreite). In unserem Beispiel wäre dies „marioX - (7 * 16)“. Nach dem Zeichen muss der Clipping-Bereich natürlich wieder zurückgesetzt werden, indem die komplette Leinwand als Clipping-Bereich definiert wird, also xc = x0 = 0, yc = y0 = 0 und die Länge und Breite der Leinwand. Im Quelltext 5.2 ist die Methode abgebildet, die die beschriebenen Aktionen durchführt. Zeile 3 definiert dabei zuerst den Clipping-Bereich an der die Spielfigur gezeichnet werden soll, danach wird das Bild in Zeile 4 versetzt gezeichnet und zum Schluss wird der Clipping-Bereich in Zeile 5 wieder zurückgesetzt. Quelltext 5.5 (Programm: Game_02_WalkMario) Den ersten Teil unseres Ziels haben wir bereits erreicht, wir wissen, wie man einen einzelnen Frame auf der Leinwand zeichnet. Der zweite Teil unseres Zieles besteht darin eine Methode zu entwickeln, die in Abhängigkeit von der momentanen Bewegungsrichtung, eine passende Framenummer zurückliefert, die dann der drawFrame-Methode übergeben werden kann. Wenn wir beim Beispiel bleiben, dass unser Mario nach oben geht, dann wäre es wünschenswert, wenn wir die Framenummernfolge von 5,6,7,8,9,5,6,7,8,9,5,6,7,8,9,usw. erzeugen könnten, um den Eindruck einer Gehbewegung zu erzielen. Es ist aber nicht ratsam die Framenummer mit jedem Aufruf der paint-Methode hochzuzählen, da so unsere Spielfigur 30 Schritte pro Sekunde zurücklegen würde. Deshalb müssen wir eine kleine Verzögerung einbauen, die es ermöglicht z. B. nur alle drei Aufrufe weiterzuschalten. Ein Beispiel für die Framenummernfolge wäre etwa 5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,5,5,5,usw. Um dies zu erreichen wurde die Methode „getFrame()“ entwickelt die in Quelltext 5.3 Zeile 1 – 9 abgebildet ist. Quelltext 5.6 (Programm: Game_02_WalkMario) Mit dem Parameter „frame“ wir die Framenummer der Spielfigur übergeben, mit der zuletzt gezeichnet wurde. Mit „min“ und „max“ legt man den minimalen und maximalen Frame der Gruppe fest und „step“ legt fest wie oft der aktuelle Frame wiederholt werden soll bis eine Umschaltung auf den nächsten Frame erfolgt. In Zeile 3 wird zuerst überprüft, ob der aktuelle Frame sich innerhalb der ausgewählten Gruppe befindet, wenn nicht wird der Frame auf den kleinsten Frame der Gruppe gesetzt. In Zeile 4 wird mithilfe des Modulo-Operators die Verzögerung erzeugt, Christian Burmeister Anhang 17 „timerFrame“ ist dabei eine einfache Zählvariable, die mit jedem „increaseFrameTimer() „Aufruf inkrementiert wird (Zeile 10 - 14). Die Auslagerung der Inkrementierung ist nötig, da in einem Spiel meist mehrere Figuren innerhalb eines paint-Methode-Zykluses bewegt werden müssen. Der Ausdruck „timerFrame % step == 0“ wird damit z.B. nur alle 3 paint-Zyklen zu „true“ ausgewertet (wenn step = 3) und inkrementiert damit die Framenummer (Zeile 5). In Zeile 6 wird noch überprüft, ob der maximale Frame der Gruppe überschritten wurde , wenn dies der Fall ist, wird wieder auf den minimalen Frame der Gruppe gewechselt. Zurückgegeben wird die Framenummer, die als nächstes gezeichnet werden soll. Bei unserm Beispiel, würde der Aufruf dann wie folgt lauten: getFrame(X, 5, 9, 3), „X“ ist dabei der Frame der zuletzt gezeichnet wurde. Um unser Spielfigur zu animieren müssen die drei Methoden noch an der richtigen Stelle im Quelltext platziert werden. In Quelltext 5.4 ist ein Ausschnitt aus dem Programm „Game_02_WalkMario“ gegeben, anhand dem man erkennen kann, wie die einzelnen Aufrufe platziert werden müssen. Quelltext 5.4 (Programm: Game_02_WalkMario) In der paint-Methode wird zunächst in Zeile 7 der FrameTimer mit der Methode „increaseFrameTimer()“ erhöht, danach wird die Leinwand geleert. In Zeile 8 wird die Spielfigur zuerst mittels der moveFigur-Methode bewegt und anschließend mit der drawFigur-Methode gezeichnet. In der moveFigure-Methode (Zeile 11 – 21) wird die Spielfigur bewegt. Dies geschieht anhand der boolschen-Variablen „down“, „up“ , „left“ und „right“, wobei die beiden letzteren in Quelltext 5.4 aus Platzgründen weggelassen wurden. Die Variablen können entweder durch eine Tasteneingabe gesetzt werden (Abschnitt 5.1.3) oder auch durch ein passenden Algorithmus. Wenn z. B. die Variable „up“ den Wert „true“ besitzt, bewegt die Spielfigur sich nach oben. Um dies zu erreichen, wird zunächst in Zeile 17 die Y-Position entsprechend der Geschwindigkeit der Spielfigur verringert und in Zeile 18, mit der bereits besprochenen getFrame-Methode, ein passender Frame aus der Gruppe „OBEN“ (min = 5, max = 9) der Variable „figureFrame“ zugewiesen. Beim Setzen der andern boolschen-Variablen läuft dies vergleichbar ab. Zu beachten ist, dass je nur eine der Variablen auf „true“ gesetzt sein sollte. In der drawFigure-Methode wird die Spielfigur nun auf die Leinwand gezeichnet. Christian Burmeister Anhang 18 Hierbei kommt die bereits besprochene Methode „drawFrame()“ zum Einsatz, die die zuvor zugewiesene Framenummer (figureFrame) an die Position (figureX, figureY) zeichnet. In unserm Beispiel ist die Bewegungsart noch relativ einfach, da die X und Y-Positionen nur entsprechend der Geschwindigkeit der Spielfigur geändert wird. In manchen Spielen ist es aber nötig, dass die Spielfigur springt und fällt. Um dies zu realisieren, bedarf es etwas mehr Aufwand. Aus Platzgründen soll hier auf eine Erläuterung verzichtet werden, wer aber dennoch Interesse hat, kann im Beispielprogramm „Game_05_SuperMarioBros“ (Klasse Mario, Methode „move()“) nachsehen. 5.1.3Tastensteuerung Die Behandlung von Benutzerinteraktionen ist ein sehr wichtiges Thema bei der Spieleprogrammierung, da fast jedes Spiel auf Interaktionen des Spielers reagieren soll. Dabei beschränken sich die Benutzerinteraktionen, bei Mobiltelefonen, meist auf die Zifferntasten, Funktionstasten und ein Steuerkreuz mit Auswahltaste. Um innerhalb unseres Spieles abzufragen, ob eine Taste gedrückt oder losgelassen wurde, stellt die Klasse „Canvas“ zwei Methoden bereit. Die erste der beiden Methode heißt „keyPressed(int key)“, sie wird jedes mal aufgerufen, sobald eine Taste gedrückt wird, die gedrückte Taste wird dabei als Parameter (key) übergeben. Die zweite Methode heißt „keyReleased(int key)“ und wird aufgerufen, sobald eine Taste wieder losgelassen wird. Die Auswertung des key-Parameters ist leider nicht einheitlich umgesetzt. Um zum Beispiel die Zifferntasten auszuwerten, stellt die Canvas-Klasse mehrere Klassenvariablen zur Verfügung, die direkt mit dem key-Paramter verglichen werden müssen. KEY_NUM0 - KEY_NUM9 steht dabei für die Zifferntasten 1 bis 9, KEY_STAR für die „*“-Taste und KEY_POUND für die „#“-Taste. Um das Steuerkreuz abzufragen muss dagegen auf die Funktion „getGameAction(int key)“ zurückgegriffen werden, die ebenfalls von der Canvas-Klasse zu Verfügung gestellt wird. Die Methode liefert dabei anhand des übergebenen key-Parameters einen Wert zurück, der mit den folgenden Klassenkonstanten verglichen werden kann: UP, DOWN, RIGHT, LEFT, FIRE, GAME_A, GAME_B, GAME_C und GAME_D. Die ersten vier Konstanten stehen dabei für die Richtungen des Steuerkreuzes und „FIRE“ für die Auswahltaste des Steuerkreuzes. Die GAMETasten werden vom Hersteller des Gerätes zugeordnet und können daher vom Endgerät zu Endgerät auf unterschiedlichen Tasten platziert sein, meisten aber Zifferntasten (1,3,7,9) Im Nachfolgenden ist ein Auszug aus dem WalkMario-Programm gegeben, das die Variablen „up“ , die bereits im vorhergehenden Abschnitt erwähnt wurden, entsprechend setzt. Das Setzen der Variablen „down“, „left“ und „right“ erfolgt dabei entsprechend. Dabei ist es egal, ob das Steuerkreuz (Zeile 4, 13 )oder die Zifferntasten 2 (Zeile 7, 16 ) zur Steuerung verwendet werden. Quelltext 5.5 (Programm: Game_02_WalkMario) Christian Burmeister Anhang 19 Wie man im Quelltext erkennen kann, wird auch in Zeile 8 die „*“-Taste abgefragt um das Programm ordnungsgemäß beenden zu können. Zu beachten ist allerdings, dass die meisten mobilen Endgeräte das gleichzeitige Drücken mehrerer Tasten nicht unterstützt. Der JavaME-Emulator vom Sun unterstützt dies allerdings, daher wurde zum besseren Testen, dies in Zeile 2 künstlich deaktiviert, indem einfach alle Tasten auf „false“ gesetzt werden. Wenn Tasten nicht gleichzeitig gedrückt werden können, hat dies in machen Situationen unschöne Auswirkungen, z.B. wenn man gleichzeitig nach rechts laufen und dabei springen will geht dies nicht. Dieser Umstand muss bei der Entwicklung von Spielen beachtet werden. Um dieses Problem dennoch zu lösen, könnte man für die Aktion „rechts laufen und dabei springen“ die Taste 3 (KEY_NUM3) belegen. 5.1.4Erstellung eines Levels In diesem Abschnitt wollen wir uns nun mit der Erstellung eines Levels beschäftigen. Dabei bezieht sich das Beispiele auf das Programm „Game_02_WalkMarioTiles“. Ähnlich wie bei älteren Computerspielen, ist auch bei der 2D-Spieleentwicklung auf mobilen Endgeräten das Verfahren der kachelbasierten Levelerstellung (tile-based design) verbreitet. Dabei werden kleine Bildchen, die sogenannten Kacheln (engl. Tiles), mosaikartig zu einem Level zusammengesetzt. Der Vorteil dieses Verfahrens besteht darin, dass sehr wenig Arbeitsspeicher benötigt wird, welcher bei mobilen Endgeräten meist nicht sehr üppig ausfällt. Die Kachelgröße wird meist einheitlich für ein Spiel festgelegt, daher ist es wieder, möglich alle Kacheln in einer einzigen PNG-Datei zu speichern. In Abbildung 5.3 ist ein Beispiel für zwei 16 x 16 Pixel Kacheln gegen, die aus dem Spiel „Game_02_WalkMarioTiles“ übernommen wurde. Abbildung 5.6 (Programm: Game_02_WalkMarioTiles) Mit den beiden abgebildeten Kacheln kann nun mithilfe eines Tile-Editors ein Level erstellt werden. Sehr gut geeignet ist hierfür das Tile Studio [TILESTUDIO]. An dieser Stelle soll aber nicht näher auf dieses Programm eingegangen werden, im Abschnitt 8.2 befindet sich aber eine ausführliche Anleitung zum Erstellen und Exportieren eines Levels mithilfe des Tile Studios. Nach Erstellung der Karte erhält man ein Array aus Zahlenwerten, dass in Abbildung 5.4 zu sehen ist. Das abgebildete Array ist dabei zweidimensional und besitzt eine Größe von 20 x 28 Kachel. Gespeichert werden dabei nur die Zahlenwerte „0“ und „1“, dies kommt daher, da in Abbildung 5.3 nur zwei Kacheln abgebildet sind. Demnach steht der Zahlwert „0“ für die Boden-Kachel und „1“ für die Wand-Kachel. Abbildung 5.7 (Programm: Game_02_WalkMarioTiles) Christian Burmeister Anhang 20 Diese Art der Speicherung bietet einige Vorteile, zum einen benötigt es sehr viel weniger Speicherplatz, im Vergleich zur Speicherung der Karte als vollständiges Bild. Zum anderen ist es sehr viel flexibler, da z.B. Zahlenwerte innerhalb des Arrays zur Laufzeit verändert werden können. 5.1.5Scrolling des Levels Da unser eben erstelltes Level eine Abmessung von 20 x 28 Kacheln hat, also 320 x 448 Pixel, ist es für die meisten mobilen Endgeräte viel zu groß, um vollständig auf dem Display angezeigt zu werden. Daher muss die Karte in Abhängigkeit von der Position der Spielfigur verschoben werden, so das die Spielfigur immer innerhalb des sichtbaren Bildschirmausschnitts (Viewport) ist. Die einfachste Art dies zu realisieren, ist eine Translation auf dem Viewport durchzuführen, denn so müssen nicht alle andern Koordinaten, z. B. der Spielfigur und Gegner, angepasst werden. Um dies innerhalb unseres Spieles zu realisieren stellt das Graphics-Objekt der paint-Methode die Methode „translate(int x, int y)“ zur Verfügung. Die übergebenen Werte sorgen dafür, dass der momentane Koordinatenursprung (linke obere Ecke) an eine neue Position verschoben wird. Das nachfolgende Bild soll dies Veranschaulichen. Abbildung 5.8 (Bild 1 vor Translation, Bild 2 nach Translation) In Bild 1 der Abbildung 5.5 wurde noch keine Translation durchgeführt, daher ist die obere linke Ecke von Karte und Viewports (Bildschirm) deckungsgleich. Die translate-Funktion wird nun mit den neuen Werten (xt, yt) aufgerufen, die Werte befinden sich dabei im negativen Bereich. Dadurch wird der Koordinatenursprung (x0, y0) an die Stelle (xt, yt) verschoben, dies ist im Bild 2 zu sehen. Durch die Translation des Koordinatenursprung änderst sich auch die Koordinate der obere linke Ecke des Viewports (-xt, -yt), obwohl die Position eigentlich nicht verändert wurde. Nach der Translation ist auch unser Spielfigur wieder im Viewport zu sehen, obwohl sie immer noch die gleiche Koordinate wie vor der Translation besitzt. Den Viewport kann man sich demach als Bilderrahmen vorstellen und die Karte als Bild. Der Bilderrahmen bleibt immer an der gleichen Position nur das sich dahinter befindliche Bild wird verschoben. Um die Translation durchzuführen, wurde die Methode „scrollMap()“ entwickelt, innerhalb dieser die Translation durchgeführt wird. Wie man in Quelltext 5.6 in Zeile 3 erkennen kann, wird zuerst die Figur bewegt und erst danach die Karte verschoben, dies ist notwendig, da die TranslationsWerte anhand der X und Y- Koordinate der Spielfigur bestimmt werden. Gezeichnet werden die Karte und die Spielfigur aber erst nach der Verschiebung des Koordinatenursprungs. Die Reihenfolge der Aufrufe ist hier sehr wichtig, da sonst die Koordinaten von Spielfigur und Karte nicht zusammen passen würden. Christian Burmeister Anhang 21 Quelltext 5.6 (Programm: Game_02_WalkMarioTiles) Die eigentliche srollMap-Methode sieht nun wie folgt aus: Quelltext 5.7 (Programm: Game_02_WalkMarioTiles) In Zeile 2 bis 7 wird der xt-Wert bestimmt, dabei wird Zeile 4 ausgeführt, wenn die Spielfigur nach unter läuft und Zeile 6 wenn die Spielfigur wieder nach oben läuft. Eine Änderung des xt-Wertes geschieht nur, wenn sich die Spielfigur in der mittleren Breite des Viewports befindet (canvasWith / 2). In Zeile 8 bis 13 wird der yt-Wert bestimmt, das Vorgehen ist dabei ähnlich. In Zeile 14 wird nun die eigentliche Translation durchgeführt. Dadurch, dass sich der Koordinatenursprung immer an der linken oberen Ecke der Karte befindet, hat die Translation keine Auswirkungen auf die X und Y-Koordinaten der Spielfigur oder anderer Objekte. Eine Ausnahme gibt es allerdings, und zwar, wenn Spielinformationen am oberen Rand des Viewports eingeblendet werden sollen. Um dieses Problem zu umgehen kann eine zweite Translation durchgeführt werden, die in Quelltext 5.6 in Zeile 7 abgebildet ist. Damit verschiebt man den Koordinatenursprung an die linke obere Ecke des Viewports, danach kann dann wie gewohnt an Stelle (0,0) gezeichnet werden. Beachten sollte man dabei, dass sich innerhalb eines paint-Zyklus die Translationen kumulativ auswirken aber in jedem neuen paint-Zykus der Urzustand wiederhergestellt ist. Dies ist so, weil immer ein neues Graphics-Objekt der paintMethode übergeben wird. 5.1.6Zeichnen des Levels Wir wissen jetzt wie man eine Karte erstellt und wie man eine Karte, in Abhängigkeit von der Position der Spielfigur, verschieben kann. Was wir aber noch nicht wissen ist, wie wir die Karte zeichnen können. In Quelltext 5.6 war bereits der Aufruf der drawMap-Methode zu sehen, diese soll nun im Nachfolgenden vorgestellt werden. Christian Burmeister Anhang 22 Quelltext 5.8 (Programm: Game_02_WalkMarioTiles) Wie man in Zeile 2 und 3 erkennen kann, werden zwei ineinander geschachtelte For-Schleifen durchlaufen. Weil wir nicht die komplette Karte zeichnen wollen, sondern nur den sichtbaren Bereich, also den Viewport, wird ab den Punkt (-xt, -yt) begonnen. Durchlaufen wird dabei die komplette Breite und Höhe des Viewports. Da wir Kacheln (Tiles) zeichnen wollen, die eine Größe von 16 Pixeln haben, wird bei jedem Durchlauf der x und y-Wert um 16 Pixel inkrementiert (TILESSIZE). In Zeile 4 und 5 wird der x und y-Wert auf die Kachelgröße geeicht, damit ist sichergestellt, dass sie immer auf die linke ober Ecke der Kachel verweisen. In Zeile 6 und 7 wird überprüft ob der x und y Wert innerhalb des gültigen Bereiches liegt, der in der Karte gespeichert ist. In Zeile 8 wird nun die Kachelnummer gespeichert, die sich an der aktuellen Position befindet. Zum Schluss wird die Kachel dann mit der bereits bekannten Methode „drawFrame()“ an die aktuelle Position gezeichnet. 5.1.7Kollisionserkennung im Level Wenn man das Programm „Game_02_WalkMarioTiles“ ausführt, merkt man schnell, dass sich die Spielfigur nach Belieben auf der Karte bewegen kann. Dies kommt daher, weil noch nicht festgelegt wurde, dass Wand-Kacheln ein Hindernis darstellen sollen. Um dies zu realisieren, benötigen wir eine Technik zur Kollisionserkennung, die es uns ermöglicht, festzustellen ob unsere Spielfigur mit einer Wand-Kachel kollidiert. Es müssen dabei nicht alle Kacheln auf eine Kollision hin überprüft werden, es reicht aus, wenn sechs Kacheln überprüft werden, da sich die Spielfigur gleichzeitig maximal auf sechs Kacheln befinden kann. Abbildung 5.9 (Programm: Game_04_WalkMarioTilesCollison) Wie man in der Abbildung erkennen kann, sind die sechs umgebenden Kacheln durch Boxen hervorgehoben. Dabei sind diese Boxen normalerweise nicht sichtbar, sie dienen hier lediglich zur besseren Anschaulichkeit. Christian Burmeister Anhang 23 Im Programm „Game_04_WalkMarioTilesCollison“ wurden die Boxen zu Demonstrationszwecken ebenfalls implementiert, wenn das Programm läuft kann man sie über die Taste „0“ ein und ausschalten. In der Abbildung 5.6 ist die untere rechte Box blau dargestellt, dies soll signalisieren, dass bei dieser Kachel eine Kollision vorliegt, da sich der Fuß der Spielfigur auf der Wand-Kachel befindet. Um diese Technik nun im Spiel verwenden zu können, wurde die „checkBorderTiles()“ Methode entwickelt, die in Quelltext 5.9 abgebildet ist. Dabei werden zunächst in Zeile 2 bis 13 die linken oberen Ecken der sechs Boxen ermittelt. Um nun zu überprüfen ob es sich bei den sechs Kacheln um eine Wand-Kachel handelt, wird in Zeile 15 bis 26 die jeweils errechnete X und Y-Position, der oberen linken Ecke, als Index in das Karten-Array eingesetzt. Wenn sich an dieser Position eine Wand-Kachel befindet, bricht die Methode ab und liefert „true“ zurück, wenn die Figur keine WandKachel berührt wird „false“ zurückgegeben. Quelltext 5.9 (Programm: Game_04_WalkMarioTilesCollision) Diese Methode kann nun in der bereits bekannten moveFigure-Methode verwendet werden. Im Quelltext 5.10 ist ein Ausschnitt aus dieser Methode abgebildet. Um nun zu bestimmen, ob die Spielfigur gegen ein Hindernis stößt, wird zunächst die Position entsprechende der Geschwindigkeit der Spielfigur geändert (Abbildung 5.10, Zeile 3). Danach wird mittels der checkBorderTiles-Methode überprüft ob die Figur gegen eine Wandkachel gelaufen ist, wenn dies der Fall ist, wird die davor gemachte Positionsänderung wieder rückgängig gemacht (Zeile 5). Christian Burmeister Anhang 24 Quelltext 5.10 (Programm: Game_04_WalkMarioTilesCollision) Damit hätten wir nun erreicht, dass die Spielfigur nicht mehr nach belieben durch Wände hindurchgehen kann, sondern an diesen gestoppt wird. 5.1.8Kollisionserkennung bei Objekten Um Kollisionen mit anderen Objekten zu erkennen wird eine ähnliche Technik verwendet. Diese setzt sogenannte Bounding-Boxes ein. Eine Bounding-Box ist dabei eine rechteckige Box die genau um das Objekt gezeichnet wird. Wenn sich zwei solcher Boxen überschneiden liegt eine Kollision vor. Die folgende Abbildung soll dies veranschaulichen. Abbildung 5.10 (Kollisionserkennung zwischen Spielfigur und Objekt) Die Boxen sind normalerweise auch nicht zu sehen, sie wurden hier ebenfalls nur zur Demonstrationszwecken eingezeichnet. Im Programm „Game_04_WalkMarioTilesCollision“ lassen sich die Bounding-Boxen über die Taste „5“ ein und ausschalten. Um diese Technik im Spiel nutzen zu können wurde die beiden folgenden Methoden entwickelt. Christian Burmeister Anhang 25 Quelltext 5.11 (Programm: Game_04_WalkMarioTilesCollision) Der checkCollision-Methode , welche die eigentliche Kollisionserkennungsmethode ist, werden zwei Rechteck übergeben, die jeweils durch zwei Punkte beschrieben werden. Wenn sich die beiden Rechtecke überlagern liefert die Methode „true“ sonst den Wert „false“ zurück. In der checkCollisionFigureRubin-Methode wird zunächst die ceckCollison-Methode aufgerufen. Dabei werden als Parameter die Eckpunkte der Spielfigur und des Objektes (hier ein Rubin) übergeben. Wenn die beiden Bounding-Boxen sich überschneiden wird in Zeile 7 der Punktestand erhöht und die Variable „rubinLocated“ auf „true“ gesetzt. Diese Variable wird in der nicht abgebildeten Methode „drawRubin()“ abgefragt, und entscheidet darüber ob der Rubin gezeichnet werden soll. 5.2Beispielprogramme Im Rahmen dieser Ausarbeitung sind insgesamt sechs JavaME-Programme entstanden, von denen jeweils ausgewählte Ausschnitte in den vorigen Abschnitten beschrieben wurden. Da diese Ausarbeitung auf 25 Seiten begrenzt ist, kann auch leider nicht näher auf diese Programme eingegangen werden. Im Anhang 8.3 befindet sich aber zu jedem Programm eine kurze Anwenderbeschreibung, die auf die Funktion des Programms und die Eingabemöglichkeiten eingeht. Weiterhin befindet sich auf der beilegenden CD im Ordner „Beispiele“ das komplette Projekt-Verzeichnis zu den jeweiligen Programmen. An dieser Stelle soll noch kurz auf das Programm „Game_05_SuperMarioBros“ eingegangen werden, welches eigentlich in Rahmen dieser Ausarbeitung besprochen werden sollte. Dies war aber auf Grund der Komplexität des Programmes leider nicht mit der Beschränkung der Ausarbeitung auf 25 Seiten vereinbar. Aus diesem Grunde soll hier nur ein kleiner Überblick über das Programm gegeben werden, um es dem interessierten Leser zu erleichtern sich selbst in den Quellcode einzuarbeiten. Als Vorlage für das Spiel dient das Jump ‘n‘ Run Spiel „Super Mario Bros“ der Firma Nintendo, welches, mit Hilfe der im Abschnitt 5.1 kennengelernten Techniken, versucht wurde nachzubauen. Um einen ersten Eindruck vom Spiel gewinnen zu können, empfiehlt es sich den Abschnitt 8.3.6 zu lesen. Dort werden zum einen drei Screenshorts des Spieles gezeigt und zum anderen die Eingabemöglichkeiten und das Ziel des Spieles erklärt. In diesem Spiel wird nicht nur eine Spielfigur animiert, sondern mehrere. Dazu gehört zum einen die Hauptspielfigur „Mario“ die einmal „groß“ und einmal „klein“ sein kann und zum anderen mehrere Gegner, ein Pilz, der die Hauptspielfigur „groß“ machen kann, und ein animiertes Geldstück das immer erscheint, wenn „Mario“ von unten gegen eine Fragezeichenbox hüpft. Um dies zu realisieren werden mehrere Klassen benötigt, die in Abbildung 5.8 in einem Klassendiagramm dargestellt sind. Christian Burmeister Anhang 26 Abbildung 5.11 (Programm: Game_05_SuperMarioBros) Die bereits aus Abschnitt 3.3 bekannte Klasse „myMIDlet“ dient wieder als Einstiegspunkt in das Spiel. Sie erzeugt eine neue Instanz der Klasse „GameCanvas“ und startet damit das Spiel. In der Klasse GameCanvas befindet sich unter anderem die Spielschleife und die Behandlung der Tastendrücke. In der Spielschleife wird durch die Klasse „Game“ das Spiel gezeichnet. Dabei stellt die Klasse „Game“ den zentralen Bestandteil des Spieles da, in ihr werden alle benötigten Spieleobjekte erzeugt und der Ablauf des Spieles durch Verwendung von Zuständen gesteuert. Das Spiel befindet sich dabei immer in einem der folgenden fünf Zustände: - PLAY: wird ausgeführt, wenn normal gespielt wird. - INTRO: wird ausgeführt, wenn das Spiel neu startet - MARIO_HIT: wird ausgeführt, wenn die Spielfigur durch einen Gegner oder einen Wassergraben ein Leben verloren hat. - GAME_OVER: wird ausgeführt, wenn die Spielfigur alle drei Leben verbraucht hat - FINISHED: wird ausgeführt, wenn das Ziel (Fahnenmast) des Spiels erreicht ist. Weiterhin ist sie für das Scrolling der Karte zuständig und für die Kollisionserkennung zwischen den einzelnen Sprites. Die Klasse „Level“ ist für die Erzeugung und Zeichnen der Karte zuständig, und stellt weiterhin Methoden bereit um abzufragen auf welcher Kachel sich eine Spielfigur befindet (z.B. für Kollisionserkennung). Die Klasse „Sprite“ ist eine abstrakte Klasse, die allgemeine Funktionen der Spielfiguren zusammenfasst, von ihr werden die vier Klassen „Enemy“, „Money“, „Mushroom“ und „Mario“ abgeleitet. In diesen vier Klassen wird das Verhalten und Erscheinungsbild der einzelnen Spielfiguren festgelegt. Die Klasse „Toolbox“ ist eine statische Klasse, die allgemeine Funktionen bereitstellt, die von mehren Klassen benötigt werden. Christian Burmeister Anhang 27 6.Abschluss 6.1Anmerkungen zur Ausarbeitung Während der Erstellung dieser Ausarbeitung sind eigentlich keine größeren Problem aufgetreten. Sehr schwer ist es mir jedoch gefallen, mich an die vorgegebene Beschränkung von 25 Seiten zu halten. Denn dadurch war es mir leider nicht möglich auf mein eigentliches Programm „Game_05_SuperMarioBros“ genauer einzugehen. Daher musste ich mich im Rahmen dieser Ausarbeitung nur auf die Grundlagen der 2D-Spieleprogrammierung beschränkt, die anhand von einfachen Beispielen demonstriert wurden. Weiterhin wollte ich auch noch kurz auf die seit MIDP 2.0 verfügbare JavaME Game-API eingehen. Diese API stellt im Namensraum javax.microedition.lcdui.game insgesamt fünf Klassen bereit, die ein Teil der in dieser Ausarbeitung erwähnten Funktionalitäten zur Verfügung stellen. Ich habe aber bewusst auf den Einsatz dieser API verzichtet, da sie zum einen nur im MIDP 2.0 zur Verfügung steht und damit weder im MIDP 1.0 noch in der normalen Java-Edition verwendet werden dann. Und zum anderen ein großer Teil der Flexibilität verloren geht, den man durch den Einsatz von eigenen Methoden erlangt. Es währe aber dennoch interessant gewesen, diese API einmal genau zu betrachten. Dem interessierten Leser sei daher die Webseite [SUNGAME] empfohlen. 6.2Schlusswort Ich hoffe, dass ich mit dieser Ausarbeitung, zumindestens einen kleinen Einblick, in die behandelten Themengebiete geben könnte. Obwohl die 2D-Spieleprogrammierung nicht meine erste Wahl war, hat es mir dennoch viel Spaß gemacht dieses Thema zu bearbeiten. Mich hat dabei positiv Überrascht, dass die Entwicklung einfacher 2D-Spiele mit relativ wenig Programmieraufwand zu bewerkstelligen ist. Dies lag mit Sicherheit auch an der JavaME-Edition die den Umstieg von JavaSE nicht sehr schwer machte. Denn obwohl die JavaME-Edition stark eingeschränkt ist, bietet sie dennoch fast alles was man von JavaSE-Edition gewohnt ist. Christian Burmeister Anhang 28 7.Literatur und Verzeichnisse 7.1Literaturverzeichnis [BR06JAVAME]JavaME, Anwendunsentwicklung für Handys, PDA und Co. Ulrich Breymann und Heiko Mosemann, ISBN: 3-446-22997-3 [LU08MGAME] Mobile Games, Spieleprogrammierung für Handys in Java ME Thomas Lucka, ISBN: 978-3-446-41197-5 [PF07JAVAME]Java Micro Edition, Mobile Anwendungen mit der MIDP 2.0 entwickeln Michael Pfeifer, ISBN: 3-89842-505-3 7.2Internetquellen - Die Internetquellen wurden am 06.01.2009 auf ihre Erreichbarkeit überprüft. - Alle Internetquellen, außer [KARBACHER] und [NOKIASDK] befinden sich auf der beiliegenden CD im Ordner Internetquellen [ECLIPSEME] Eclipse Plug-In für JavaME http://eclipseme.org/ [ECLIPSE] Integrierte Entwicklungsumgebung: Eclipse http://www.eclipse.org/downloads/ [IBMM3G] M3G Tutorial vom IBM http://www.ibm.com/developerworks/java/library/wi-mobile1/ http://www.ibm.com/developerworks/wireless/library/wi-mobile2/ [JSR30] Connected Limited Device Configuration 1.0 www.jcp.org/en/jsr/detail?id=30 [JSR37] Mobile Information Device Profile 1.0 www.jcp.org/en/jsr/detail?id=37 [JSR118] Mobile Information Device Profile 2.0 www.jcp.org/en/jsr/detail?id=118 [JSR139] Connected Limited Device Configuration 1.1 www.jcp.org/en/jsr/detail?id=139 [JSR184] M3G Version 1.0, 1.1 http://jcp.org/en/jsr/detail?id=184 http://jcp.org/aboutJava/communityprocess/mrel/jsr184/index.html [JSR297] M3G Version 2.0 http://jcp.org/en/jsr/detail?id=297 [KARBACHER]Diplomarbeit zu JavaME http://www.karbacher.org/java-j2me/midlets-midletsuite/ Christian Burmeister Anhang 29 [MARIOSP] Mario Sprite http://www.gsarchives.net/index2.php? category=all&system=gameboyadvance&game=mario_and_luigi_superstar_saga& type=sprites&level0=non-animated&level1=mario [NETBEANS] Integrierte Entwicklungsumgebung: Netbeans http://www.netbeans.org/downloads/index.html [NOKIASDK] SKD für JavaME von der Firma Nokia http://www.forum.nokia.com/Resources_and_Information/Explore/Runtime_Platfor ms/Java.xhtml [PAINTNET] Bildbearbeitungsprogramm Paint.NET http://www.getpaint.net/download.html [SMBMAP] Vorlage für das erste Level im Spiel Game_05_SuperMarioBros http://ian-albert.com/misc/smb.php [SMBSPRITE] Sprites für das Spiel Game_05_SuperMarioBros http://www.mariomayhem.com/downloads/sprites/super_mario_bros_sprites.php http://www.videogamesprites.net/SuperMarioBros/ [SUN1] Übersicht über die Java ME Plattform http://java.sun.com/javame/technology/index.jsp [SUN2] Connected Limited Device Configuration Übersicht http://java.sun.com/products/cldc/overview.html [SUNGAME] Java Game API http://developers.sun.com/mobility/midp/articles/gameapi/ [SUNJDK] Java SE Development Kit (JDK) 6 http://java.sun.com/javase/downloads/index.jsp [SUNM3G] Getting Started With the Mobile 3D Graphics API for J2ME http://developers.sun.com/mobility/apis/articles/3dgraphics/ [SUNWTK] Sun Java Wireless Toolkit for CLDC http://java.sun.com/products/sjwtoolkit/download.html [TILESTUDIO] Tile Studio http://tilestudio.sourceforge.net/ [WERM3G] Ausarbeitungen von Herr Jeronimo Werder Mobile 3D Grahics (Ausarbeitung im Rahmen des berufspraktischen Semesters) Präsentation zu Mobile 3D Grahics am 21.11.08 im Fachbereich AI, FHFulda Diplomarbeit: „Realisierung von 3D-Grafiken für mobile Endgeräte unter Betrachtung geeigneter Grafikbibliotheken (OpenGL|ES, M3G) und Fenstersystemen“ Zu finden auf der beiliegenden CD im Ordner „Internetquellen\WERM3G“ oder auf Nachfrage auch bei Prof. Dr. Werner Heinzel, FH-Fulda Christian Burmeister 7.3Abkürzungsverzeichnis AMS Aplication Managment Software API Application Programming Interface CDC Connected Device Configuration CLDC Connected Limited Device Configuration IDE Integrated Development Environment J2ME Java 2 Micro Edition -> heute: Java Micro Edition JavaEE Java Enterprise Edition JavaME Java Micro Edition JavaSE Java Standard Edition JDK Java Development Kit JSR Java Specification Request JVM Java Virtual Machine KVM K(ilobyte) Virtual Machine MIDP Mobile Information Device Profile PDA Personal Digital Assistant PNG Portable Network Graphics SDK Software Development Kit WTK Wirless Toolkit Anhang 30 Christian Burmeister Anhang 31 8.Anhang 8.1Einrichten von Eclipse In diesem Abschnitt soll nun beschrieben werden, wie man ein JavaME Programm mithilfe von Eclipse erstellen und ausführen kann. Dies soll nun im Folgenden schrittweise gezeigt werden. 8.1.1Installation des Java SE Development Kit Um Eclipse installieren zu können, müssen wir zunächst das Java SE Development Kit (JDK) installieren. Heruntergeladen kann man es kostenlos von der Webseite der Firma Sun [SUNJDK]. Nachdem man die Installationsdatei ausgeführt hat, wird man nach dem Installationsverzeichnis gefragt, dabei sollte das vorgegebene Verzeichnis „C:\Programme\Java\jre6“ übernommen werden. Am Ende der Installation muss man noch auf „Finish“ klicken um die Installation zu beenden. Damit wäre die Installation des JDK beendet. 8.1.2Installation des Sun Java Wireless Toolkit for CLDC Das Wireless Toolkit (WTK) stellt die Grundlage für JavaME da. Es installiert zum einen die JavaME API und zum anderen mehre Emulatoren für JavaME. Das WTK kann dabei ebenfalls kostenlos von der Webseite der Firma Sun heruntergeladen werden [SUNWTK]. Bei der Installation wird man als erstes nach dem Verzeichnis des Java SE Development Kit (JDK) gefragt. Hier kann der Vorschlag übernommen werden, da das Verzeichnis „C:\Programme\Java\jre6“ bereits ausgewählt ist. Als Installationsverzeichnis für das WTK wird „C:\ WTK2.5.2_01“ vorgeschlagen, soweit nichts dagegen spricht sollte dieses Verzeichnis übernommen werden. Um die Installation zu beenden, muss man ebenfalls wieder auf „Finish“ klicken. 8.1.3Installation von Eclipse Eclipse muss zunächst von der Webseite [ECLIPSE] heruntergeladen werden. Nach dem Herunterladen muss man einfach die ZIP-Datei entpacken und das enthaltene Verzeichnis „eclipse“ nach „C:\Programme“ kopieren. Jetzt kann man Eclipse durch anklicken der „eclipse.exe“-Datei, die sich unter „C:\Programme\eclipse“ befinden sollte, starten. Hier erscheint zunächst ein Fenster, welches nach dem Speicherort für den Arbeitsordner fragt, hier kann einfach der Vorgabewert übernommen werden. Damit wäre auch Eclipse installiert. 8.1.4Installation von EclipseME Um das WTK mit Eclipse nutzen zu können, wird der Plugin EclipseME benötigt. Zu beziehen ist er von [ECLIPSEME]. Die Installation ist wieder relativ einfach, da die ZIP-Datei nur entpackt werden muss und die beiden Ordner „features“ und „plugins“ in das Verzeichnis „C:\Programme\eclipse“ kopiert werden müssen. 8.1.5EclipseME einrichten Um EclipseME verwenden zu können, sind noch ein paar Einstellungen nötig. Dafür muss zunächst Eclipse gestartet werden und der Menüpunkt „Window -> Preferences“ ausgewählt werden. Daraufhin sollte sich folgendes Fenster öffnen. Christian Burmeister Anhang 32 Abbildung 8.12 (Programm: Eclipse) Jetzt muss in den Menüzweig „J2ME -> Device Management“ gewechselt werden. In dem sich jetzt öffnenden linken Fenster muss auf den Knopf „Import …“ geklickt werden. Daraufhin öffnet sich folgendes Fenster. Abbildung 8.13 (Programm: Eclipse) Christian Burmeister Anhang 33 In diesem Fenster muss unter dem Eingabefeld „Specify search directory“ das Installationsverzeichnis des WTK ausgewählt werden, also „C:\WTK2.5.2_01“. Danach klickt man auf „Refresh“, damit startet man die Suche nach den installierten JavaME-Emulatioren. Es sollten dabei vier Emulatoren gefunden werden, diese sind auch in Abbildung 6.2 abgebildet. Danach bestätigt man mit einem klick auf „Finish“. Jetzt sollte folgendes Fenster wieder sichtbar sein. Abbildung 8.14 (Programm: Eclipse) Die vier Emulatioren sind nun importiert. Das „DefaultColorPhone“ sollte als „Default“ ausgewählt werden. Danach mit einem klick auf „Apply“ die Eingabe bestätigen. Nun muss noch die Debug-Einstellungen angepasst werden. Dazu wechselt man im Menüzweig auf „Java -> Debug“, in dem sich nun links öffnenden Fenster (Abbildung 8.4) müssen die folgenden Optionen deaktiviert werden. - Suspend execution on uncaught exceptions Suspend execution on compilation errors Weiterhin muss unter dem Punkte „Debugger timeout (ms)“ der Wert auf 15000 erhöht werden. Um die Eingabe abzuschließen klickt man zuerst auf „Apply“ und dann auf „OK“. Damit wäre nun auch der EclipseME Plugin erfolgreich eingerichtet. Christian Burmeister Anhang 34 Abbildung 8.15 (Programm: Eclipse) 8.1.6Anlegen eines JavaME-Projekes in Eclipse Nachdem nun alle erforderlichen Komponenten installiert und eingerichtet sind, kann man nun ein Java-ME Projekt anlegen. Dazu wählt man in der Menüzeile von Eclipse „File -> New -> Project…“ aus. Daraufhin erscheint folgendes Fenster Abbildung 8.16 (Programm: Eclipse) Christian Burmeister Anhang 35 Hier wählt man „J2ME -> J2ME Midlet Suite“ aus. Danach klickt man auf „Next“. Abbildung 8.17 (Programm: Eclipse) In dem sich jetzt öffnenden Fenster kann man dem Projekt einen Namen geben, in unserem Fall „Hello World“. Danach wieder auf „Next“ klicken. In dem sich jetzt öffnenden Fenster einfach auf „Finish“ klicken. Daraufhin gelangt man wieder ins Hauptfenster, auf der linken Seite ist jetzt das eben erstellt Projekt zu sehen. Abbildung 8.18 (Programm: Eclipse) Christian Burmeister Anhang 36 Innerhalb des „src“-Ordners müssen nun über den Menüpunkt „File -> New -> Class“ die beiden Klassen „MyMIDlet“ und „MyCanvas“ erstellt werden. Der Inhalt der beiden Klassen kann dabei aus Abbildung 3.1 bzw 3.2 übernommen werden. Danach muss man auf die Datei „HelloWorld.jad“ klicken, die sich innerhalb des Projektzweiges befindet. Abbildung 8.19 (Programm: Eclipse) Daraufhin öffnet sich der „Application Descriptior Editor“ der die bereits erwähnte JAD-Datei erstellt. Hier muss man auf den Reiter „Midlets“ wechsel , der sich am unteren Rand befindet. Danach muss man über den „Add“ Knopf einen neuen Eintrag für das JavaME Programm erzeugen. Dabei sollte als Name „HelloWorld“ und als „Class“ die von MIDlet abgeleitete Klasse gewählt werden. Danach speichert man die getätigten Änderungen. Um das Programm nun innerhalb des Emulators auszuführen muss man noch einige Einstellungen machen. Über dem Menüpunkt „Run -> Run Configurations … “ gelangt man in folgendes Fenster. Abbildung 8.20 (Programm: Eclipse) Christian Burmeister Anhang 37 Hier klickt man auf den Punkt „Wirless Toolkit Emulator“ daraufhin erstellt sich ein neuer Eintrag unterhalt von „Wirless Toolkit Emulator“ und auf der rechten Seite öffnet sich ein neues Fenster (Abbildung 8.9). Hier vergibt man den Namen „HelloWorld“ und im Eingabefeld „Projekt“ wählt man das Projekt „HelloWorld“ aus und zuletzt im Eingabefeld „Midlet“ die Klasse, die von MIDlet abgeleitet ist. Danach bestätigt man mit einem klick auf „Apply“. Um das Programm nun auszuführen drückt man auf „Run“. Damit sollt sich nun der JavaME-Emulator öffnen. Abbildung 8.21 (Programm: WTK) Über den Menüpunkt „Run -> Run History“ kann der Emulator in Zukunft einfacher ausgeführt werden. Christian Burmeister Anhang 38 8.2Erstellen einer Karte mit Tile Studio Wie bereits im Abschnitt 5.1.4 erwähnt, werden Level in 2D Spielen meist mittels Kacheln (engl. Tiles) realisiert. Alle Kacheln besitzen dabei stets die gleichen Abmessungen z.B. 16 x16 oder 32 x 32 Pixel. Da es meist nicht bei ein oder zwei Kacheln bleibt, speichert man alle Kacheln zusammen in eine einzigen Datei ab, dadurch ist die Handhabung um einiges einfach. Da wir bereits in Abschnitt 5.1.4 eine einfache Karte erstellt haben, soll hier auf eine etwas komplexere Karte eingegangen werden. Das Beispiel stammt dabei aus dem Programm „Game_05_SuperMarioBros“. Um eine Karte zu erstellen benötigt man zuerst die erwähnten Kacheln. Um diese zu erstellen bietet sich das kostenlose Bildbearbeitungsprogramm „Paint.NET“ an, das unter der Adresse [PAINTNET] heruntergeladen werden kann. Nachdem man die einzelnen Kacheln erstellt hat, legt man eine neue PNG-Datei an. Die Höhe und Breite ist dabei von der Kachelgröße abhängig. Das in Abbildung 5.1 gezeigt Bild hat zum Beispiel eine Höhe von 16 Pixeln und eine Breite von 544 Pixeln. Da die einzelnen Kacheln eine Größe von 16 x 16 Pixel besitzen, können so genau 34 Kacheln (544 / 16 = 34) in der Datei gespeichert werden. Die Zahlen unter den einzelne Kacheln, sind nicht Bestandteil des Bildes, sie dienen hier lediglich als Hilfsmittel zur Orientierung. Abbildung 8.22 (Programm: Game_05_SuperMarioBros) Nachdem man die einzelnen Kacheln erstellt und in einer PNG-Datei gespeichert hat, kann man mit der Erstellung der Karte beginnen. Zu diesem Zweck installiert man sich das Programm „Tile Studio“ das ebenfalls kostenlos unter der Adresse [TILESTUDIO] heruntergeladen werden kann. Die Installation des Programmes besteht lediglich darin, eine ZIP-Datei herunterzuladen und zu entpacken. Danach startet man einfach die „ts.exe“-Datei. Jetzt sollte das Programm starten und das folgende Fenster erscheinen. Abbildung 8.23 (Programm: Tile Studio) Christian Burmeister Anhang 39 Zum importieren der PNG-Datei mit den einzeln Kacheln muss der Punkt „File->Import Tiles…“ ausgewählt werden. Jetzt erscheint ein Fenster in dem die PNG-Datei selektiert werden muss. Wenn dies erfolgreich absolviert wurde, sollte folgendes Fenster erscheinen. Abbildung 8.24 (Programm: Tile Studio) Sehr wichtig beim Importieren ist, das die „Tile Width:“ und „Tile Height:“ auf die Größe einer Kacheln eingestellt wird, in unserm Beispiel also 16 x 16 Pixel. Um Transparenz nutzen zu können, muss mit der Maus auf das Feld „Transparent color(s):“ geklickt werden und dann auf die entsprechende Farbe im Bild, die später transparent erscheinen soll, in unserm Fall ist dies Weiß. Nachdem die Einstellungen alle gesetzt wurden, klickt man auf „Import“. Jetzt sollte das Hauptfenster in etwa wie folgt aussehen. Abbildung 8.25 (Programm: Tile Studio) Christian Burmeister Anhang 40 Im untern linken Teil des Fensters sind nun die importierten Kacheln zu erkennen. Um mit diesen jetzt eine Karte erstellen zu können, muss zuerst eine neue Karte angelegt werden. Dafür klickt man auf „File->New Map…“, daraufhin öffnet sich folgendes Fenster. Abbildung 8.26 (Programm: Tile Studio) In diesem Fenster legt man die Höhe und Breite der Karte fest, diesmal aber nicht in Pixeln, sondern in Anzahl der Kachel. Für unser Beispiel benötigen wir eine Größe von 212 x 18 Kacheln, dies entspricht einer Auflösung von 3392 x 288 Pixeln. Nach dem Anlegen der Karte sollte das Hauptfenster in etwa wie folgt aussehen. Abbildung 8.27 (Programm: Tile Studio) Der obere dunkel-graue Bereich stellt die Fläche da, in der die Karte erstellt wird. Um die einzelnen Kacheln jetzt in der Karte zu platzieren gibt es 2 Modi. Der erste der beiden ist ein Modus, in dem man direkt zeichnen kann, ausgewählt wird er über das Zeichenstift-Symbol (vgl. Abbildung 8.17) an linken Fensterrand. Um nun eine Kachel auf der Karte zu platzieren, wählt man eine beliebige Kachel im untern Fensterbereich aus und platziert sie dann, mit gedrückter linker Maustaste, nach Belieben auf der Karte. Mit dem zweiten Modus kann man Bereiche festlegen, auf den sich dann die nachfolgende Operation bezieht. Um ihn auszuwählen, wählst man das gestrichelte Rechteck-Symbol auf der linken Seite des Fensters (vgl. Abbildung 8.17). Christian Burmeister Anhang 41 Abbildung 8.28 (Programm: Tile Studio) Jetzt kann man mit gedrückter linken Maustaste einen Bereich festlegen. Wenn man dies getan hat, kann man auf eine beliebige Kachel klicken um damit den Bereich mit der gewählten Kachel zu füllen. Es ist aber auch möglich auf den gewählten Bereich die Operationen „Ausschneiden“, „Kopieren“, „Einfügen“ oder „Löschen“ auszuführen, dafür wählt man die entsprechenden Symbole in der Menüleiste. Wenn man sich mit Hilfe der beiden Modi eine Karte zusammengestellt hat, könnte sie in etwa wie folgt aussehen. Abbildung 8.29 (Programm: Tile Studio) Wie man vielleicht in der Abbildung erkennen kann weichen die Kacheln 30 und 33 von den in Abbildung 8.1 gezeigten Kacheln ab, Kachel 30 wird hier als X dargestellt und die Kachel 33 als Fragezeichen. Dies dient aber nur als Hilfestellung, da diese Kacheln später im Spiel als vollständig transparent dargestellt werden. Es ist prinzipiell auch egal wie die Kacheln im Tile Studio aussehen, da nur die Kachelnummern (vgl. Abbildung 8.1 , 8.2, 8.4) in der Karte gespeichert werden und nicht die Kacheln selbst. Um die Karte nun zu exportieren gibt es mehre Vorlagen, da aber leider keine passende vorhanden war, musste selbst eine Vorlage erstellt werden. Um selbst eine Export-Vorlage zu erstellen muss man sich an die „Tile Studio Definiton“ (TSD) halten die unter http://tilestudio.sourceforge.net/tutor.html erläutert wird. Dies ist eine Art Beschreibungssprache mit der man festlegt, wie man die Karte exportieren kann. Eine sehr einfachst Export-Vorlage ist in Quelltext 8.1 abgebildet. Dabei wird in Zeile 1 festgelegt in welche Datei die Karte gespeichert werden soll, hier also „level.dat“. In Zeile 4 wird die Anzahl der Kacheln in der Höhe und Breite gespeichert. Mit den Zeilen 4, 6 und 7 wird jetzt jede einzelne Kachelnummer hintereinander, durch Komma getrennt, gespeichert. Dabei wird mit der Kachel oben links begonnen und dann Zeilenweise bis zur unteren rechten Kachel vorgegangen. Christian Burmeister Anhang 42 Quelltext 8.7 (Datei: format.tsd) Der Inhalt der „level.dat“ würde dann in etwa wie folgt aussehen. Dabei würde die Ausgabe der Kachelnummern etwas gekürzt, da 3816 einzelne Kachelnummern (212 * 18 = 3816) abgespeichert werden müssen. Quelltext 8.8 (Datei: level.dat) Diese Export-Vorlage eignet sich gut, wenn man Level aus einer Datei einlesen will. Da bei dem Programme „Game_03_WalkMarioTiles“ und „Game_03_SuperMarioBros“ aber jeweils nur ein einziges Level vorhanden ist, eignet sich die nachfolgende Export-Vorlage besser, da sie die Kachelnummern gleich in Form eines zweidimensionalen Arrays speichert. Quelltext 8.9 (Datei: format2.tsd) Wie man in Zeile 2 erkennen kann, wird die Karte jetzt in die Datei „format2.dat“ exportiert. In Zeile 4 und 5 werden noch Zusatzinformationen, wie Datum und Uhrzeit, abgespeichert. In Zeile 7 und 8 wird die Anzahl der Kacheln in der Höhe und Breite gespeichert. Zeile 11, 12 und 13 dienen dazu die Karte in einem zweidimensionalen Array zu speichen. Der Inhalt der „format2.dat“-Datei sieht dann in etwa wie im Quelltext 8.4 aus. Der Vorteil dieser Export-Vorlage ist, dass der Inhalt der „format2.dat“-Datei einfach in das JavaME-Projekt kopiert werden kann, ohne Änderungen zu mache. Christian Burmeister Anhang 43 Quelltext 8.10 (Datei: format2.dat) Um die beiden Export-Vorlagen nun in das Tile Studio einzubinden müssen die beiden Dateien einfach in das Programmverzeichnis kopiert werden. Danach muss man im Programm auf „Code-> Code Generation Settings…“ klicken, daraufhin sollte dann folgendes Fenster aufgehen. Abbildung 8.30 (Programm: Tile Studio) Christian Burmeister Anhang 44 Wie man in der Abbildung erkennen kann, kann man die gewünschte Export-Vorlage nun auswählen. Nach dem man die gewünschte Export-Vorlage ausgewählt hat, bestätigt man mit einem klick auf „OK“. Um die Karte zu exportieren muss man dann nur noch im Hauptprogrammfenster die Taste „F10“ auf der Tastatur drücken, damit wird die Karte in die angegebene Datei exportiert wird. Wenn der Export-Vorgang erfolgreich war, erscheint folgendes Fenster. Abbildung 8.31 (Programm: Tile Studio) Damit hätte man den Export der Karte abgeschlossen. Christian Burmeister Anhang 45 8.3Beispielprogramme (Anwenderdokumentation) Im nachfolgenden sollen die im Rahmen dieser Ausarbeitung erstellten Programm kurz vorgestellt werden. 8.3.1JavaME_01_HelloWorld Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/JavaME_01_HelloWorld/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/JavaME_01_HelloWorld/.eclipseme.tmp/emulation“ Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - MyCanvas.java: eine von Canvas abgeleitete Klasse, die den Text „Hello World“ auf die Leinwand zeichnet. Screenshot: Abbildung 8.32 Beschreibung: - Dieses Programm dient lediglich dazu, zu zeigen, wie ein einfaches JavaME-Programm erstellt wird. Auf dem Bildschirm wird der Text „Hello World!“ dazu ausgegeben. Besprochen in: - Abschnitt 3.3, Abschnitt 8.1.6 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm Christian Burmeister Anhang 46 8.3.2Game_01_GameLoop Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/Game_01_GameLoop/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/Game_01_GameLoop/.eclipseme.tmp/emulation“ Erweiterung von: - JavaME_01_HelloWorld Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - GameCanvas.java: eine von Canvas abgeleitete Klasse, die innerhalb einer Schleife die paint-Methode aufruft Screenshot: Abbildung 8.33 Beschreibung: - Dieses Programm dient lediglich dazu, zu zeigen, wie man innerhalb einer Canvas-Klasse eine Spielschleife realisiert. Eine Spielschleife ist dabei nichts Anderes als eine Schleife, die es ermöglicht die paint-Methode eine bestimmte Anzahl mal pro Sekunde aufzurufen. Zu Demonstrationszwecken wird auf dem Bildschirm eine Zahl hochgezählt Besprochen in: - Abschnitt 5.1.1 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm Christian Burmeister Anhang 47 8.3.3Game_02_WalkMario Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/Game_02_WalkMario/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/ Game_02_WalkMario/.eclipseme.tmp/emulation“ Erweiterung von: - Game_01_GameLoop Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - GameCanvas.java: eine von Canvas abgeleitete Klasse, die die Animierung und Steuerung der Spielfigur übernimmt. - mario.png: Bild im dem die einzelnen Frames für die Spielfigur gespeichert sind Screenshot: Abbildung 8.34 Beschreibung: - Dieses Programm dient dazu, zu veranschaulichen, wie man eine Spielfigur animieren kann und sie dann mittels Tastatur über den Bildschirm steuern kann. Zu steuern ist die Spielfigur über die unten aufgeführten Eingabemöglichkeiten. Es ist allerdings noch möglich über die Bildschirmgrenzen hinaus zu laufen. Besprochen in: - Abschnitt 5.1.2, Abschnitt 5.1.2 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm - „→“ oder „6“ Taste: Spielfigur läuft nach rechts - „←“ oder „4“ Taste: Spielfigur läuft nach links - „↑“ oder „2“ Taste: Spielfigur läuft nach oben - „↓“ oder „8“ Taste: Spielfigur läuft nach unten Christian Burmeister Anhang 48 8.3.4Game_03_WalkMarioTiles Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/Game_03_WalkMarioTiles/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/Game_03_WalkMarioTiles/.eclipseme.tmp/emulation“ Erweiterung von: - Game_02_WalkMario Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - GameCanvas.java: eine von Canvas abgeleitete Klasse, die zum einen die Animierung und Steuerung der Spielfigur übernimmt und zum andern das zeichnen und Scrollen der Karte. - mario.png: Bild im dem die einzelnen Frames für die Spielfigur gespeichert sind - tiles.png: Bild im dem die einzelnen Kacheln für die Karte gespeichert sind Screenshot: Abbildung 8.35 Beschreibung: - Dieses Programm dient dazu, zu veranschaulichen, wie man ein einfaches Level erstellen, zeichnen und scrollen kann. Dabei ist das Scrolling der Karte jeweils von der Position der Spielfigur abhängig, dadurch ist gewährleistet, dass die Spielfigur immer innerhalb des Bildschirms zu sehen ist , auch wenn die Karte um einiges größer ist wie der Bildschirm selbst. Es ist allerdings noch möglich die Spielfigur, mittels der unten aufgeführten Eingabemöglichkeiten, über Hindernisse hinweg zu bewegen (z.B. Mauer, Kartenrand). In der oberen linken Ecke wird als Information der Punkt angegeben, der als Koordinatenursprung definiert wurde. Besprochen in: - Abschnitt 5.1.4 bis Abschnitt 5.1.6 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm - „→“ oder „6“ Taste: Spielfigur läuft nach rechts Christian Burmeister Anhang 49 - „←“ oder „4“ Taste: Spielfigur läuft nach links - „↑“ oder „2“ Taste: Spielfigur läuft nach oben - „↓“ oder „8“ Taste: Spielfigur läuft nach unten 8.3.5Game_04_WalkMarioTilesCollision Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/Game_04_WalkMarioTilesCollision/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/Game_04_WalkMarioTilesCollision/.eclipseme.tmp/emulation“ Erweiterung von: - Game_02_WalkMarioTiles Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - GameCanvas.java: eine von Canvas abgeleitete Klasse, die zumeinen die Animierung und Steuerung der Spielfigur übernimmt und zum anderen das Zeichnen und Scrollen der Karte. Zusätzlich wurde eine Kollisionserkennung eingeführt. - mario.png: Bild im dem die einzelnen Frames für die Spielfigur gespeichert sind - tiles.png: Bild im dem die einzelnen Kacheln für die Karte gespeichert sind - rubin.png: Bild für das Objekt (Rubin) - BoundingBox16x16.png: Bild für BoundingBox 16x16 Pixel - BoundingBox16x32.png: Bild für BoundingBox 16x32 Pixel Screenshot: Abbildung 8.36 Beschreibung: - Dieses Programm dient dazu, zu veranschaulichen, wie man eine Kollisionserkennung implementieren kann. Zunächst wurde die Kollisionserkennung zwischen Spielfigur und Karte implementiert, dadurch ist es der Spielfigur nicht mehr möglich durch Wände zu gehen. Um die Art der Implementierung zu demonstrieren, kann man die Taste „0“ drücken. Dadurch werden um die Figur 6 Rechtecke gezeichnet, diese dienen als Christian Burmeister Anhang 50 „Kollisionserkenner“, sobald sich eines dieser Rechtecke auf einer Wand-Kachel befindet, wird das Rechteck in blauer Farbe gezeichnet. Dies kann nun innerhalb des Programmes dazu benutzt werden, dass sich die Spielfigur nicht weiter in diese Richtung bewegen kann, im Demonstrationsmodus wurde dies aber bewusst deaktiviert. Die zweite Art der Kollisionserkennung ist die Erkennung vom Kollisionen zwischen der Spielfigur und einem Objekt (im Programm ein Rubin). Zu dieser Erkennungsart wurde ebenfalls ein Demonstrationsmodus implementiert, der über die Taste „5“ aktiviert werden kann. Hier werden ebenfalls Rechtecke um Spielfigur und Objekt gezeichnet, diesmal aber nur je eines. Wenn sich zwei dieser Rechtecke (Bounding-Boxes) überschneiden liegt eine Kollision vor und das Rechteck verfährt sich blau. Besprochen in: - Abschnitt 5.1.7, Abschnitt 5.1.8 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm - „→“ oder „6“ Taste: Spielfigur läuft nach rechts - „←“ oder „4“ Taste: Spielfigur läuft nach links - „↑“ oder „2“ Taste: Spielfigur läuft nach oben - „↓“ oder „8“ Taste: Spielfigur läuft nach unten - „0“ Taste: Demo-Kollisionserkennung für Kacheln und Spielfigur ein/ausschalten - „5“ Taste: Bounding-Box für Spielfigur und Rubin ein/ausschalten (Kollisonserkennung) 8.3.6Game_05_SuperMarioBros Speicherorte: - Quelltext: Auf der beiliegenden CD im Ordner „Beispiele/ Game_05_SuperMarioBros/src“ - Installationsdateien: Die JAD und JAR-Datei befinden sich auf der beiliegenden CD im Ordner „Beispiele/ Game_05_SuperMarioBros/.eclipseme.tmp/emulation“ Bestandteile: - MyMIDlet.java: eine von MIDlet abgeleitete Klasse, die zum Anzeigen der Leinwand dient. - GameCanvas.java: Leinwand, auf der das Spiel gezeichnet wird - Game.java: Diese Klasse koordiniert den Ablauf des Spiels - Level.java: Diese Klasse realisiert die Karte des Spiels - ToolBox.java: Diese Klasse stellt unterschiedliche Methoden bereit - Sprite.java: Abstrakte Klasse die eine Spielfigur realisiert - Mario.java: von Spirte, abgeleitete Klasse, die die Spielfigur realisiert - Enemy.java: von Spirte, abgeleitete Klasse, die einen Gegner realisiert - Money.java: von Spirte, abgeleitete Klasse, die springendes Geld realisiert - Mushroom.java: von Spirte, abgeleitete Klasse, die Pilz realisiert - Enemies.png: Bild für den Pilz - Items.png: Bild das einige Gegenstände enhält - MapTiles.png: Bild enthält die Kacheln für die Karte - MarioSmall.png: Bild enthält die einzelnen Sprites für die Spielfigur (klein) Christian Burmeister - Anhang 51 MarioTall.png: Bild enthält die einzelnen Sprites für die Spielfigur (gross) Screenshot: Abbildung 8.37 Beschreibung: - Ziel des Spieles ist es, bis ans Ende der Karte (Fahnenstange) zu gelangen. Auf dem Weg dorthin begegnen der Spielfigur einige Gegner (unzerstörbar) und drei Wassergräben, durch die die Spielfigur ein Leben verlieren kann. Die Spielfigur besitzt insgesamt drei Leben, wenn diese aufgebraucht sind ist das Spiel verloren. Auf dem Weg zum Ziel begegnen der Spielfigur aber nicht nur Gegner und Wassergärten, sondern auch Fragezeichenboxen, öffnen kann man diese, indem man von unten dagegenhüpft. In einer Fragezeichenbox kann entweder Geld (100 Punkte) oder ein Pilz versteckt sein. Wenn die Spielfigur einen Pilz berührt, wird sie „Groß“ und ist dadurch in der Lage eine Mauer zu zerstören, wenn sie von unten dagegenhüpft. Wenn die Spielfigur im großen Zustand einen Gegner berührt wird sie wieder klein, aber verliert kein Leben dadurch. Als besondere Herausforderung sind innerhalb des Spieles zwei versteckte Fragezeichenboxen platziert, die 1000 Punkte erbringen. - Zu beachten ist, dass die Karte immer dann gescrollt wird, wenn sich die Spielfigur in etwa der Mitte der Karte befindet. Damit wird der sichtbare Bildschirmausschnitt automatisch weiter nach rechts bewegt. Danach ist es nicht mehr möglich in den nun verdeckten linken Bereich der Karte zu gelange. - In der oberen linken Ecke werden zur Information der Punktestand und die Anzahl der verbleibenden Leben angezeigt. Besprochen in: - Abschnitt 5.2 und 8.2 Eingabemöglichkeiten: - „*“ Taste: beendet das Programm - „→“ oder „6“ Taste: Spielfigur läuft nach rechts - „←“ oder „4“ Taste: Spielfigur läuft nach links - „↑“ oder „2“ Taste: Spielfigur springt nach oben - „1“ Taste: Spielfigur springt nach links - „3“ Taste: Spielfigur springt nach rechts Christian Burmeister Anhang 52 8.4Zeitaufwand In diesem Abschnitt soll noch kurz auf die benötigte Zeit für die Erstellung dieser Ausarbeitung eingegangen werden. Tätigkeit Benötigte Zeit Informationsbeschaffung 30 Std. Programmierung der Beispiele 50 Std. Erstellung der Ausarbeitung 77 Std. Erstellung der Präsentation 8 Std. Gesamt 165 Std. Christian Burmeister Anhang 53 8.5Inhalt der CD-Rom An dieser Stelle soll noch kurz der Inhalt der beilegenden CD erläutert werden. Auf der CD befinden sich dabei die drei folgenden Ordner: (fettgedrückte Worte stellen jeweils Ordner/Dateien da) - - - Ausarbeitung o In diesem Ordner befindet sich zum einen die Ausarbeitung und zum anderen die Präsentation. o Formate: PDF-Datei -> Adobe Reader (AdbeRdr90_de_DE.exe) DOC-Datei -> Microsoft Word 2007 (WordViewer.exe) PPT-Datei -> Microsoft PowerPoint 2007 (PowerPointViewer.exe) o AusarbeitungChristianBurmeister.pdf o AusarbeitungChristianBurmeister.doc o PräsentationChristianBurmeister.pdf o PräsentationChristianBurmeister.ppt o Viewer Enthält Betrachtungsprogramme zum anzeigen der Ausarbeitung. PowerPointViewer.exe WordViewer.exe AdbeRdr90_de_DE.exe Beispiele o In diesem Ordner liegen die im Rahmen dieser Ausarbeitung erstellten Beispielprogramme. Dabei enthalten die Unterordner jeweils das komplette Eclipse-Projektverzeichnis. Im Ordner „Export-Vorlagen für TileStudio“ wurden die Export-Vorlagen abgespeichert die in Abschnitt 8.2 erwähnt wurden o JavaME_01_HelloWorld (Beschreibung in Abschnitt 8.3.1) o Game_01_GameLoop (Beschreibung in Abschnitt 8.3.2) o Game_02_WalkMario (Beschreibung in Abschnitt 8.3.3) o Game_03_WalkMarioTiles (Beschreibung in Abschnitt 8.3.4) o Game_04_WalkMarioTilesCollision (Beschreibung in Abschnitt 8.3.5) o Game_05_SuperMarioBros (Beschreibung in Abschnitt 8.3.6) o Export-Vorlagen für TileStudio format.tsd (Beschreibung in Abschnitt 8.2) format2.tsd (Beschreibung in Abschnitt 8.2) Internetquellen Christian Burmeister o Anhang 54 Dieser Ordner enthält die unter Abschnitt 7.2 aufgeführten Internetquellen in abgespeicherter Form. Die beiden Quellen [KARBACHER] und [NOKIASDK] befinden sich dabei nicht im diesen Ordner, weil der Umfang dieser Seiten zu groß waren.