Start Magazin Android-Spiele mit Monkey entwickeln

Android-Spiele mit Monkey entwickeln

In Ausgabe 11/2012 zeigten wir Ihnen, wie Sie mit dem App Game Kit unkompliziert ein Android-Spiel erstellen. Zu diesem Kit existiert jedoch auch ein Konkurrenzprodukt: Monkey Coder. Wir stellen den Monkey vor.

Während auf der einen Seite das App Game Kit sehr beliebt ist, hat auf der anderen Seite auch die Programmiersprache Monkey unter Smartphone-Spieleentwicklern eine treue Anhängerschaft gefunden. Doch welche der beiden Sprachen ist besser für den persönlichen Geschmack geeignet? Welche für Anfänger, welche für Fortgeschrittene? Dies werden wir im folgenden Artikel untersuchen, indem wir das Spiel vom letzten Mal ("Apple Shooter") erneut entwickeln – diesmal in der Programmiersprache Monkey. Optimalerweise haben Sie hierfür bereits den Workshop zum App Game Kit aus der Ausgabe 11/2012 durchgearbeitet. Dort wurde besprochen, wie Spiele im Allgemeinen aufgebaut sind, und wie diese mit dem App Game Kit im Speziellen ihre Umsetzung finden. Geübt wurde dies anhand eines Spieles, bei dem Äpfel durch Touch-Bewegungen auf dem Bildschirm abgeschossen werden – unserem "Apple Shooter" (Abbildung 1 und 2). Wir werden nun diese Spielidee ebenfalls mit Monkey umsetzen – auf diese Weise sehen Sie die Unterschiede zu der internen Konzeption des App Game Kits.

Abbildung 1: Das Startbild unseres selbst entworfenen Spiels Apple Shooter.
Abbildung 1: Das Startbild unseres selbst entworfenen Spiels Apple Shooter.

Abbildung 2: Anders als bei der Umsetzung mit dem App Game Kit nutzen wir diesmal eine verspieltere Schriftart.
Abbildung 2: Anders als bei der Umsetzung mit dem App Game Kit nutzen wir diesmal eine verspieltere Schriftart.

Installation und Vorarbeiten

Zunächst einmal muss die Demo-Version von Monkey heruntergeladen und auf einem Windows-PC entpackt werden [1]. Deren Einschränkung besteht darin, dass sie ausschließlich HTML5-Spiele für den Browser generieren kann. Für Testzwecke und zum Durcharbeiten dieses Workshops ist dies vollkommen ausreichend. Wer die Vollversion besitzt (Kostenpunkt: 99 Euro), kann mit Monkey zusätzlich das eigene Spiel – unter anderem – als Android-APK-Datei exportieren. Die HTML5 und Android-Variante sehen dabei exakt gleich aus und verhalten sich auch identisch, obwohl für sie derselbe Programmcode geschrieben wurde (das App Game Kit ist übrigens ebenfalls in der Lage, ein identisches Spiel ohne Mehraufwand für verschiedene Betriebssystem-Plattformen zu generieren).

Während das App Game Kit über viele eingebaute, vom Hersteller mitgelieferte Funktionen verfügt, ist das Konzept von Monkey ein anderes: Dieses verfügt zwar über eine ausgeklügelte Sprache, doch die Anzahl der bereits enthaltenen Befehle ist eher überschaubar. Doch in diese Nische sind ein paar Fans der Sprache gesprungen: Dritte Entwickler, die nicht zum Hersteller gehören, haben den Sprachumfang durch selbstgeschriebene externe Bibliotheken (so genannte Module) erweitert. Für unser Apple-Shooter-Spiel ist es daher nötig, dass wir diese zusätzlichen Module installieren.

