Spieleentwicklung mit Android: Sorgenkind “Performance”

opt_frontDie Entwicklung von (kleineren) Spielen für die Android-Plattform ist selbst für Android-Neulinge (mit etwas Java-Erfahrung) kein großes Problem: Dank ausführlicher Beispiele und umfangreicher Dokumentation im SDK lassen sich schnell erste, ansehliche Ergebnisse erzielen. Vor allem, wenn man sich auf zwei Dimensionen beschränkt, genügen schon wenige Zeilen Code, um ein paar bewegte Grafiken auf das Display zu zaubern.
So konnte auch ich meine Idee zum Spiel Graviturn recht schnell in eine spielbare Anwendung umsetzen, die meine Vorstellungen von Bedienbarkeit und grafischer Ausgestaltung weitestgehend erfüllte. Allerdings tat sich mit steigender Komplexität ein recht unerwartetes Problem auf: Die Performance des Spiels wurde mit jeder zusätzlichen Zeile Code mieser und die Framerate erreichte irgendwann den inakzeptablen Bereich von 15-25 Frames pro Sekunde (man konnte also ein gewisses Ruckeln bei schnellen Bewegungen feststellen).
Über meine Erfahrungen auf dem Weg zu einem flüssigen, gut laufenden Spiel soll es daher nun im Folgenden gehen.

Google I/O 2009, Chris Pruett

Google I/O 2009, Chris Pruett

Die meisten wichtigen Hinweise und Tipps habe ich dabei aus dem wirklich sehr empfehlenswerten, englischen Video Google I/O 2009 – Writing Real-Time Games for Android von Chris Pruett (Lafzeit: 1 Stunde).

Threads + sauberer Code

Zwei wichtige Punkte habe ich “glücklicherweise” von Anfang an richtig gemacht: der gesamte für das Spiel relevante Code (Physik-Berechnungen, Zeichnen, Spiel-Logik) war in einem gesonderten Thread (sodass ein langsames Spiel nicht die Anwendung selbst bremst und unbedienbar macht), und mein Code war recht sauber gegliedert: getrennte Methoden für Physik/Zeichnen/Benutzereingabe/… sowie eine vernünftige Unterteilung der Spielelemente (Spielfeld, Spielelemente) in entsprechende Klassen. Vor allem letzteres erleichtert jeglichen Umgang mit dem Code natürlich ungemein – sollte aber ja auch bei jedem Programmierer Standard sein :)
Die weiteren Ausführungen beziehen sich jetzt stets auf den Teil des Spiels, der in erwähntem Thread läuft, sprich zigmal pro Sekunde abgearbeitet wird. Im Einzelnen also die Berechnung der Position der Objekte auf dem Spielfeld/des Spielers, Kollisionsberechnungen, das Zeichnen von Spielfeld/Spieler/Objekten usw.

Messbarer Erfolg?

Als ersten Schritt habe ich einen Zähler eingebaut, der die Zeit misst, die pro Frame zum Berechnen und Zeichnen benötigt wird, und diese Info alle paar Sekunden über die Debug-Konsole ausgibt ( Log.d(<String tag>, <String message>); ). Mit diesem Zähler war nun das Messinstrument für den Erfolg oder Misserfolg aller kommenden Optimierungen geschaffen.
Eine Ausgabe innerhalb des Spiels selbst (etwa als Text, der auf die Zeichenoberfläche geschrieben wird) ist übrigens nicht empfehlenswert, da man sonst mit dieser Messung das Ergebnis ja bereits verfälschen würde.

Speicherallokation und der Garbage Collector (GC)

Der GC ist ein echter Zeitfresser

Der GC ist ein echter Zeitfresser

