Projects Case Study
Mini Mysteries: ein Detektivspiel ohne Zeitdruck
20 Detektivfälle in fünf Kapiteln für Kinder von 6 bis 12 Jahren. Keine Timer, keine Leben, falsche Tipps nie fatal. Kotlin, Jetpack Compose, 67 Unit-Tests.
Beobachten ist die Fähigkeit#
Ein Detektivspiel für Kinder steht und fällt mit einer einzigen Frage: Was macht dieses Spiel, wenn das Kind nicht weiterkommt?
Nicht: Es zeigt einen Hinweis und zählt einen Fehlversuch. Sondern erklärt es freundlich, welcher Hinweis noch fehlt, und lässt es erneut versuchen. Der Unterschied zwischen diesen beiden Varianten ist der Unterschied zwischen einem Spiel, das ein Kind fünf Minuten spielt, und einem, das es eine Woche lang spielt.
Also stand am Anfang kein Level, sondern eine Liste von Dingen, die nicht drin sein werden:
- keine Timer, keine Countdowns
- keine Leben, keine Energie
- keine Wartezeiten, keine täglichen Belohnungen
- keine künstliche Frustration
- kein falscher Tipp, der irgendetwas kostet
Milo löst durch Hinsehen#
Die Figur ist Milo, ein kleiner Detektiv mit Hut, Mantel und Lupe. Kein Superheld, kein Kämpfer. Milo löst Probleme ausschließlich durch genaues Hinsehen.
Die Kernschleife:
Szene untersuchen → Gegenstände antippen → Hinweise sammeln
→ im Notizbuch ansehen → Beweise kombinieren
→ Aussagen vergleichen → Schlussfolgerung treffen
→ Fall lösen → Abzeichen und Sammelobjekt erhaltenJede Szene wird vollständig aus Code gezeichnet. Tippt man auf ein Objekt, öffnet sich eine kurze Beschreibung, und passt ein Hinweis dazu, landet er automatisch im Notizbuch. Falsche Tipps kosten nichts.
20 Fälle, fünf Kapitel#
| Kapitel | Fälle | Ton |
|---|---|---|
| 🏠 Das Zuhause | 5 | verschwundene Gegenstände, Familienmissverständnisse |
| 🏫 Die Schule | 5 | Widersprüche in Aussagen, kleine Gaunereien |
| 🌳 Der Park | 4 | Fußabdrücke, Wind, Wasser |
| 🏛 Das Museum | 3 | Dinge, die jemand genauer anschauen wollte |
| 🎉 Das geheimnisvolle Fest | 3 | Luftballons, Musikbox, Kerzen |
Die inhaltliche Linie ist streng: keine Gewalt, keine Waffen, kein Tod, keine Entführungen, keine Kriminalfälle, keine Horror-Ästhetik. Die „Täter" sind am Ende immer Katzen, Hunde, Mäuse, Luftballons, ein Roboterstaubsauger, der Wind, ein Kleinkind oder ein freundliches Missverständnis.
Jede Auflösung ist so gebaut, dass niemand dafür beschimpft wird. Das ist nicht nur Anstand, sondern Gestaltungsauftrag: Ein Fall, in dem ein Kind am Ende ermahnt wird, ist ein Fall, den ein Kind nicht fertigspielt.
Fälle sind Daten, nicht Code#
Die Architekturentscheidung, die das Projekt am längsten getragen hat: Ein Fall ist ausschließlich Daten. Für die Engine muss nie etwas geändert werden.
case("park_05", Chapter.PARK, 5, "Der verschwundene Regenschirm") {
teaser = "Der Regenschirm steht nicht mehr im Spind."
scene("Sonnenschutz", Backdrop.PARK) {
prop("spind", PropShape.LOCKER, 0.3f, 0.6f, 0.2f, 0.3f, z = 2)
}
hotspot("nass", "Nasser Abdruck", evidence = "ev_nass")
combo("c_a_b", "ev_nass", "ev_x", "ev_ergebnis")
conclusion(
prompt = "Wo ist der Regenschirm?",
required = listOf("ev_nass", "ev_ergebnis"),
correct = "a",
options = listOf(opt("a", "…", "…"), opt("b", "…", "…")),
)
hint(Difficulty.JUNIOR, 1, "…", highlight = "nass")
}Eine kleine DSL, damit Fälle nur Daten sind. Und weil die Schwierigkeitsgrade über
difficulties = setOf(...) am Hotspot hängen, bekommt der Junior-Modus automatisch weniger
relevante Gegenstände – ohne dass ein zweiter Fall geschrieben werden muss.
Der Validator ist das Gegenstück dazu. CaseValidator.validate(fall) prüft Verweise,
Rechtecke, Antwortlisten, Hinweisziele und Belohnungen. Der Test CaseLibraryTest lässt alle
20 Fälle durchlaufen. Ein neuer Fall mit kaputtem Verweis fällt damit sofort auf.
Schwierigkeitsgrade, die sich nicht wie Zusatzinhalte anfühlen#
Jeder Fall hat Hinweise für beide Grade, und die unterscheiden sich in der Substanz:
| Junior-Modus | Detektiv-Modus | |
|---|---|---|
| Hinweisstufe 1 | Bereich hervorheben | nur Richtung |
| Hinweisstufe 2 | kleine Hilfe | kleine Hilfe |
| Hinweisstufe 3 | konkreter Hinweis | konkreter Hinweis |
| Interaktive Objekte | alle | gefiltert |
Dazu kommt ein bewusst kleines Detail: Im Junior-Modus bekommen noch nicht untersuchte Objekte einen dezenten, langsam pulsierenden Ring. Im Detektiv-Modus gibt es den nicht. „Interaktive Objekte gut erkennbar" ist eine Anforderung, keine Dekoration.
Barrierefreiheit, die aus dem Spielprinzip folgt#
Viele Spuren sind winzig gezeichnet – ein Faden, ein Löchlein in der Wand. Beim Antippen wird die Fläche deshalb auf mindestens 0,14 × 0,18 der Szenengröße vergrößert, auf einem Telefon im Querformat rund 44 × 34 dp. Überlappungen gewinnt das Objekt, dessen Mitte näher liegt.
Weiter im Detail:
- Schriftgrößen folgen der Systemeinstellung, Kontraste sind dunkel auf hell
- Information wird nie nur über Farbe vermittelt: geprüfte Objekte bekommen ein grünes Symbol, Hervorhebungen zusätzlich einen pulsierenden Rahmen, Sterne eine Form
- „Weniger Bewegung" schaltet alle Endlos-Animationen tatsächlich ab
- Ton, Musik und Haptik sind einzeln schaltbar
- der Elternbereich ist durch eine Rechenaufgabe geschützt
Eine vollständige Bedienung rein über Screenreader ist bewusst nicht umgesetzt. Das Spiel ist ein Beobachtungsspiel; die Szene trägt eine Kurzbeschreibung mit Namen und Anzahl der untersuchbaren Gegenstände.
Offline, diesmal mit einer einzigen Berechtigung#
Das Manifest enthält genau eine Permission: android.permission.VIBRATE – eine normale
Berechtigung für das optionale haptische Feedback, die bei der Installation automatisch
gewährt wird und keinen Dialog zeigt. Damit kann die App technisch keine Netzwerkverbindung
öffnen, auch wenn eine Abhängigkeit es versuchen würde.
Der Fortschritt liegt über DataStore im privaten App-Daten, allowBackup="false" verhindert
Cloud-Backup und Geräte-Übertragung. Die App prüft nicht einmal, ob Internet verfügbar ist –
es gibt keinen Code dafür.
67 Unit-Tests, 11 UI-Tests#
| Datei | Tests | Inhalt |
|---|---|---|
CaseLibraryTest |
10 | 20 Fälle, 5 Kapitel, Datenintegrität, Belohnungen, IDs |
CaseEngineTest |
24 | Untersuchen, Kombinieren, Hinweisstufen, Sterne, jeder Fall in beiden Graden lösbar |
StorageTest |
14 | JSON-Roundtrip, kaputte Daten, vier Profile, Zurücksetzen, Spielzeit |
GameViewModelTest |
15 | Navigation, vollständiges Spielen, Profilwechsel, Speichern |
ParentGateTest, ProfilesTest |
4 | Rechenaufgaben, Profil-Hilfsfunktionen |
Der interessanteste Test ist der letzte Teil von CaseEngineTest: jeder Fall muss in
beiden Graden vollständig lösbar sein. Das schließt den Fehler aus, dass ein Hinweisziel
existiert, aber nicht erreichbar ist.
Auf dem echten Gerät (SM-G975F, Android 12) sind 11 instrumentierte UI-Tests grün geworden. Dabei gefunden und behoben: zu hohe Inhalte auf niedrigen Landscape-Fenstern (360 dp Höhe) sowie eine Endlos-Animation, die Compose-Testläufe blockierte.
Was ich dabei gelernt habe#
Ein Spiel für Kinder ist eine Aussage über Erwartungen. Alles, was nicht auf dieser Liste steht, muss man bewusst weglassen – und das ist mehr Arbeit als das Hinzufügen.
Datengetriebene Fälle skalieren besser als handgeschriebene Logik. Bei 20 Fällen ist das noch lösbar, aber der Validator macht den Unterschied sichtbar: Die häufigste Fehlerquelle in Spielen mit many cases sind nicht die Algorithmen, sondern die kaputten Verweise.
Landscape ist eine Produktentscheidung. Szenen brauchen Breite; im Hochformat wäre die Szene so klein, dass die Spuren ihre Vergrößerung bräuchten.
Ein Release-Buildtype mit Development-Signatur ist eine gute Idee. assembleRelease läuft
so lokal ohne Geheimnisse durch. Für die Veröffentlichung wird der signingConfig auf einen
eigenen Keystore umgestellt – im Repository liegt bewusst kein privater Schlüssel.
Grenzen#
Die Oberfläche ist nur auf Deutsch ausgelegt, die Falldaten müssten für weitere Sprachen zusätzlich angelegt werden. Eine vollständige Bedienung über Screenreader fehlt. Die Spielzeit wird beim Wechsel in den Hintergrund gespeichert; bei einem erzwungenen Beenden fehlt die laufende Sitzung.
Und es gibt keine Export- oder Importfunktion für Profile. Das ist Absicht – keine Datenübertragung – heißt aber auch: Ein Gerätewechsel erfordert erneutes Spielen.
Die Referenz auf haasarts.de zeigt das Projekt im Zusammenhang. Ähnliche Projekte – ruhig, offline, kindgerecht – gerne über den Kontakt.
Quelle
Dieses Projekt
Mini Mysteries ist Teil meiner Referenzen. Hier geht es zum Projekt auf haasarts.de.