Laden Sie hierzu die erforderlichen ZIP-Dateien ([2], [3], [4]) herunter. Entpacken Sie die Datei autofit.zip in das modules-Unterverzeichnis von Monkey. Das hierbei automatisch erstellte Verzeichnis autofit2 benennen Sie danach in autofit um. Aus diddy.zip ist nur der Ordner diddysrcdiddy nach modules zu entpacken, nicht die Verzeichnishierarchien oberhalb – ansonsten findet Monkey später dieses Modul nicht. Für Fontmachine erstellen Sie den Unterordner fontmachine und entpacken das zugehörige ZIP dort hinein. Nun sollten sie im Verzeichnis modules die folgenden, neuen Unterverzeichnisse vorfinden (zusätzlich zu den vom Hersteller bereits mitgelieferten Modulen): autofit, diddy und fontmachine.

Quellcode zum Download

Den Quellcode zum hier vorgestellten Spiel finden Sie unter Link 5 auf der Android-User-Homepage zum Download.

In dem Ordner bananas ihrer Monkey-Installation werden die Quellcodes selbstentwickelter Spiele (wie auch die vom Hersteller mitgelieferten Beispiele) abgelegt. Erstellen Sie dort für unser Spiel das Unterverzeichnis AppleShooter. Innerhalb von diesem ist nochmal der Ordner AppleShooter.data anzulegen. Dort wird unsere App später nach Spielegrafiken, Sounds und Schriftarten suchen. Die Spielegrafiken und Sounds (welche bereits beim Workshop zum App Game Kit zu ihrem Einsatz kamen) kopieren Sie von der Android-User-Homepage in das AppleShooter.data-Unterverzeichnis. Nun fehlt uns noch eine Schriftart, um später die erreichten Punkte und verbleibende Anzahl in Sekunden anzuzeigen. Hierfür ist aus modulesfontmachinesample programsample02.data das Unterverzeichnis SportsFont als Ganzes nach bananasAppleShooterAppleShooter.data zu kopieren.

Abbildung 3: Die Entwicklungsumgebung von Monkey nach dem Starten.
Abbildung 3: Die Entwicklungsumgebung von Monkey nach dem Starten.

Die Umsetzung in Monkey

Die eigentliche Programmierumgebung (Abbildung 3) startet nach einem Doppelklick auf monkey.exe. Mit File | New legen Sie ein neues Projekt an. Wählen Sie hier als Zielverzeichnis bananasApple Shooter aus, der zu vergebende Dateiname für unseren Programm lautete AppleShooter.monkey. Nun kopieren Sie den Quellcode am besten aus dem Download [5] oder schauen sich Listing 1 an. Doch was bedeuten all diese Zeilen? Hierfür wollen wir uns erstmal den Grundaufbau eines Monkey-Spieles anschauen (Abbildung 4):

Abbildung 4: Nach dem Start folgen mit Monkey erstellte Apps diesem Schema.
Abbildung 4: Nach dem Start folgen mit Monkey erstellte Apps diesem Schema.

Beim Start der App wird der Methodenblock OnCreate() aufgerufen. Dieser kümmert sich um alle einmaligen Aktionen, die als Initialisierung des Programms nötig sind – in der Regel also das Laden von Spielgrafiken und -sounds in den Speicher. Danach wird von nun an in einem bestimmten, vom Programmierer festgelegten Intervall (zum Beispiel 10 Mal pro Sekunde) das Unterprogramm OnUpdate() aufgerufen. Dort legt der Entwickler alle Befehle ab, welche die eigentliche Spielsteuerung übernehmen. Das Spiel wertet hier beispielsweise Benutzerinteraktionen (wie das Berühren des Bildschirms) aus oder prüft, ob eine Änderung des Spielzustands eingetreten ist. Wenn noch genug Prozessorzeit vorhanden ist, ruft die App nach OnUpdate() automatisch OnRender() auf. Dieses Unterprogramm ist für das Neuzeichnen des Bildschirms verantwortlich. Es werden also die (gegebenenfalls zuvor von OnUpdate veränderten) Spielvariablen wie die aktuelle Punktzahl, der derzeitige Spielzustand oder die Position der Spielfigur ausgelesen, und anhand dieser die dazu passenden Zeichenbefehle aufgerufen. Falls Sie ein rasantes Action-Spiel geschrieben haben, welches 60 Mal pro Sekunde OnUpdate aufruft, kann es auf langsamen Smartphones der preiswerteren Klasse nun passieren, dass diese zu langsam sind, um jedesmal OnRender() im Anschluß zu starten. Das ergibt in diesem Fall, dass Ihr Spiel auf solch einem Handy mit einer niedrigeren Framerate als den angestrebten 60 Herz ausgegeben wird. Monkey strebt dann aber trotzdem an, zumindest OnUpdate() 60 Mal pro Sekunde zu durchlaufen, damit zumindest der Spielablauf nicht unter den Beschränkungen des Geräts leidet. Hinter dieser Konstruktion steckt auch der moderne Ansatz, Spiellogik und graphische Ausgabe voneinander zu trennen. Dies erleichtert unter anderem ebenfalls eine spätere Wartung des Programmcodes. Werfen wir nun einen Blick darauf, wie die konkrete Umsetzung der Apple-Shooter-Spielidee aus Heft 11/2012 in Monkey aussieht. Den Quellcode ( Ausschnitt) zeigt Listing 1.