So ziemlich das schlimmste, was man innerhalb der Spielroutine überhaupt machen kann, ist das allokieren von Speicher, sprich das Erzeugen neuer Variablen/Objektinstanzen.
Denn jedes Objekt wird irgendwann wieder durch den Garbage Collector freigegeben, sofern es nicht mehr benötigt wird. Üblicherweise wird der GC spätestens bei etwa 10.000-20.000 Objekte aktiv und gibt diese dann in einem Rutsch frei. Dies dauert jedesmal etwa 200-400ms! In dieser Zeit wird das Spiel (bzw. das ganze System!) deutlich ausgebremst und die Framerate bricht für einen Moment komplett ein.
Lösung: Eine Anwendung ohne Objektinstanzen? Natürlich nicht, schließlich müssen die Daten irgendwo verarbeitet und (zwischen-)gespeichert werden. Allerdings sollte man sämtliche Objekte, die man öfters benötigt, bereits zu Beginn des Spiels instanziieren und dann immer wieder darauf zugreifen. Das heißt konsequenterweise auch:

Verzicht auf lokale Objekte zugunsten von globalen Objekten.

Das widerspricht grundsätzlich erstmal jedem guten Programmierstil, schließlich büßt man dadurch Übersichtlichkeit und Flexibilität ein. Doch das Opfer lohnt sich, denn der Garbage Collector ist häufig die größte Performancebremse.
Bei Graviturn habe ich beispielsweise bei der Kollisionsberechnung (Ball -> Wand) sehr häufig mit Point-Objekten gearbeitet (zur Verarbeitung von x/y-Koordinaten), die in jedem Durchlauf bei Bedarf lokal erzeugt wurden. Das hat dazu geführt, dass etwa alle 1-2 Sekunden der Garbage Collector aktiv wurde, und diese Objekte freigegeben hat. Durch Nutzung von globalen Variablen oder simplen Datentypen (etwa zwei int für x und y) konnte dies drastisch reduziert werden.

Ein sehr nützliches Hilfsmittel ist dabei DDMS (”Dalvik Debug Monitor”) aus den Android-Tools. Der DDMS bietet einen sogenannten “Allocation Tracker“, der sämtliche Allokationen protokolliert und inklusive der Position im Quellcode ausgibt. Damit lassen sich auf einfache Weise alle unnötigen Allokationen ausmachen und beseitigen.

Allokationstracker bei Graviturn

Allokationstracker bei Graviturn


In meinem Fall konnte ich damit die Allokation auf ca. 100 Objekte alle 30 Sekunden beschränken. Da ein Level in meinem Spiel selten länger als ein bis zwei Minuten dauert, konnte ich den GC bequem zwischen den Leveln manuell auslösen ( System.gc(); ), wo dies nicht weiter störend ist.

Traceview verwenden (Android Profiler)!

Traceview der Zeichenroutine von Graviturn

Traceview der Zeichenroutine von Graviturn


Allen Performancebremsen, die sich mit den allgemeinen Tipps nicht beseitigen lassen, kommt man spätestens mit “Traceview”, einem sehr mächtigen Werkzeug aus der Android-Tool-Sammlung, auf die Schliche. Es handelt sich dabei um einen sehr übersichtlichen Profiler, welcher rekursiv für jede (!) Methode, die innerhalb des Messzeitraumes aufgerufen wurde, anzeigt, wieviel Zeit diese benötigt hat (absolsut und relativ, inklusive und exklusive deren Untermethoden).
Egal ob es eine langsame Kollisionserkennung, eine schlecht optimierte Zeichenroutine oder auch nur eine zu häufig durchlaufene Schleife ist: mit Traceview lässt sich jeder Flaschenhals aufspüren.
Die Verwendung ist allerdings nicht unbedingt trivial und würde den Rahmen dieses Artikels sprengen, einen guten Einstieg vermittelt der entsprechende Artikel im Dev Guide.

Noch ein paar allgemeine Tipps

  • Methodenaufrufe wenn möglich vermeiden
    Da Methodenaufrufe immer zusätzlich Zeit kosten, sollte man beispielsweise Variablen einer Klasse lieber public machen, anstatt get- und set-Methoden zu verwenden. Zwar “unsauber”, aber schneller.
  • Gleitkommazahlen (float) vermeiden.
    Je nach benötigter Genauigkeit könnten skalierte integer den entscheidenden Geschwindigkeitsvorteil bringen. Allerdings setze ich zugunsten der Flexibilität weiterhin Gleitkommazahlen ein.
  • statische Methoden verwenden so oft es geht
  • Keine Iteratoren verwenden
    So praktisch und hübsch sie auch sein mögen, für die Performance sind sie leider schlecht. Mit einer simplen Schleife oder dergleichen lässt sich dasselbe sparsamer erreichen.

