Projects Case Study
KOMOREBI: ein Arcade-Spiel, das nur aus einem Tipp besteht
Ein schnelles Tap-Tap-Kill für Android in Godot 4.7. Acht Kapitel, Endlos-Modus, prozedurale Grafik und prozeduraler Sound, ohne Assets, ohne Werbung, ohne Internet.
Ein Spiel mit einem einzigen Verb#
Es gibt eine Klasse von Spielen, die auf eine einzige Geste zusammengefällt: antippen. Lädt eine Figur an der passenden Stelle, und sie zerfällt. Mehr braucht die Steuerung nicht, mehr braucht sie auch nicht.
KOMOREBI ist genau so ein Spiel, und die Designfrage war deshalb nicht „welche Mechanik baue ich“, sondern: wie viel Substanz bekommt eine Mechanik, bevor sie langweilig wird?
Die Antwort lag in der Mechanik selbst. Kombo, kritische Treffer, Mehrfach-Treffer, drei Gaben und Gegner, die unterschiedliche Aufmerksamkeit verlangen. Ein Finger, fünf Arten ihn zu belohnen – oder zu bestrafen.
| KOMOREBI | |
|---|---|
| Werbung | keine |
| In-App-Käufe | keine |
| Login / Konto | keins |
| Tracking / Analytics | keines |
| Internet zum Spielen | nicht nötig, vollständig offline |
| Berechtigungen | keine |
| Server | keiner |
| Cloud-Speicherung | keine |
| Sterne, Bestwerte, Kapitel-Freischaltung | lokal in user://komorebi.cfg |
Die Regel ist eine Zeile#
Zerstöre die Schatten, bevor das Licht erlischt.
Daraus folgt der ganze Loop: Schatten treiben aus der Dunkelheit ins Bild, man tippt sie weg, hält die Kombo am Laufen und sammelt Gaben ein, bevor die Zeit abläuft. Jedes Kapitel hat eine Soll-Zahl an Schatten und ein Zeitlimit. Erreicht oder nicht – der Screen zeigt Sterne, der nächste Versuch ist einen Tipp entfernt.
Die Zeit ist der einzige Gegner. Es gibt keine Lebensenergie, keinen Herzverlust, keine Game-Over-Sequenz mit Tod. Nur eine Uhr, die leerläuft.
Fünf Gegner, fünf Arten Aufmerksamkeit#
Der eigentliche Inhalt des Spiels sind nicht die Kapitel, sondern die Gegner. Jeder verlangt eine andere Sorte von Blicken:
| Gegner | Verhalten | Punkte | Was ihn interessant macht |
|---|---|---|---|
| Schatten | treibt langsam | 10 | Ein Tipp, und er zerfällt |
| Funkenleiter | zickt, stößt in kurzen Schüben | 16 | muss abgewartet werden |
| Splitter | treibt langsam | 20 | zerfällt beim Tod in drei Scherben (je 6) |
| Panzerschatten | sehr langsam | 30 | drei Treffer; beim Tod eine Sprengladung, die alle Nachbarn mitnimmt |
| Großer Schatten | pendelt zur Mitte | 150 | Kapitel-Boss mit 6–8 zu löschenden Kerzen |
Der Panzerschatten ist das Beispiel für eine Regel, die weitergreift: Seine Sprengladung macht Nachbarn zu Bonusmaterial. Wer ihn im dichten Feld killt, räumt auf – wer ihn in der Ecke killt, verliert nur die eigenen Punkte. Das Verhalten ist damit nicht nur Kosmetik, sondern eine echte Entscheidung.
Kombo, Kritisch, Mehrfach#
Drei Mechaniken tragen das Scoring, und alle drei hängen an derselben Frage: war das letzte Drittel einer Sekunde gut?
Kombo. Jeder Treffer ohne Fehlgriff erhöht die Kombo, mit einem Fenster von 2,6 Sekunden. Ab vier Treffern steigt der Multiplikator Schritt für Schritt bis ×9. Ein Fehlgriff bricht die Kette – nicht den Lauf, aber das Momentum. Genau das ist der Unterschied zwischen einem weiteren Treffer und einem lohnenden.
Kritisch. Mit wachsender Kombo werden Treffer häufiger kritisch: doppelte Punkte, weißer Blitz, Goldring und eine kurze Zeitlupe. Die Belohnung ist nicht nur Zahl, sie ist spürbar.
Mehrfach. Mehrere Schatten innerhalb von 0,3 Sekunden ergeben einen Bonus – und ein sichtbares „MEHRFACH x3“ auf dem Bildschirm. Gerade das ist in einem Spiel ohne Maus wichtig: ein Treffer, den man nicht sieht, ist ein Treffer, den man nicht wiederholt.
Gaben, die den Takt ändern#
| Gabe | Farbe | Wirkung |
|---|---|---|
| Sonnenstich | bernstein | 5 s doppelte Punkte |
| Reif | cyan | alle Gegner fliegen deutlich langsamer |
| Kette | mint | die nächsten 6 Töte zünden durch und reißen Nachbarn mit |
Reif ist die interessanteste, weil sie nichts gibt, sondern das Spiel verlangsamt. In einem Arcade-Spiel, in dem die Zeit ohnehin gegen einen läuft, ist „weniger Druck“ eine rare und starke Gabe.
Acht Kapitel und ein Endlos-Modus#
| # | Name | Soll | Zeit | Neu |
|---|---|---|---|---|
| 1 | Erster Schein | 14 | 45 s | Schatten |
| 2 | Glutflug | 20 | 45 s | Funkenleiter |
| 3 | Splitternebel | 22 | 45 s | Splitter |
| 4 | Panzerlicht | 24 | 45 s | Panzerschatten |
| 5 | Dämmerung | 28 | 48 s | alles, dichter |
| 6 | Kagura | 18 + Boss | 55 s | Großer Schatten (6 Kerzen) |
| 7 | Nebelsturm | 32 | 48 s | härteste Mischung |
| 8 | Großer Schatten | 22 + Boss | 60 s | Endgegner (8 Kerzen) |
Die Kurve beginnt mit einem Gegnertyp und einem kleinen Soll, damit der erste Treffer überhaupt landet, und endet mit dem Endgegner. Jedes Kapitel vergibt bis zu drei Sterne über Score-Schwellen: ein Stern ist das sichere Abschaffen, drei Sterne verlangen eine gehaltene Kombo. Das ist eine bewusste Abstufung – die meisten Spieler werden einen Stern holen, und wer drei will, muss die Kette spielen, nicht nur tippen.
Dahinter wartet der Endlos-Modus: 60 Sekunden, eine einzige Frage – wie weit kommst du.
Kein Fremd-Asset, kein Audio-Asset#
Bei den bisherigen Spielen habe ich als einzigen Fremdbestandteil eine Schrift verwendet. Bei KOMOREBI bleibt es bei genau einem:
Grafik ist vollständig prozedural. Gegner, Partikel, Ringe, Blitze, der animierte Dämmerungs-Hintergrund, Sterne und das Logo werden zur Laufzeit gezeichnet. Kein PNG im Projekt, das auf eine DPI verloren gehen könnte, keine Ladezeit, keine fehlenden Assets.
Sound ist vollständig prozedural. Alle 15 Effekte werden beim Start aus reinen
Funktionen in AudioStreamWAV-Puffer gerendert. Kein Audio-Asset, keine Abhängigkeit,
und – das ist der eigentliche Grund – dasselbe Ergebnis auf jedem Gerät.
Die Schrift ist Inter (SIL OFL 1.1). Eine einzige Ausnahme, dokumentiert in
assets/fonts/README.md.
Regeln und Darstellung getrennt#
Die technische Entscheidung, die ich am meisten schätze: arena.gd weiß nichts über
Punkte oder Level, game_screen.gd weiß nichts über Treffer-Geometrie. Beide
kommunizieren über Signale.
Das klingt trocken, hat aber einen konkreten Effekt. arena.gd ist headless lauffähig
und wird es auch – deshalb kann das Spiel sich selbst durchspielen:
godot --headless --path . -- --autoplay=6 # bis Kapitel 6
godot --headless --path . -- --autoplay=endless # Endlos-Modus
godot --headless --path . -- --notap # Game-Over-Pfad
godot --headless --path . -- --maxsec=45 # ZeitlimitEin Spiel, das sich selbst durchspielen kann, braucht für Logik, Persistenz und Levelwechsel keinen Emulator. Kein Android, kein GL-Kontext, kein Gerät.
Testbarkeit als Feature#
Der zweite Teil ist der unangenehmere, der mehr gekostet hat. Ein automatisierter Gameplay-Test auf dem Emulator, der weiß, wo die Knöpfe sind.
Der naïve Ansatz wäre, Screenshots per Farb-Heuristik zu lesen. Der funktioniert nicht, weil ein Tipp zeitlich schwer zu treffen ist. Die Lösung: Das Spiel schreibt Knopf- und Gegenpositionen inklusive Skalierung nach Logcat. Der Test liest diese Werte, statt zu raten – und prüft Screenshots als zweite, unabhängige Quelle.
# ENEMY_POS meldet viermal pro Sekunde ein vollständiges Bild
# aller lebenden Figuren – Spawn-Zeilen allein sind zu alt,
# weil die Gegner driften.Genau dieser Satz hat Stunden gekostet. Ein Test, der nur Spawn-Zeilen auswertet, prüft eine Welt, die es nicht mehr gibt.
Der Test umfasst rund 40 Prüfschritte: App-Start und Titelbildschirm inklusive Bildhelligkeit, Hauptmenü, Levelauswahl, Kapitel-Intro, HUD, Pause und Fortsetzen, Mehrere Treffer mit Bildbeleg, Kombo-Aufbau, der Nachweis dass ein Fehlgriff den Score nicht verändert, Gaben und ihre Aktivierung, Kapitelabschluss mit Sternen, Levelwechsel, Game Over durch Zeitablauf, Persistenz nach App-Neustart, Endlos-Modus – und am Ende ein Logcat-Scan auf echte Fehler, Exceptions und Script-Fehler.
Screenshots und Logcat-Auszüge landen in artifacts/.
60 statt 20 Bilder pro Sekunde#
Ein Detail, das mir mehr Zeit gekostet hat als jedes Leveldesign: der Hintergrund.
Die erste Fassung zeichnete den Dämmerungsgrund mit Geometrie – die Lichtschäfte als 48 einzelne gefüllte Streifen, alles live im Frame. Auf dem Emulator kostete dieser Aufbau rund zwei Drittel der Bildzeit.
vorher: 20 Bilder/s
nachher: 60 Bilder/sOptisch ist es identisch. Die Lösung: der Grund wird mit 30 Hz in eine Textur gezeichnet, die Lichtschäfte liegen als ein einziges texturiertes Trapez darüber statt als 48 Flächen. Zwei Änderungen, ein Faktor drei.
Ich habe es nicht gemerkt, weil es auf dem Desktop flüssig lief. Der Emulator war die richtige Investition – nicht für den Test, sondern für die Performance.
Keine Geheimnisse im Repository#
Der Release-Key liegt lokal, nicht im Repository. signing/ steht vollständig in
der .gitignore, und ./tools/build_android.sh release bricht ab, solange
signing/komorebi-upload.jks fehlt:
./tools/make_release_keystore.sh # erzeugt Key + Passwortdatei
./tools/build_android.sh release # APK + AAB bauen und prüfenEs wird niemals ein Debug-Key als Release ausgegeben. Das Passwort wird nur für die
Dauer des Exports in export_presets.cfg eingetragen und danach wieder entfernt
(tools/release_keystore.py). Kein Secret-Wert gehört in eine versionierte Datei.
Für wen das nach Overkill klingt: eine verlorene .jks bedeutet, dass die App später
nicht mehr signierbar ist – sofern Play App Signing den App-Key nicht selbst verwaltet.
Ein Debug-Key als Release zu nehmen, ist ein Fehler, den man erst sehr spät bemerkt.
Build, Test, Release#
Ein Skript, neun Einstiegspunkte:
./tools/build_android.sh emulator # AVD starten
./tools/build_android.sh debug # Debug-APK, schnelle Schleife
./tools/build_android.sh build # Release-APK
./tools/build_android.sh aab # App Bundle
./tools/build_android.sh release # APK + AAB, technisch geprüft
./tools/build_android.sh install # Release-APK auf emulator-5554
./tools/build_android.sh run # starten, Screenshot + Logcat
./tools/build_android.sh test # vollständiger Gameplay-Test
./tools/build_android.sh analyze # apkanalyzer / bundletoolinstall, run und test verwenden standardmäßig die Release-APK, weil nur sie dem
Play-Artefakt entspricht. Mit KOMOREBI_TEST_APK=debug läuft die schnellere Schleife.
Diese eine Umgebungsvariable ist der Unterschied zwischen einem Test, der das
auslieferbare Artefakt prüft, und einem, der etwas anderes prüft.
Was ich daraus gelernt habe#
Eine Regel ist stärker als eine Feature-Liste. „Zerstöre die Schatten, bevor das Licht erlischt“ hat mehr Entscheidungen geprägt als jede Aufzählung von Mechaniken. Als Einstieg habe ich nicht „Was braucht ein Arcade-Spiel?“, sondern „Was widerspricht dieser einen Zeile?“ gestellt. Die Antworten waren das Spiel.
Prozedural ist nicht automatisch schlank. Der Hintergrund war prozedural, korrekt gezeichnet – und kostete zwei Drittel der Bildzeit. „Machen wir es prozedural“ ist eine Entscheidung über die Herkunft der Daten, nicht über deren Laufzeit.
Ein Test, der sich nicht verhalten lässt, testet Farben. Die erste Version des Gameplay-Tests war Screenshot-Heuristik und damit wertlos. Erst als das Spiel seine eigenen Positionen meldete, wurde daraus ein Test. Das ist Aufwand im Spiel – und der teuerste Teil des ganzen Projekts.
Release-Signatur ist Teil des Produkts. Kein Key im Repository, kein
Debug-Key-Fallback, kein Passwort in export_presets.cfg. Drei Zeilen Skript, ein
Problem weniger für immer.
Grenzen#
Es ist kein echter Play-Upload erfolgt. Die App ist gebaut und geprüft; was fehlt, sind Dinge, die kein Code erledigt: der Eintrag in der Play Console, Store-Texte, Screenshots auf echten Geräten und – falls gewünscht – ein eigener App-Key.
Der Emulator ist nicht die Wahrheit. Der Emulator auf diesem Host beendet sich unter Last gelegentlich selbst (GL-Kontext). Der Test erkennt das als Umgebungsproblem und bricht sauber ab – aber es heißt, dass die 40 Prüfschritte ihre Aussage auf einer Umgebung treffen, die man nicht kontrolliert.
Eine Eingabefalle bleibt. Godot erzeugt aus jedem Touch zusätzlich ein emuliertes Mausereignis. Eine kurze Eingabesperre direkt nach Rundenende fängt das ab. Auf echten Geräten ist das Fenster deutlich kleiner als die Latenz zwischen den Ereignissen – aber es bleibt eine Korrektur, keine Lösung.
Der Titelbildschirm ist eine Vorschau, kein Spiel. Er zeigt eine kuratierte Auswahl der Gegnerformen, drifting statt spielbar. Absicht, aber eine Einschränkung: der erste Eindruck zeigt nicht, wie sich das Spiel anfühlt.
GLES 3 heißt GLES 3. gl_compatibility läuft überall dort, wo Godot läuft – und
nicht überall dort, wo eine schnelle GPU existiert. Das ist eine bewusste Wahl für
Reichweite, keine für Höchstleistung.
Für ein ähnliches Projekt – ein kompaktes Android-Spiel oder Tool, das ohne Werbung, ohne Konto und ohne Server auskommen soll – gibt es den Weg über haasarts.de.
Quelle
Dieses Projekt
KOMOREBI ist Teil meiner Referenzen. Hier geht es zum Projekt auf haasarts.de.