Listing 1

Der Quellcode

#ANDROID_APP_LABEL="Apple Shooter"
#ANDROID_APP_PACKAGE="com.AppleShooter"
#ANDROID_SCREEN_ORIENTATION="landscape"
Import mojo
Import autofit
Import diddy
Import fontmachine
Function Main ()
  New AppleShooter()
End
Class AppleShooter Extends App
  Field Spielstatus:String
  Field ApfelPositionX, ApfelPositionY:Int
  Field SpielerHatZeitBis, Punkte, SekundenUebrig:Int
  Field PunkteSchriftart:BitmapFont
  Field Hintergrundbild:Image
  Field GameOverSchriftzug:Image
  Field KnopfNeuesSpiel:Image
  Field ApfelBild:Image
  Field TitelLogo:Image
  Field Schuss:Sound
  Field Explosion:Sound
  Field DrueckenTon:Sound
  Field GameOverSFX:Sound
  Method OnCreate ()
    SetUpdateRate(10)
    SetVirtualDisplay (800, 480)
    Seed = RealMillisecs()
    SetChannelVolume(1,1)
    Hintergrundbild = LoadImage("hintergrundbild.png")
    GameOverSchriftzug = LoadImage("gameover.png")
    KnopfNeuesSpiel = LoadImage("knopfNeuesSpiel.png")
    ApfelBild = LoadImage("apfel.png")
    TitelLogo = LoadImage("titellogo.png")
    PunkteSchriftart = New BitmapFont("SportsFont/SportsFont.txt", True)
    Schuss = LoadSound ("schuss.wav")
    Explosion = LoadSound ("explosion.wav")
    DrueckenTon = LoadSound ("knopfGedrueckt.wav")
    GameOverSFX = LoadSound ("gameover.wav")
    PlayMusic("hintergrundmusik.mp3")
    Spielstatus = "Anfangsbildschirm"
    StartwerteFuerSpielSetzen ()
  End
  Method StartwerteFuerSpielSetzen ()
    ApfelPositionX = 300
    ApfelPositionY = 70
    SpielerHatZeitBis = RealMillisecs()/1000 + 20
    Punkte = 0
  End
  Method OnUpdate ()
    If Spielstatus="Anfangsbildschirm" Or Spielstatus="Game Over"
      If  ( (TouchHit() > 0) And (VTouchX() >= 250) And (VTouchY() >= 350) And (VTouchX() <= 550) And (VTouchY() <= 450) )
        PlaySound(DrueckenTon,1)
        StartwerteFuerSpielSetzen()
        Spielstatus="Action!"
      Endif
      Return
    Endif
    If Spielstatus="Action!"
      SekundenUebrig = SpielerHatZeitBis - RealMillisecs()/1000
      If SekundenUebrig = 0
        PlaySound(GameOverSFX,1)
        Spielstatus="Game Over"
      Else
        If (TouchHit() > 0)
          PlaySound(Schuss,0)
          If ( (VTouchX() >= ApfelPositionX) And (VTouchY() >= ApfelPositionY) And (VTouchX() <= ApfelPositionX + 199) And (VTouchY() <= ApfelPositionY + 200) )
            PlaySound(Explosion,1)
            ApfelPositionX = Floor( Rnd(1,600) )
            ApfelPositionY = Floor( Rnd(1,280) )
            Punkte = Punkte + 50
          Else
            Punkte = Punkte - 50
          Endif
        Endif
      Endif
      Return
    Endif
  End
  Method OnRender ()
    UpdateVirtualDisplay
    Cls 0, 0, 0
    DrawImage(Hintergrundbild,0,0)
    If Spielstatus="Anfangsbildschirm"
      DrawImage(TitelLogo,60,140)
      DrawImage(KnopfNeuesSpiel,250,350)
    Else
      PunkteSchriftart.DrawText("Punkte: " + Punkte,0,0)
      PunkteSchriftart.DrawText("Zeit: " + SekundenUebrig + " Sekunden",0,40)
    Endif
    If Spielstatus="Action!"
      DrawImage(ApfelBild,ApfelPositionX,ApfelPositionY)
    Endif
    If Spielstatus="Game Over"
      DrawImage(GameOverSchriftzug,100,150)
      DrawImage(KnopfNeuesSpiel,250,350)
    Endif
  End
