23.04.2014 Aufrufe

Bequemer als Backup Bequemer als Backup - Wuala

Bequemer als Backup Bequemer als Backup - Wuala

Bequemer als Backup Bequemer als Backup - Wuala

MEHR ANZEIGEN
WENIGER ANZEIGEN

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!