Bequemer als Backup Bequemer als Backup - Wuala
Bequemer als Backup Bequemer als Backup - Wuala
Bequemer als Backup Bequemer als Backup - Wuala
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
Know-how | Spieleprogrammierung mobil<br />
chen passieren: Ein Handy-Besitzer,<br />
der gerade mit Spielen beschäftigt<br />
ist, erhält beispielsweise<br />
genau dann eine SMS. Die<br />
Folge: Die Anzeige der Nachricht<br />
verdeckt die Grafikausgabe des<br />
Spiels. Das Programm sollte auf<br />
solche Situationen damit reagieren,<br />
dass es automatisch die<br />
Spieleschleife unterbricht und<br />
sie erst dann erneut startet,<br />
wenn das Spiel wieder sichtbar<br />
wird. Dies lässt sich relativ leicht<br />
über die von GameCanvas geerbte<br />
Methode MobileFishCanvas.showNotify()<br />
realisieren: Das System ruft<br />
sie automatisch immer dann auf,<br />
wenn die Ausgabefläche sichtbar<br />
wird. Sie startet einen neuen<br />
Thread, der nichts anderes tut,<br />
<strong>als</strong> die Spieleschleife in MobileFish-<br />
Canvas.run() zum Laufen zu bringen:<br />
gameLoop = new Thread(this);<br />
gameLoop.start();<br />
Die Methode hideNotify(), das<br />
Gegenstück zu showNotify(), wird<br />
von der Umgebung aufgerufen,<br />
wenn das Spiel im Display eben<br />
nicht mehr sichtbar ist, und killt<br />
daraufhin den aktuellen Thread<br />
mit<br />
gameLoop = null;<br />
Die Spielschleife in der run()-Methode<br />
läuft, solange der aktuelle<br />
Thread noch vorhanden ist und<br />
nicht auf null gesetzt wurde.<br />
Die Schleifendurchläufe sollten<br />
möglichst in ungefähr gleichen<br />
Zeitabständen erfolgen,<br />
damit immer gleich viele Bilder<br />
pro Sekunde auf das Display<br />
kommen und es in den Bewegungen<br />
der Spielfiguren kein für<br />
den Anwender sichtbares Ruckeln<br />
gibt. Das Programm unterteilt<br />
eine Sekunde in gleichlange<br />
Zeitscheiben (engl. Ticks). In<br />
jeder dieser Zeitscheiben ruft es<br />
einmal die update()-Methode zum<br />
Aktualisieren der Spielewelt und<br />
einmal die render()-Methode zum<br />
Zeichnen auf. Ohne dieses Eintakten<br />
wäre die Ablaufgeschwindigkeit<br />
des Spiels von der Rechenleistung<br />
des konkreten Handys<br />
abhängig. Das Programm<br />
müsste dann bei jeder zeitabhängigen<br />
Berechnung einer Bewegung<br />
die im aktuellen Schleifendurchlauf<br />
vergangene Zeit mit<br />
einbeziehen, was alles ziemlich<br />
verkomplizieren würde.<br />
Die run()-Methode stoppt am<br />
Anfang der while-Schleife die Uhrzeit<br />
und ermittelt nach einem<br />
Durchlauf, wie lange er gedauert<br />
hat:<br />
long timeTaken =<br />
System.currentTimeMillis() - startTime;<br />
Ist nach getaner Arbeit noch Zeit<br />
über, wartet sie die restliche Zeit<br />
einfach ab:<br />
if(timeTaken < MILLIS_PER_TICK) {<br />
Thread.sleep(<br />
MILLIS_PER_TICK - timeTaken);<br />
}<br />
Die Konstante MILLIS_PER_TICK<br />
steht für die Anzahl der Millisekunden,<br />
die für einen Schleifendurchlauf<br />
vorgesehen sind, und<br />
gibt damit auch vor, wie viele Bilder<br />
pro Sekunde auf dem Display<br />
erscheinen.<br />
Das einzige, was in der Spieleschleife<br />
außer Aufrufen von update()<br />
und render() noch passiert, ist<br />
ein Aufruf der Methode flushGraphics().<br />
Diese von GameCanvas geerbte<br />
Methode bewirkt, dass alles,<br />
was in der render()-Methode gezeichnet<br />
wurde, letztendlich auf<br />
dem Display erscheint. Denn alle<br />
Zeichenoperationen werden<br />
vom API automatisch erst einmal<br />
in einen gesonderten Speicherbereich<br />
umgeleitet, damit der<br />
Anwender nichts vom Erstellen<br />
des Bildes mitbekommt. Erst<br />
flushGraphics() schiebt alles von diesem<br />
Zwischenspeicher in einem<br />
Rutsch auf das Display.<br />
Akteure<br />
Alle im Spiel vorkommenden Figuren<br />
und Hintergrundgrafiken<br />
sind von der abstrakten Basisklasse<br />
Layer abgeleitet. Eine Figur,<br />
die aus einem einzelnen Bild besteht<br />
wie etwa der Fisch, ist von<br />
der davon abgeleiteten Klasse<br />
Sprite. Dieser Begriff ist eine Reminiszenz<br />
an das Mittelalter der Informatik<br />
– auch bei C64 & Co.<br />
gab es schon Sprites.<br />
Da selbst ein einfaches Spiel<br />
schon zwanzig und mehr Spielfiguren<br />
haben kann, gibt es in<br />
Ereignis „wird in<br />
Display sichtbar”<br />
Ereignis „ist nicht mehr<br />
in Display sichtbar”<br />
Grafische Handy-Spiele<br />
sind nach einem recht einfachen<br />
Bauplan konstruiert.<br />
Die Hauptarbeit leistet die<br />
Spieleschleife, hier in der<br />
Methode run().<br />
Java ME eine eigene Klasse LayerManager<br />
zum unkomplizierten<br />
Verwalten und Darstellen der<br />
Layer. Dadurch gestaltet sich die<br />
render()-Methode relativ einfach:<br />
private void render() {<br />
Graphics g = getGraphics();<br />
layerManager.setViewWindow(<br />
camera.x, camera.y,<br />
getWidth(), getHeight());<br />
layerManager.paint(g, 0, 0);<br />
// ...<br />
}<br />
Als Erstes holt sie sich den Grafikkontext,<br />
eine Instanz der Klasse<br />
Graphics. Dieser ist die Schnittstelle<br />
zwischen dem Programm und<br />
den eigentlichen Grafikausgaben.<br />
Die danach aufgerufene Set-<br />
ViewWindow()-Methode des Layer-<br />
Manager legt den Bereich fest, der<br />
aktuell im Handy-Display dargestellt<br />
wird. Ihre ersten beiden Parameter<br />
geben die Position des<br />
auszugebenden Ausschnitts innerhalb<br />
der Spielewelt vor. Dieser<br />
hängt von der aktuellen<br />
Spielsituation ab und wird daher<br />
von einer eigenen Klasse (Camera)<br />
verwaltet – mehr dazu weiter<br />
unten. Der dritte und vierte Parameter<br />
definieren die Höhe und<br />
Breite des Ausschnitts. Die hier<br />
verwendeten Methoden get-<br />
Height() und getWidth() gehören zur<br />
Klasse GameCanvas und geben Auskunft<br />
über die maximale Größe<br />
des konkreten Handy-Displays.<br />
Die paint()-Methode des Layer-<br />
Manager gibt schlussendlich den<br />
definierten Ausschnitt auf den<br />
Grafikkontext in der Position<br />
(0, 0) aus. Durch diese Position<br />
und die oben verwendeten<br />
Werte mit der maximalen Größe<br />
des Displays wird die komplette<br />
Anzeigefläche des Handys verwendet.<br />
Das Einlesen der Bilddateien<br />
und die Initialisierung des Layer-<br />
Manager erledigt die Init()-Methode<br />
des MobileFishCanvas. Der Ablauf ist<br />
MobileFischCanvas<br />
(GameCanvas)<br />
init()<br />
alle benötigten<br />
Objekte erstellen<br />
showNotify()<br />
hideNotify()<br />
Spieleschleife beenden<br />
run()<br />
update()<br />
render()<br />
update()<br />
render()<br />
Schleife<br />
starten<br />
Während der Entwicklungsphase<br />
tummelt sich Freddy,<br />
der Fisch, in einem Handy-<br />
Emulator, den die Entwicklungsumgebung<br />
NetBeans bereits<br />
mitbringt.<br />
für jede Spielfigur der gleiche.<br />
Als Erstes erzeugt das Programm<br />
ein neues Objekt vom Typ Sprite:<br />
freddy = new Sprite(<br />
Image.createImage("/Freddy.png"));<br />
Dieses benötigt zum Initialisieren<br />
die Bilddatei. In diesem Beispiel<br />
befinden sich alle Bilder zusammen<br />
mit den Java-Klassen in<br />
einer einzigen JAR-Datei.<br />
freddy.setPosition(16, 184);<br />
Die Argumente von setPosition()<br />
sind die Koordinaten innerhalb<br />
des LayerManager. Erst bei der Ausgabe<br />
rechnet dieser automatisch<br />
die x- und y-Werte passend für<br />
die gewählte Ausgabefläche um.<br />
layerManager.append(freddy);<br />
Schließlich gibt Init() das Sprite<br />
noch dem aktuellen LayerManager<br />
bekannt. Die Initialisierung der<br />
anderen grafischen Elemente erfolgt<br />
nach einem sehr ähnlichen<br />
Strickmuster. Ein wichtiges Prinzip<br />
ist, dass das zuletzt hinzugefügte<br />
Element – im Beispielprogramm<br />
das Hintergrundbild –<br />
später immer zuerst gezeichnet<br />
wird. Die Fisch-Figur, das erste<br />
Element des LayerManager, ist<br />
damit der oberste Layer und verdeckt<br />
die danach hinzugefügten<br />
Bilder. Das Programm erreicht<br />
c’t 2008, Heft 20<br />
©<br />
Copyright by Heise Zeitschriften Verlag GmbH & Co. KG. Veröffentlichung und Vervielfältigung nur mit Genehmigung des Heise Zeitschriften Verlags.<br />
199