End
Abbildung 5: Ein Teil des Codes unseres Apple Shooters im Quelltext-Editor.
Abbildung 5: Ein Teil des Codes unseres Apple Shooters im Quelltext-Editor.

Mit einem Druck auf F5 können Sie das Spiel nun als HTML5-Version in einem Internet-Browser testen. Mit der Vollversion ist es möglich, das eigene Smartphone per USB-Kabel an den Computer anzuschließen, und nach Drücken von Run direkt darauf das Spiel auszuprobieren. Ebenfalls kann sie eine komplette APK-Datei generieren, um die eigene Kreation an Dritte weiterzugeben. Für einen Test reichen jedoch im Prinzip die Demoversion und ein Internet-Browser aus. Das Spiel läuft also nun – doch was hat es mit den Inhalten der Codezeilen (Abbildung 5, Listing 1) auf sich?

Zeile 1-3 legt Android-spezifische Angaben fest, wie beispielsweise den Namen des Spiels in der App-Übersicht, oder dass es im Landscape-Modus dargestellt wird. Anschließend werden alle benötigten Module (Zeile 5-8) importiert, damit uns auch die Befehle zur Verfügung stehen, die wir brauchen. Die Funktion Main() markiert nun den eigentlichen Beginn des Programms – diese startet unseren Programmkern, indem das Objekt AppleShooter erschaffen wird (Zeile 11). Doch was beinhaltet dieses überhaupt? Dies wird ab Zeile 14 definiert: Hier deklariert der Ausdruck extends App, dass für unseren "Apple Shooter" der Aufbau der Klasse App Pate stand – und diese schreibt unter anderem die Methoden OnCreate(), OnUpdate() und OnRender() vor.

In den Zeilen 15 bis 29 werden alle benötigten Variablen definiert und ihr Typ festgelegt (also beispielsweise, ob es sich um eine Zeichenkette oder eine Zahl handelt). Die nun folgende Methode OnCreate() definiert, dass 10 Mal pro Sekunde OnUpdate() und anschließend OnRender() aufgerufen werden (SetUpdateRate), initialisiert den Zufallsgenerator, und lädt Spielegrafiken sowie -sounds. Abschließend ruft es das Unterprogramm StartwerteFuerSpielSetzen() auf, welches wir zwischen den Zeilen 54 und 59 definieren. Dieses setzt die Startwerte eines Spiels (Punkte=0). Das Auslagern in ein eigenes Unterprogramm hat den Vorteil, dass wir auch zu einem späteren Zeitpunkt im Programm ein neues Spiel starten können, indem StartwerteFuerSpielSetzen() aufgerufen wird.