Die Liste lässt sich schier beliebig erweitern (hier sei nochmal auf das Video verwiesen), genannt habe ich nur die Punkte, die ich selbst erfolgreich angewandt habe.

Fazit

Es macht Sinn, sich schon frühzeitig Gedanken über die Performance eines Spiels zu machen, um sich zeitraubende Nachbesserungen und Korrekturen am Ende der Entwicklung zu sparen. Gerade weil Android auf einer Vielzahl von unterschiedlichen Endgeräten laufen kann, ist es bei der Spieleentwicklung wichtig, stets ein Maximum an Optimierung herauszuholen, um auch auf schwächerer Hardware ein flüssiges und angenehmes Spielgefühl zu wahren.
Im Fall von Graviturn konnte ich mit den hier aufgezählten Tipps die Framerate von ca. 20 Frames pro Sekunde auf über 50 steigern, was genug Puffer darstellt, um auf allen gängigen Geräten befriedigend zu laufen.

Du kannst alle Antworten zu diesem Eintrag via RSS 2.0 Feed erfolgen. Du kannst einen Kommentar hinterlassen, oder einen Trackback von deiner eigenen Seite.

20 Kommentare »

 
  • Maniac sagt:

    Schöner Artikel und Anregung, danke. Hab mich zwar schon ausgiebig mit Android beschäftigt, aber mit den Tools noch nicht. Bei der App-Entwicklung ja auch nicht ganz so wichtig. Aber wird sicher auch dafür hilfreich sein und ich werds mir mal anschauen.

    Und mein Spiel wird leider aufgrund der “geklauten” (naja, abgeschauten) Idee leider nicht das Licht der Öffentlichkeit erblicken.

  • Maniac sagt:

    Ich habe die Idee von Flight Control (vom iPhone) genutzt… zwar nicht identisch nachgebaut (bei mir merkt man erst, ob das Flugzeug die Landebahn korrekt trifft, wenn es dort angekommen ist, nicht schon vorher per Farbcodierung usw.), aber halt doch die gleiche Idee und Umsetzung.

    Es gibt zwar keine Version für Android und soweit ich weiß, macht Firemint (der Hersteller) derzeit auch keine Anstalten, auf Android zu expandieren, trotzdem war mir das zu heikel und ich hab einfach mal eine Mail mit der Frage hingeschickt…

    Zurück kam immerhin was, nämlich dass sie mir keinen rechtlichen Rat geben können, aber Flight Control natürlich ein sehr wertvolles Gut wäre und sie es mit allen Möglichkeiten beschützen.

    Ich könnte es jetzt zwar riskieren und hoffen, dass es niemanden kratzt, (zumal es wohl sogar aufm iPhone einige Clones gibt) aber die Gefahr ist mir einfach zu groß…

    Von daher muss ich mir wohl was anderes ausdenken.

  • GM_Alex sagt:

    Also ich glaube nicht das die Idee das Spiels rechtlich geschützt ist, siehe Echtzeitstrategiespiele, Ego-Shooter etc. Sonst könnte es ja auch keine Fussballmanger von EA und Ascaron ohne Rechtsstreit geben. Ich bin mir ziemlich sicher das du dein Spiel unter einem frei erfundenen Namen ohne weiteres veröffentlichen kannst sofern du keine Grafiken, Sounds oder Namen von dritten Verwendest. Jedoch bin ich hier kein Experte.

    • flo sagt:

      Würde ich auch sagen… wenn sie nicht wirklich großen Aufwand betrieben haben und sich das schützen haben lassen (so wie z.B. das Brettspiel “Mensch ärgere dich nicht”), dürfte man das nachbauen dürfen. Erst recht natürlich, wenns kein 1:1-Clone ist.

      Fände ich auf jeden Fall sehr geil, wenns das Spiel auch für Android gäbe – wenn schon die Herstellerfirma das nicht machen will :/

  • Maniac sagt:

    Jo, danke für die Antworten…

    Prinzipiell denke ich das ja auch. Allerdings sind wir hier leider alle keine Experten und Anwälte. Und in Zeiten wo man sich sogar eine Farbe schützen kann (magenta ;) ) bin ich mir da echt nicht so sicher…

    Zumal ich das dann wohl auch gern als 99 Cent App rein stellen, also damit auch ein paar Cents verdienen möchte. Sowas ruft dann natürlich erst recht die Neider und ggf. die Firma auf den Plan.

    Wobei ich wie gesagt gelesen habe, dass sogar im Apple-Store n Clone existieren soll, der sogar recht weit oben in den Charts ist (also demnach sicher auch bekannt). Und genauso habe ich das gleiche Spielprinzip mit nem Hafen und Schiffen schon gesehen.

    Nur wie gesagt, ne Sicherheit kann mir keiner geben… und ich muss keinen teuren Rechtsstreit oder Abmahnung am Hals haben. :(

    Grafiken, Sounds oder Namen hab ich natürlich nicht kopiert / genutzt. Aber das Spielprinzip ist halt schon das gleiche… (bisher) 3 Flugtypen (Jumbo, Propellor, Hubi), 2 Landebahnen, 1 Helipad. Und man kann den Flugzeugen per Finger ihre Route zuweisen. Keine Ahnung, ob das schon soviel schöpferische Höhe hat, das man es sich schützen kann… das nächste Problem ist ja auch, dass die Firma ja nun in USA sitzt und da teilweise ganz andere Rechte / Gerichte gelten… wenn es nur um D ginge, könnte ich meinen Anwalt wohl fragen, was er dazu meint. Aber so ist mir das echt recht heikel…

    P.S. kannst Du hier mal einrichten, dass man per Mail auf neue Kommentare hingewiesen wird? Irgendwann vergesse ich einfach, immer wieder nachzuschauen…

    • flo sagt:

      E-Mail-Benachrichtigungen sollten jetzt aktivierbar sein (ungetestet), gute Idee :)

      Das Game-Enginge-Prinzip ist so ähnlich, aber nicht streng in dieser Baumform etc. (habe das Video ja erst später gesehen).
      Von Replica Island weiß ich leider auch noch nix, würde mich aber auch mal interessieren (zumal das Spiel selbst ja auch sehr nett aussieht).

      @Forum: Leider nicht, soweit ich weiß. Das Thema wird irgendwie eh recht stiefmütterlich behandelt in den Communities. Es gibt ja eigentlich nur einzelne Threads mit sehr speziellen Fragen, aber leider nichts allgemeines …

      • Maniac sagt:

        Na gut, wenn Du da nen Thread aufmachst oder so, sag bescheid, finde das ganze auch verdammt spannend.

        Vor allem auch den Bereich künstliche Intelligenz. Hatte mich letztens mal etwas tiefer mit dem Algorythmus für “Brettspiele” usw. (Alpha-Beta) befasst. Dass ich es ganz verstanden habe, kann ich aber noch nicht behaupten… :(

        Vor allem basiert das auf Rekursion, was ja den obigen Angaben (Methoden-Aufrufe und Objekt-Erzeugungen vermeiden) ein wenig widerspricht.

        Leider funktioniert der KI-Algo für mein Spiel auch noch nicht wirklich… weiß aber noch nicht so recht, ob es an der Bewertungsfunktion oder dem Algorythmus liegt.

        Ich hätte auch Lust, ein Spiel gemeinsam zu entwickeln…

        Also wenn Du ne Idee hast oder sowas, gerne her damit oder nen Thread aufmachen oder so.

        Nebenbei hier mal die Mail-Benachrichtigung testen… :)

        • Maniac sagt:

          Ok, das war eigentlich auch zu einfach, mal kurz gegooglet:
          http://www.replicaisland.net/

          Nur leider noch nichts zu sehen… nur 3 Einträge im Blog, die ganz interessant sein könnten, werd ich mir jetzt mal zu Gemüte führen…

        • flo sagt:

          Ja, sobald ich mal wieder die Muse dazu habe, werd ich mal einen Thread aufmachen (im Moment bastel ich wieder mal an Graviturn, mal schauen, ob sich eine erweiterte Version verkaufen lässt). Du verkaufst doch deine Anwendungen auch, in welcher Größenordnung liegen denn da die Verkäufe bzw. die Install-Rate (im Market sieht man ja nur die Downloads, aber viele davon werden wohl innerhalb eines Tages zurückgeben und bringen damit nix) – wenn man fragen darf.

          @ReplicaIsland: Die Blogeinträge waren ja wirklich ziemlich interessant :) Zwar nix, was mir momentan weiterhilft, aber wie auch schon das Video ein sehr lehrreicher Einblick :)

          • Maniac sagt:

            Joa, das Verkaufen ist ja bei Android offenbar gar nicht so einfach, es sind ja auch noch vergleichsweise wenige Android-Geräte im Umlauf und viele Leute haben keine Kreditkarte oder wollen sie nicht nutzen oder leben in einem Land, wo noch keine Paid-Apps unterstützt werden. Da gingen in den letzten Tagen ein paar Berichte durch die Blogs und Twitter. Gesehen? Sonst such ich nochmal den einen oder anderen Link raus.

            Wobei ich bei mir mit der Installrate sehr zufrieden und eigentlich schon sehr überrascht bin. Derzeit sind es laut Developer Console 79% active installs. Die refund-Quote ist gefühlt sehr niedrig. Und von den Refundern sind offenbar ein großer Teil, die “mein Prinzip” (Add-on, was sich nicht selbst starten lässt) nicht verstanden (gelesen) haben und bei der Meldung “Anwendung konnte nicht gestartet werden” es deinstallieren und neu installieren…

            Wobei es aber vermutlich auch daran liegt, dass es ja eine “echte Produktivitäts-App” ist, die man langfristig nutzt und nicht nur ein kurzweiliges Spiel.

            Außerdem habe ich es ja zwischenzeitlich auch schon auf Platz 3 in meiner Kategorie geschafft (womit ich nie gerechnet hätte) und das ist dann natürlich auch wieder Werbung und in gewisser Weise ein Selbstläufer…

            Ich selbst hab auch schon einige Apps, aber vor allem auch Spiele getestet, die recht schnell langweilig wurden und ich demnach refunded habe.

            Also der Trick, bzw. die Kunst ist wohl wirklich Langzeitmotivation zu schaffen, was gerade bei Spielen nicht so einfach ist.

            Graviturn wirkt auf mich z.B. sehr professionell und ansprechend, von der Gestaltung und Optik (Grafik ist leider so gar nicht meins, was mich auch noch stark von Spieleprogrammierung abhält, viele meiner Commenter sagen ja auch, mein Icon wäre häßlich). Aber irgendwie fehlt mir am Spiel auch noch der letzte Kick und die Motivation, länger zu spielen, auch wenn Du Dir mit den weg klickbaren Elementen usw. ja schon gute Variationen ausgedacht hast.

            Jedenfalls ist es derzeit halt noch recht schwer und wenn überhaupt dann wohl nur ein netter Nebenverdienst. Allerdings glaube ich auch, dass es in nächster Zeit noch sehr viel besser wird, je mehr Geräte auf dem Markt und verkauft sind. Außerdem sind ja schon größere Änderungen am Market angekündigt und angeblich auch neue Bezahlmethoden, was noch mit am wichtigsten wäre. Gerade vielleicht auch bei Dir, weil Spiele ja auch eher von jüngeren Nutzern gespielt werden, die vielleicht noch keine Kreditkarte haben usw.

            Auch ist ja die Überlegung Werbung vs. Paid-App… auch da gabs letztens mal ein Vergleich, dass Werbung wohl mehr gebracht hätte. Auch den Link kann ich nochmal raus suchen. Wobei ich persönlich bei Werbung auch immer so einen faden Beigeschmack habe…

            Also alles nicht so einfach und trivial zu beantworten…

            Ja, die Blogeinträge zu ReplicaIsland fand ich auch sehr interessant, wenn ich auch zugeben muss, dass ich einiges nicht ganz kapiert habe, zum Teil vielleicht ein wenig die Sprache Schuld (kann aber eigentlich gut englisch), zum anderen aber auch von der Technik kann ich es mir noch nicht so ganz vorstellen. Deshalb würde ich ja gerne mal den Code dazu sehen…

            P.S. die Mailbenachrichtigung läuft super, sonst hätte ich hier vermutlich nicht mehr rein geschaut.

  • Maniac sagt:

    Nachtrag noch zum Thema:
    Hast Du eigentlich das gleiche Game-Engine Prinzip genutzt wie Chris im Video vorgestellt hat? Also so einen Baum usw.?

    Und hat er das Replica Island jetzt irgendwo im Source veröffentlicht? Den Code würde ich gern mal sehen, weil ich bei solchen Dingen teilweise echt noch stocke, bzw. nach best practices oder sowas suche.

    Mein Spiel läuft soweit aber jedenfalls in der aktuellen Version auch ohne explizit die Tipps zu nutzen schon recht flüssig mit im Schnitt 40-60 FPS. Zeichnung per Canvas. Hab ja aber auch nur ne begrenzte Zahl an Objekten und scheinbar schon von mir aus auf einige Optimierungen geachtet. Obwohl da sicher auch noch mehr rauszuholen wäre…

    Gibt es eigentlich schon irgendwo im Forum n Thread oder Unterforum für Spieleentwicklung? Wäre sicher interessant, sich da auszutauschen.

  • Lukas Klamm sagt:

    Unsauber = schneller. Leider wahr. Mein Lieblingsprinzip. =)

  • GM_Alex sagt:

    @flo & Maniac: Kostet es auch etwas kostenlose Apps über den Market anzubieten? Mir fehlt zwar im Moment noch die Idee für eine App, weil ich bisher noch nichts vermisst habe, aber vielleicht passiert das ja noch und dann würde ich es gerne der Allgemeinheit zur Verfügung stellen. Aber wenn das was kosten würde wäre das suboptimal.^^

    • Maniac sagt:

      Ja, man muss sich als Entwickler registrieren, was einmalig 25$ kostet.

      Wobei es mittlerweile auch schon haufenweise Webseiten mit alternativen Market-Angeboten gibt (z.B. andappstore.com). Da ist halt nur das Problem, dass die nicht so verbreitet und nicht über den mitgelieferten Market erreichbar sind. D.h. da müssten sich die User erst ne Market-App für diese Alternativen installieren.

      Du könntest natürlich auch einfach die apk-Datei irgendwo auf nen Webserver laden und somit zum Download anbieten. Aber auch da wirst Du halt vermutlich nicht die Reichweite haben, wie über den Google Market…

      Juhu, mein Galaxy rebootet gerade… :( aber das nur am Rande…

      • GM_Alex sagt:

        Na gut 25$ hält sich ja noch in Grenzen. Dann muss ich halt mit meinem Wordpress-Plugin noch etwas Geld verdienen bzw. gespendet bekommen.^^

        • Maniac sagt:

          Joa und mit ein wenig Glück holst Du Dir die 25$ auch mit Werbeeinblendungen oder einer Paid-App wieder rein.

          Finde das noch fair. Im Apple-Store geht die Anmeldung bei 99$ los…

          • GM_Alex sagt:

            Naja Werbung in Anwendungen hasse ich, das will ich keinem antun, aber ein Paid-App mit extra Features für 1$ oder so das wäre auch was.

  • Lars sagt:

    Habe mal eine Frage braucht der Aufruf des GC (System.gc();) immer so viel Zeit oder nur wenn die von dir genannten 10.000-20.000 Objekte freigegeben werden, warum ruft man dann nicht den GC jede Sekunde auf, dann würden vielleicht nur so 1-2 Objekte freigegeben und die Verzögerung dürfte nur sehr klein ausfallen oder nicht?

    (Habe bisher selbst nicht für Android programmiert, möchte das aber demnächst angehen…)

  • “Das hat dazu geführt, dass etwa alle 1-2 Sekunden der Garbage Collector aktiv wurde, und diese Objekte freigegeben hat” – was meinst du damit?

 

Einen Kommentar hinterlassen

XHTML: Diese Tags kannst Du benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>