Die in Intervallen automatisch gestartete Methode OnUpdate() erstreckt sich anschließend von Zeile 62 bis 94: Die Logik ist hierbei im Groben dieselbe wie bei der Umsetzung für das App Game Kit aus dem letzten Heft – abhängig vom Spielstatus wird entweder auf das Drücken der Schaltfläche "Neues Spiel starten" getestet (Zeile 64-71), oder es wird während eines laufenden Spiels reagiert (Zeile 73-92): Wenn die Zeit abgelaufen ist, dann beende das Spiel (Zeile 74-77). Läuft das Spiel hingegen noch und der Spieler hat einen Apfel abgeschossen, dann belohne ihn mit 50 Punkten (Zeile 78-85). Hat er danebengetippt? Dann sind 50 Strafpunkte abzuziehen (Zeile 86-87). Besonders beachtenswert sind bei dieser Methode die Zeilen 65 und 81: Anders als beim App Game Kit lässt sich nicht vereinfacht abfragen, ob ein bestimmte Sprite berührt wurde – stattdessen ist es in Monkey vonnöten, etwas umständlicher zu testen, ob eine Bildschirmberührung innerhalb des Quadrates lag, an der sich die entsprechende Grafik befindet. Allerdings liesse sich theoretisch auch für Monkey ein eigenes Unterprogramm schreiben, welches dieses Vorgehen vereinfacht.

App Game Kit oder Monkey?

Beide Produkte erlauben, mit ein und demselben Code ein Spiel für unterschiedliche Plattformen (wie z.B. Android und iOS) zu entwickeln. Ferner gestaltet sich bei beiden der Entwicklungsprozess oft kürzer, als dies etwa in Java oder Objective-C der Fall wäre. Für Anfänger scheint das App Game Kit die bessere Wahl zu sein. Es ist einfach zu installieren, gut und anschaulich dokumentiert, und kann nach einer einfachen, auch für Fachfremde verständlichen Struktur programmiert werden. Die Foren des Herstellers bieten ebenfalls Menschen mit wenigen Vorkenntnissen unkomplizierte Hilfe an. Anders sieht dies bei Monkey aus: Dieses bietet unter der Haube viel Potential, bringt aber wenig eingebaute Funktionen mit. Dies wird zwar durch die von Dritten programmierten Module mehr als kompensiert, doch dürfte es nicht jedem Anfänger liegen, bei der Installation zuerst einmal alle benötigten Erweiterungen im Internet zusammenzusuchen.

Der Aufbau von Monkey-Apps wirkt auf Fortgeschrittene sauberer und professioneller, auch lässt sich die Programmiersprache intern besser erweitern. In den Monkey-Foren wird tendenziell auf einem höheren technischen Niveau diskutiert – für Profis interessant, für den Durchschnittsmenschen, der einfach nur schnell und unkompliziert sein erstes eigenes Spiel fertigstellen möchte, hingegen eher hinderlich. Es sollte jedoch berücksichtigt werden, dass es beim App Game Kit neben der anfängerfreundlichen, einfachen Basic-Sprache optional auch eine sogenannte Tier 2 gibt: Dort werden Spiele in C++ entwickelt und die App-Game-Kit-Befehle als externes Framework zur Verfügung gestellt. Überhaupt versuchen die beiden Produkte auf Grund ihrer gegenseitigen Konkurrenzsituation, mit jeder neuen Version die eigenen Schwächen auszubügeln: So wird Monkey zunehmend übersichtlicher, und das App Game Kit lässt mehr Komplexität zu. Zum jetzigen Zeitpunkt lautet die Empfehlung jedoch noch: Einsteiger sollten eher zum App Game Kit greifen, Fortgeschrittene eher zu Monkey. Vor einem Kauf ist es unabhängig davon ratsam, zuerst einmal von beiden die jeweiligen Demoversionen ausprobiert zu haben. Nur so können Sie feststellen, was Ihrem persönlichen Geschmack entspricht.

Kommentiere den Artikel

Please enter your comment!
Please enter your name here