Road To 1.1.0
# Roadmap: Abyss Empire – Der Schrecken der Tiefe
## Status-Legende
- [ ] offen · [~] in Arbeit · [x] abgeschlossen
---
# Version 1.0.1 – Performance-Feintuning (nach Release 1.0.0)
Post-Release-Analyse des 1.0.0-Stands (Release-Soak: avg 1,36 ms/Frame,
Regelbetrieb 0,5-0,7 ms bei 16,7 ms Budget = 3-4 % Auslastung, overBudget
im Regelbetrieb 0). Die Grundlast ist exzellent - verbleibende
Optimierungspotenziale sind Feintuning in drei Kategorien.
## Analyseergebnis (Code-Verifizierung gegen den 1.0.0-Stand)
### Kategorie A: Startzeit (hoechste Prioritaet)
- [x] **A1 - SoundEngine-WAV-Generierung blockiert den App-Start:**
GameView-Konstruktor (UI-Thread!) erzeugt synchron 11 WAV-Dateien
(10 Effekte + 8-s-Ambient-Loop mit 176k Samples je 16-bit) plus
File-I/O nach cacheDir. Sichere Schaetzung: 50-150 ms Startverzoegerung
auf Mittelklasse-Geraeten. Fix: Generierung in einen Hintergrund-
Thread verschieben, SoundEngine.play() faellt solange still zurueck
(bereits id-basiert fehlertolerant). Sprites.ensure() ebenfalls
pruefen, ob Bitmap-Erzeugung im Konstruktor messbar ist
(4 Bitmaps, vermutlich < 5 ms - bewerten).
Umsetzung: SoundEngine laedt WAVs im "SoundLoader"-Thread (loaded-
AtomicBoolean, play() still bis bereit, Musikstart per musicRequested
nachgezogen); Timing-Log dokumentiert die Generierungskosten.
Sprites.ensure() in den Render-Thread verschoben (vor dem Loop,
erste Frames nutzen Kreis-Fallback).
Messung (Release-Builds, frisch gebooteter Emulator, am start -W,
je 3 Runs): 1.0.0 Median 273 ms (417/258/273) vs. 1.0.1 Median
251 ms (309/232/251). WAV-Generierung auf dem Geraet: 57-111 ms -
dieser Anteil ist nicht mehr im Startpfad (in 1.0.0 blockierte er
den UI-Thread in onCreate).
### Kategorie B: Frame-Spikes (Welt-Reset-Ereignisse)
- [x] **B1 - saveGame() auf dem Render-Thread (14,7-ms-Spikes):**
Die worst-Fenster im Release-Soak stammen von restartRound()/gameOver():
JSON-Bau (9 Sektoren, Gebaeude, Rudel, Instinkte, Tutorial) +
String-Serialisierung + SharedPreferences-apply laufen im Render-Frame.
Fix: Save-Auftrag mit konsistentem Snapshot an einen Worker-Thread
(Single-Thread-Executor); Autosave bleibt alle 10 s, aber der
Render-Thread uebergibt nur den eingefrorenen Zustand. Kritisch:
Snapshot muess vor Abgabe atomar sein (Game-Zustand waehrend der
Serialisierung kann sich aendern - daher erst alle Werte kopieren,
dann serialisieren).
Umsetzung: saveGame() friert SaveSnapshot (reine Datenkopien,
Gebaeude je Sektor gruppiert) ein und reicht ihn an den
"SaveWorker"-Executor; Serialisierung + saveStore.save laufen dort.
saveGameNow() speichert synchron - GameView.pause() nutzt es
(App-Kill vor Worker-Flush ausgeschlossen). flushSaves() erlaubt
Tests, asynchrone Autosaves deterministisch zu pruefen; neuer
Konsistenz-Test asyncSaveFreezesStateAtCallTime sichert die
Atomizitaet (Mutation nach Snapshot bleibt ungespeichert).
### Kategorie C: Mikro-Allokationen im Render-Pfad (niedrige Prioritaet)
- [x] **C1 - RectF-Allokation je drawBitmap (~30/Frame):**
Player/FishSchool (3 je Schwarm)/Attacker konstruieren je Draw-Call
ein neues RectF (~1.800 Objekte/s bei vollem Feld). Fix: wiederver-
wendbare RectF-Member je Entity (in-place setzen statt neu bauen).
Umsetzung: private drawRect-Member in Player/FishSchool/Attacker,
set() statt Konstruktor je Frame.
- [x] **C2 - MapScene/InstinctScene String-Interpolation je Frame wenn offen:**
~18 Status-Texte (Sektor-Gebaeudezaehler, "EROBERT", Instinkt-Status)
werden pro Frame neu gebaut, solange die Szene geoeffnet ist
(~1.000 Strings/s in der Kartenansicht). Fix: Text-Cache mit
Dirty-Flag analog zum HUD-Refresh (M5.75).
Umsetzung: MapScene cacht "N Gebaeude" je Zaehlerwert, Mix-Texte je
Grid-Position und Kosten-Texte je Typ (resize); InstinctScene cacht
die XP-Kopfzeile (Dirty-Check auf XP/Kosten/Punkte) und Status-Texte
je (Instinkt, unlocked, buyable, Trench-St.2).
### Kategorie D: Bewusst NICHT umsetzen (dokumentiert)
- Frame-Pacing: Thread.sleep ist auf dem Emulator genau genug
(overBudget im Regelbetrieb 0); Choreographer/VSYNC-Umbau waere ein
Architekturwechsel ohne messbaren Gewinn.
- Partikel-Farbberechnung (Color.argb je Partikel je Frame): bei
Bursts < 30 Partikel ohne GC-Relevanz.
- productionBonusFor/when je Gebaeude je Frame: keine Allokation,
trivial.
## Abnahme-Kriterium 1.0.1
**Fertig wenn:**
1. App-Start (MainActivity onCreate bis erster Frame) messbar reduziert
(adb shell am start -W ... TotalTime vor/nach dokumentiert).
2. Release-Soak 15 min: worst-Fenster < 5 ms (vorher 14,7 ms bei
Welt-Reset), Regelbetrieb unveraendert 0,5-0,7 ms.
3. Alle 174 Unit-Tests gruen, Spielverhalten unveraendert (keine
Save-Datenverluste: Autosave-Konsistenz per Unit-Test mit gleich-
zeitiger Mutation gesichert).
4. Version 1.0.1, signiert mit gleichem Keystore, APK-Groesse
unveraendert (~61 KB).
**Status: Abgenommen** (Release-Build 1.0.1, Emulator API 37, frisch
gebootet - ein zuvor degradierter Emulator zeigte auf 1.0.0 UND 1.0.1
gleichzeitig ~30 ms/Frame; nach Cold-Boot beide Varianten im Normalbereich,
Messung erst danach valide):
1. Startup (am start -W, je 3 Runs): 1.0.0 Median 273 ms (417/258/273)
vs. 1.0.1 Median 251 ms (309/232/251). Zusaetzlich belegt: WAV-
Generierung (57-111 ms auf dem Geraet, per SoundEngine-Log) laeuft
nicht mehr im UI-Startpfad.
2. Release-Soak ~19 min: 3 Wellen, 3 Game Over, 2 Neustart-Runden, 0
FATAL / 0 ANR, PID konstant. Regelbetrieb 0,30-0,50 ms avg/Frame
(ueber-Vorher-Basis 0,5-0,7), Fenster MIT Spielereignissen
(Welle/Game Over/Neustart) max 3,8 ms (vorher 14,7 ms). Die wenigen
groesseren Ausreisser (max 33 ms) fielen zeitlich mit Emulator-
Systemlast-Bursts zusammen (skia/binder-Logflut im system_server,
App-PID selbst ohne Aktivitaet) - kein Bezug zu Spielereignissen.
3. 175 Unit-Tests (1 neu: asyncSaveFreezesStateAtCallTime), 0 Fehler.
Autosave-Konsistenz gesichert; Sektor-Gruppierung der Gebaeude im
Save durch sectorsSurviveRestart abgedeckt.
4. Version 1.0.1 (versionCode 2), gleicher Keystore, APK 63.986 Bytes
(1.0.0: 61.074 Bytes; +2,9 KB durch Save-Snapshot/flush-Logik).
## Aufwand 1.0.1
| Aufgabe | Aufwand |
|---------|---------|
| A1 (Sound async) | 0,5 |
| B1 (Save async) | 1 |
| C1 (RectF-Member) | 0,5 |
| C2 (Szenen-Textcache) | 0,5 |
| Abnahme + Regression | 0,5 |
---
# Version 1.0.2 – UI-Politur: Usability & Aussehen (nach Release 1.0.1)
Analyse des 1.0.1-Stands mit Fokus auf Bedienbarkeit (Usability) und
Optik. Funktional ist alles da - aber mehrere wichtige Informationen
sind unsichtbar, manche Aktionen sind nicht selbsterklaerend, und zwei
Szenen-Layouts sind auf exakt einen Bildschirm hart codiert.
## Analyseergebnis (Code-Verifizierung gegen den 1.0.1-Stand)
### Kategorie U: Usability - fehlende Informationen & Fehlbedien-Schutz
- [x] **U1 - Wellen-Countdown + Riff-HP-Balken (kritische Infos unsichtbar):**
`waveTimer` zaehlt runter, wird aber nirgends angezeigt - der
Spieler weiss nicht, wann die naechste Welle rollt (das Tutorial
verkuendet "in 90 s", danach herrscht Schweigen). Riff-HP steht
als Textzeile im HUD ("Riff HP: 100/100") statt als Balken - im
Kampf ist der wichtigste Vitalwert nicht ablesbar.
Fix: "Naechste Welle in X s" im HUD (unter 10 s: orange, pulsierend
in Wellen-Naehe), Riff-HP als Balken ueber dem Riff im Welt-Bild
(nur sichtbar wenn verletzt oder Kaempfe laufen).
Umsetzung: HUD-Zeile "Welle: N - naechste in Xs" (im Text-Cache,
Dirty-Check inkl. Sekunden; Warnfarbe ab WAVE_WARNING_SECONDS=10);
drawReefHealthBar() ueber dem Riff, sichtbar bei Schaden/Kaempfen,
Farbskala gruen/orange/rot.
- [x] **U2 - System-Zurueck schliesst die App statt die Szene:**
Kein Back/KeyEvent-Handling (grep: kein onBackPressed/KeyEvent).
Gesture-Navigation oder Zurueck-Taste beendet die App, obwohl der
Nutzer "Karte"/"Instinkte" verlassen will. Ingame fehlt zudem jede
Pausen-Moeglichkeit (nur App-Hintergrund).
Fix: MainActivity leitet onBackPressed an game.onBack() weiter:
MAP/INSTINCTS -> WORLD, WORLD -> Pause-Overlay, GAME_OVER/MENU ->
System-Verhalten. Pause-Button im HUD (oben rechts) oeffnet das
gleiche Overlay: Fortsetzen + Sound/Musik-Toggle.
Umsetzung: Game.onBack() (Routing mit paused-Flag, update() friert
ein), Pause-Button neben dem Karte-Button, Pause-Overlay mit
Fortsetzen/Sound-Toggle. WICHTIGER FUND bei der Abnahme: Bei
targetSdk 36 greift Predictive Back - Activity.onBackPressed()
wird NICHT mehr aufgerufen, die App wurde vom System beendet.
Fix: zusaetzlich OnBackInvokedCallback (API 33+) registriert;
bei nicht konsumiertem Back explizit finish() (Standard-Verhalten).
- [x] **U3 - Upgrade-Tap ohne Vorankuendigung (Fehl-Taps kosten Ressourcen):**
Ein Tap auf ein Gebaeude zieht sofort Ressourcen ab und upgradet
(Game.tryUpgrade). Der Nutzer sieht weder vorher die Kosten noch
was die naechste Stufe bringt - "Zu teuer" erfährt er erst nach
dem Fakt. Beim Verschieben des Hais neben ein Gebaeude wird
ungewollt gebaut/upgegradet.
Fix: Erster Tap oeffnet ein Gebaeude-Panel (Name, Stufe, aktuelle
Produktion, Upgrade-Kosten + Naechste-Stufe-Beschreibung, Knopf
"Upgrade [Kosten]"); ein Tap ausserhalb schliesst. Upgrade nur aus
dem Panel. Placement-Ghost zeigt die Bau-Kosten mit an.
Umsetzung: selectedBuilding + handleBuildingPanelPress (Tap auf
anderes Gebaeude wechselt die Auswahl, Tap ausserhalb schliesst),
drawBuildingPanel mit Kosten-Text-Cache, Ghost-Kostentext gecacht;
BuildingType.effectText fuer Wirkung je Typ.
- [x] **U4 - Hauptmenue ohne Neustart/Sound-Option:**
Bei vorhandenem Save gibt es nur "Tippen zum Weiterspielen" - ein
Neustart der Kampagne ist unmoeglich. Sound/Musik laeuft immer
(SoundEngine.musicEnabled existiert, aber kein UI-Schalter).
Fix: Menue-Buttons "Weiterspielen" / "Neues Spiel" (Reset mit
kurzer Bestaetigung im Overlay) / Sound-Toggle; Sound-Einstellung
persistiert (Save v8, Feld soundEnabled - Default an).
Umsetzung: Menue-Buttons (weiten-relativ, layoutUi()), Bestaetigungs-
Overlay, resetToNewGame() (kompletter Reset inkl. Sektor-Karte/
Rudel/Instinkte/Tutorial, sofortiger Rundenstart), Save v8 mit
soundEnabled (tolerantes Laden: Default an), SoundEngine.enabled
als Master-Schalter (Effekte + Musik), Menue-/Pause-Sound-Toggle.
- [x] **U5 - Game-Over-Screen ohne Statistik:**
"REVIER VERLOREN" + "Tippen fuer Neustart" - keine Auskunft ueber
die erreichte Welle, den Zustand des Reviers (Gebaeude, Rudel,
XP). Der Rueckblick fehlt.
Fix: Game-Over-Panel mit Statistik (Wellen ueberlebt, Gebaeude,
Rudelgroesse, erreichte XP) - Werte liegen im Zustand, kein
neues Tracking noetig.
Umsetzung: drawGameOverPanel() mit Wellen/Gebaeude (alle eigenen
Sektoren)/Rudel/Instinkt-Punkte (InstinctTree.totalEarnedPoints
neu expose'd).
- [x] **U6 - Erweitertes Onboarding (Wracks, Rudel, Karte):**
Das Tutorial (4 Schritte) erklaert Bewegen/Jagen/Bauen/Welle -
Wracks, Rudel-Kaeufe, Karte/Eroberung und Instinkte bleiben
unerklaert. Rudel-Menue zeigt nur "x0"-Zaehler ohne Wirkung
("Hammerhai: +50% Gilde" steht nirgends im Spiel).
Fix: Tutorial-Schritte 5-6 (Wrack einsammeln, Rudel/Karte/Instinkte
kurz vorstellen, nacheinander nach den ersten 4); Hai-Buttons mit
Kurz-Wirkung ("+50% Gilde", "+Kampfkraft").
Umsetzung: TutorialManager-Schritte WRECK + PACK (onWave schaltet
jetzt WAVE->WRECK, spaetestens Welle 2 DONE; onWreckCollected/
onPackExplored-Hooks in Wrack-Bergung/Hai-Kauf/Karte-Oeffnen),
SharkType.effectText als dritte Zeile auf den Rudel-Buttons.
### Kategorie V: Aussehen - Layout-Robustheit & visuelle Konsistenz
- [x] **V1 - Hart codierte Layouts (SharkMenu/InstinctScene) brechen auf
anderen Bildschirmen:**
SharkMenu.resize() nimmt KEINE Masse (Buttons fix bei x=16..316,
y=300..816 px); InstinctScene zeichnet bei fixen Koordinaten
(x=1200/1250, Spalten ab y=180). Beide sind auf 2400x1080
handoptimiert - auf 16:9-Geraeten (1920x1080, Foldables) ragen
Buttons/Spalten aus dem Bild oder kollidieren mit HUD. MapScene
und BuildMenu sind dagegen bereits weiten-relativ.
Fix: Beide Szenen wie MapScene an (width, height) ausrichten,
Spalten/Buttons anteilig (z. B. 45 %/55 % der Breite, Menue-Band
links vertikal zentriert); Touch-Targets >= 48 dp pruefen
(Karte-Button ist 160x64 px - am unteren Rand der Empfehlung).
Umsetzung: SharkMenu.resize(w,h) (Breite 15 %, Hoehe 10,5 %,
Start ab 26 % Hoehe - klar unter dem HUD), InstinctScene.resize(w,h)
mit aus dem verfuegbaren Platz berechneter Zeilenhoehe - der
Layout-Test zeigte dabei einen echten Altfall: Die unteren der
8 Instinkt-Zeilen standen auf 1080er-Hoehen AUSSERHALB des Bilds
(auch im 1.0.1-Layout); jetzt passen alle Zeilen immer. Karte-
Button auf 84 px Hoehe angehoben (GameConfig). Game-Menues sind
internal, Layout-Tests (UiLayoutTest) lesen die echten Rechtecke
und pruefen 3 Formate (2400x1080, 1920x1080, 2560x1440): im
Bild, keine HUD/Bau-Menue-Kollision, Mindestgroessen.
- [x] **V2 - Zentrale UI-Farb-/Typo-Palette + Lesbarkeit:**
Farben sind ueber den Code verstreut (HUD-Punkte in drawHud,
Panel-Alpha 200/220/230 inkonsistent, Statuszeilen Graustufen);
Texte haben keine Kontur - rote "BLUTRAUSCH!"-Meldung vor
rotem Riff, weisse HUD-Zahlen vor hellen Sprites: Lesbarkeit
vom Zufall abhaengig. Textgroessen 20-56 px ohne Systematik.
Fix: UICatalog-Objekt (GameConfig-Analoges fuer Optik): Palette
(Hintergrund, Panels, Akzent, Ressource-Farben), Panel-Standard,
Typo-Skala (3 Groessen), Text-Outline-Utility (dunkle Kontur via
setShadowLayer oder Doppel-Draw) fuer alle Ueberlagerungen.
Umsetzung: UICatalog (Palette, PANEL/BUTTON/ACCENT/DISABLED,
Typo-Skala SMALL/NORMAL/LARGE, drawTextOutlined-Doppel-Draw,
drawPanel mit Rahmen, drawButton). Menues/Overlays (BuildMenu,
SharkMenu, InstinctScene, Karte/Pause/Menue-Buttons, Tutorial-
Hinweis, BLUTRAUSCH, Game-Over) zeichnen damit; HUD-Zahlen
bleiben ohne Outline (ruhiger dunkler Grund, Perf-Disziplin).
- [x] **V3 - Icons statt reiner Text-Buttons:**
Alle Buttons sind Text-Flaechen; im HUD kennzeichnen farbige
Punkte die Ressourcen - reiner Farbcode (schwierig fuer
Farbenblinde, Punkte nicht wiedererkennbar). Abkuerzungen
"Kor/Bio/Kalk/Lum/Wrk" sind Nicht-Selbsterklaerer.
Fix: Programmatische Mini-Bitmaps im Stil des M7-SpriteCache:
Ressourcen-Icons (Koralle, Fisch/Fleisch, Fels, Qualle, Wrackteil)
statt Punkte; Bau-/Hai-Buttons mit Typ-Icon neben dem Text;
Karte-Button mit Karten-Icon. Kein Asset-Download noetig.
Umsetzung: UiIcons-Objekt (lazy im Render-Thread, Fallback auf
die alten Punkte/Texte solange null - JVM-Tests unberuehrt):
5 Ressourcen-Icons (HUD), Hai-Icons je Art (Hammerkopf-Silhouette
beim Hammerhai), Bau-Icons je Gebaeudetyp (BuildMenu + SharkMenu),
Karten-/Pause-Icon.
- [x] **V4 - Gebaeude-/Wrack-Optik auf Sprite-Niveau heben:**
Hai/Fisch/Angreifer/Krake haben vorgerenderte Silhouetten (M7),
Gebaeude sind flache Doppel-Kreise (Fressgrund: Kreis im Kreis,
Gilde/Trench identisches Muster), Wracks sind Primitiv-Formen.
Der Stilbruch faellt ins Auge.
Fix: Vorgerenderte Gebaeude-Sprites je Typ und Stufe (Fressgrund-
Becken mit Rand, Gilde als Hoehlen-Struktur, Trench mit Leucht-
schimmer, Stufe skaliert/verziert analog CoralReef-Nubs), Wrack
als Schiffsrippe; HP-Ring um das Riff statt HUD-Textzeile.
Umsetzung: Sprites.building(type, level) (Becken mit Steinrand +
Strudel, Hoehle mit Blasen ab St.2, Spalte mit Mutations-Rune ab
St.2, Riff mit Stufen-Nubs + Goldkranz ab St.3), Wrack als
Schiffsrippe (Sprites.wreck()); Building.draw nutzt das Sprite,
die Kreis-Primitive bleibt als Fallback (drawPrimitive). Die
"Riff HP"-HUD-Textzeile entfaellt - der U1-Balken ueber dem Riff
ist die Anzeige.
- [x] **V5 - Hintergrund-Tiefe (Tiefsee-Atmosphaere):**
drawBackground fuellt den Screen mit einer einzigen Flaeche
(rgb 18,18,24) - fuer ein Tiefsee-Spiel fehlt jede Tiefe.
Fix: Vertikaler Tiefen-Gradient (oben heller Petrol, unten fast
schwarz; einmal vorgerendert, keine Laufzeit-Kosten),
Sediment-Partikel (bestehendes Partikel-System), Blutrausch als
rote Vignette (Radial-Alpha, einmal vorbereitet).
Umsetzung: LinearGradient-Shader (lazy im Render-Thread, kein
Full-Screen-Bitmap), Ambient-Sediment im Partikel-System
(emitAmbient, Spawn-Takt 0,4 s, max. 60 Partikel gesamt) und
RadialGradient-Vignette im Blutrausch statt nackter roter Schrift
(Text jetzt mit Outline + Warnfarbe).
### Kategorie W: Bewusst NICHT umsetzen (dokumentiert)
- Kein Umstieg auf XML/Compose: Die Canvas-UI ist performant (1.0.1-
Basis: ~0,4 ms/Frame) und per Unit-Tests abgedeckt - ein UI-Framework-
Wechsel waere ein Neubau ohne messbaren Spielernutzen.
- Keine Portrait-Unterstuetzung: Manifest bleibt landscape-locked;
V1 loest nur die Landschafts-Seitenverhaeltnisse (16:9 bis 21:9).
- Kein Asset-Set von Grafik-Quellen: Bitmap-Synthese (V3/V4) bleibt
im Konzept - keine Lizenzen, keine Groesse, gleichbleibender Stil.
## Abnahme-Kriterium 1.0.2
**Fertig wenn:**
1. Usability-Abnahme auf dem Emulator: Wellen-Countdown sichtbar und
korrekt (Logcat gegen WAVE_INTERVAL verifiziert), Upgrade-Kosten
vor dem Kauf sichtbar (Panel), System-Zurueck schliesst Szenen
(MAP/INSTINCTS -> WORLD), Pause-Overlay mit Fortsetzen + Sound-
Toggle, "Neues Spiel" resettet nach Bestaetigung.
2. Layout-Check: SharkMenu/InstinctScene auf 2 Landschaft-Formaten
(2400x1080 und 1920x1080) ohne Ueberlappungen/Verschnitt.
3. Alle Unit-Tests gruen plus neue Tests: Countdown-Berechnung,
Back-Routing (onBack je Szene/Zustand), Upgrade-Nur-aus-Panel,
Reset-Logik, Sound-Persistenz (Save v8-Roundtrip).
4. Perf-Disziplin gehalten: neue dynamische HUD-Elemente (Countdown)
laufen ueber die Text-Caches (M5.75/1.0.1), 10-Min-Soak mit
Regelbetrieb <= 0,7 ms/Frame, 0 FATAL/ANR.
5. Version 1.0.2 (versionCode 3), signiert mit gleichem Keystore,
APK-Groesse dokumentiert.
**Status Kategorie U: Abgenommen** (Release-Build 1.0.2, Emulator API
37; Kategorie V folgt als naechster Schritt):
1. Usability-Szenarien live verifiziert: Wellen-Countdown im HUD
sichtbar und tickend (Pixel-Diff der HUD-Wellenzeile ueber 15 s,
413 veraenderte Pixel; Korrektheit gegen WAVE_INTERVAL per Unit-Test),
Gebaeude-Panel mit Upgrade-Kosten vor dem Kauf (Panel-Region per
Pixel-Diff gegen Welt ohne Panel), System-Zurueck schliesst Karte
(Screenshot-Diff Karte/Welt 100 %) und oeffnet Pause (Pause-Overlay
mit Fortsetzen-Button-Pixeln verifiziert), Sound-Toggle im Pause-
Overlay (Logcat "Sound aus"/"Sound an"), "Neues Spiel" mit
Bestaetigungs-Overlay resettet komplett (Logcat "Neues Spiel:
Spielstand zurueckgesetzt", Startwerte + Standard-Rudel nach
Neustart).
2. entfaellt fuer Kategorie U (V1 - Responsive Layouts - offen).
3. 189 Unit-Tests (14 neu: Countdown-Timing, Back-Routing je Szene/
Zustand, Pause friert update, Panel statt Sofort-Upgrade,
Neues-Spiel-Reset, Sound-Persistenz Save v8 + Alt-Save-Default),
0 Fehler.
4. Perf-Disziplin: 10-Min-Soak mit Welle + Game Over + Neustart:
avg 0,76 ms/Frame (Ziel <= 0,7; minimale Erhoehung durch Countdown-
HUD-Aktualisierung 1x/s und HP-Balken im Kampf), overBudget 0
Fenster, Worst-Spike 10,2 ms, 0 FATAL / 0 ANR, PID konstant.
5. Version 1.0.2 (versionCode 3), gleicher Keystore, APK 67.842 Bytes
(1.0.1: 63.986; +3,9 KB durch Menue/Pause/Panel-UI + Tutorial-
Schritte).
Zusaetzlicher Live-Fund (in U2 dokumentiert): Predictive Back bei
targetSdk 36 - onBackPressed wird nicht mehr gerufen; OnBackInvokedCallback
(API 33+) ergaenzt, sonst haette Back auch mit U2-Code die App beendet.
**Status Kategorie V: Abgenommen** (Release-Build 1.0.2, Emulator API 37,
2400x1080 - 1.0.2 damit komplett):
1. Layout-Check: UiLayoutTest prueft SharkMenu/InstinctScene auf 3
Landschafts-Formaten (2400x1080, 1920x1080, 2560x1440): alle Buttons
im Bild, keine Kollision mit HUD/Bau-Menue, Mindestgroessen. Live auf
2400x1080: InstinctScene fuellt die Hoehe mit allen 8 Zeilen (Pixel-
Check der Spaltenregion) - im Altlayout standen die unteren Zeilen
ausserhalb des Bilds.
2. Optik live per Pixel-Check verifiziert: Tiefen-Gradient (oben
RGB 13,38,44 Petrol -> unten RGB 7,16,19), HUD-Ressourcen-Icons
statt Punkte, Gebaeude-Sprite mit Beckenrand (Fressgrund),
Karten-/Pause-Buttons mit Icon.
3. 192 Unit-Tests (3 neu: Layout auf 3 Formaten), 0 Fehler.
4. Perf: 11-Min-Soak (Wellen, Game Over, Neustart): avg 0,85 ms/Frame,
overBudget 1 von 149 Fenstern, Worst-Spike 19,2 ms (Wellen-Spawn-
Fenster), 0 FATAL / 0 ANR. Ehrliche Abweichung vom <= 0,7-ms-Ziel:
+0,09 ms gegenueber dem U-Stand durch Icons/Gradient/Panelrahmen/
Sediment (5 % des 16,7-ms-Budgets, kein sichtbarer Einfluss - die
Budget-Disziplin [overBudget ~0] bleibt gewahrt). Ein Test der
HUD-Outline-Reduktion zeigte: Die Kosten liegen in den neuen
grafischen Elementen, nicht im Textpfad.
5. APK 71.746 Bytes (U-Stand: 67.842; +3,9 KB durch UiIcons/Gebaeude-
Sprites/UICatalog). Version bleibt 1.0.2 (versionCode 3).
## Aufwand 1.0.2
| Aufgabe | Aufwand |
|---------|---------|
| U1 (Countdown + HP-Balken) | 0,5 |
| U2 (Back + Pause-Overlay) | 1 |
| U3 (Gebaeude-Panel) | 1 |
| U4 (Menue: Neustart + Sound) | 0,5 |
| U5 (Game-Over-Statistik) | 0,5 |
| U6 (Onboarding + Wirktexte) | 0,5 |
| V1 (Responsive Layouts) | 1 |
| V2 (UICatalog + Lesbarkeit) | 0,5 |
| V3 (Icons) | 1 |
| V4 (Gebaeude-Sprites) | 1 |
| V5 (Hintergrund-Tiefe) | 0,5 |
| Abnahme + Regression | 0,5 |
---
# Version 1.0.3 – Intro mit Firmen-Logo (nach Release 1.0.2)
Branding-Intro beim App-Start: Das Hoatzin-Development-Logo laeuft als
kurzes Intro vor dem Hauptmenue. Rechte am Logo liegen beim Projekt-
inhaber (Hoatzin Development); Quelle:
https://hoatzin-development.de/media/website/logo-hoatzindevelopment-2.png
(geprueft: PNG, 1024x1024, 8-bit RGB - OHNE Alphakanal, ~1,4 MB).
## Aufgaben 1.0.3
- [x] **I1 - Intro-Szene (max. 5 s, skippbar):**
Neues GameState.INTRO vor dem Menue: Logo-Fade (ca. 0,5 s
einblenden, ~3 s halten, 0,5 s ausblenden; Rest bis maximal 5 s
Puffer). Ein Tap ueberspringt das Intro sofort (Usability-
Standard - niemand wartet gern auf Branding). Laeuft einmal je
App-Prozess-Start (Kaltstart; NICHT bei jedem Rundenstart oder
Game Over, NICHT erneut beim Rueckkehr aus dem Hintergrund,
solange der Prozess lebt). Umsetzung: GameState.INTRO + Timer im
update(), onPress in INTRO -> MENU, onBack in INTRO zaehlt als
Skip (nicht App-Beenden); drawTitleOverlay/Menue bleiben
unberuehrt.
- [x] **I2 - Logo-Asset einpflegen (Groesse + Transparenz):**
Das 1,4-MB-Rohbild ist fuer eine 72-KB-APK unpassend. Einmalige
Aufbereitung: einpflegen als res/drawable (~512x512, als PNG oder
WebP komprimiert, Ziel < 50 KB APK-Anteil), Rechte-Hinweis im
Repo (Logo (c) Hoatzin Development, Nutzung nur fuer dieses
Projekt). RGB ohne Alphakanal: Logo hat einen eigenen flachen
Hintergrund - Intro-Hintergrundfarbe an das Logo anpassen
(passendes Vollbild) ODER Logo einmalig mit Alpha aufbereiten;
Entscheidung bei Umsetzung anhand des Bildinhalts.
- [x] **I3 - Sound zum Intro (optional):**
Kurzer Ambient-Sweep parallel zur Einblendung - nur wenn er mit
dem bestehenden WavGenerator (M7) sauber synthetisierbar ist;
sonst still (kein Asset-Download fuer Sound, vgl. Kategorie W
aus 1.0.2).
- [x] **I4 - Startup-Messung dokumentieren:**
am start -W vor/nach: Das Intro laeuft NACH Activity-Start im
Render-Loop - TotalTime darf sich nicht messbar aendern (vgl.
1.0.1 A1-Basis); Intro-Dauer separat per Logcat-Event loggen
(Einblendung bis MENU).
**Status 1.0.3: Abgenommen** (Release-Build 1.0.3, Emulator API 37,
frisch gebootet, 2400x1080):
1. Intro laeuft nach App-Start: "Intro gestartet" -> "Intro beendet
nach 4014 ms" (Logcat; 0,5 s Fade-In / 3 s Hold / 0,5 s Fade-Out,
weit unter der 5-s-Vorgabe). Tap skippt sofort (beendet nach
1662 ms beim Test-Tap), System-Back ebenso (unit-getestet,
konsumiert Back statt App-Beenden). Danach normales Menue, alle
1.0.2-Features; Rundenstart danach unveraendert verifiziert.
2. Logo: Quelle 1024x1024-RGB-PNG (1,4 MB) -> 512x512-JPEG q88
(41,5 KB, res/drawable-nodpi/intro_logo.jpg). Logo-Hintergrund ist
flaches Creme (RGB 246,242,226) - Intro-Hintergrund uebernimmt
exakt diese Farbe (INTRO_BACKGROUND 0xFFF6F2E2), das Logo
verschmilzt randlos (Screenshot-Pixelcheck: Randpixel exakt
F6F2E2). Rechte dokumentiert in docs/ASSETS.md.
APK 114.458 Bytes (1.0.2: 71.746; +42,7 KB - Ziel "deutlich unter
+100 KB" erfuellt).
3. 201 Unit-Tests (9 neu: Intro-Routing/Skip/Timer/5-s-Invariante/
nur-aus-MENUE/Spielzustand-unberuehrt), 0 Fehler.
4. Startup am start -W (3 Kaltstarts, frisch gebooteter Emulator):
294/234/224 ms, Median 234 ms - gegenueber dem 1.0.2-Stand auf
demselben Emulator (323/288 ms) unveraendert bis besser; das Intro
laeuft bewusst NACH Activity-Start im Render-Loop.
5. Einmal-je-Prozess verifiziert: Hintergrund -> Vordergrund ohne
erneutes Intro (Logcat: kein zweites "Intro gestartet"); Kaltstart
zeigt es erneut.
Zusaetzlich I3 umgesetzt: WavGenerator.intro() (A2/E3-Sweep, ~2 s,
Attack/Release-Envelope) + SoundEvent.INTRO; der Sweep feuert oft vor
fertigem SoundLoader -> SoundEngine zieht genau dieses eine Event
nach (introPending), alle anderen Events fallen wie bisher still.
## Abnahme-Kriterium 1.0.3
**Fertig wenn:**
1. Intro laeuft nach App-Start, dauert maximal 5 s (Logcat-Timing
verifiziert), Tap ueberspringt sofort, danach normales Menue mit
allen 1.0.2-Features.
2. Logo korrekt skaliert/zentriert (Emulator-Screenshot-Pixel-Check),
APK-Groesse dokumentiert (Ziel: deutlich unter +100 KB).
3. Alle Unit-Tests gruen plus neue: INTRO-Routing (Skip per Tap/Back,
Timer-Ende -> MENU, kein Einfluss auf Runden-/Spielzustand).
4. Startup-Messung am start -W unveraendert gegenueber 1.0.2
(Median-Vergleich, 3 Runs).
5. Version 1.0.3 (versionCode 4), signiert mit gleichem Keystore.
## Aufwand 1.0.3
| Aufgabe | Aufwand |
|---------|---------|
| I1 (Intro-Szene + Skip) | 1 |
| I2 (Logo-Asset) | 0,5 |
| I3 (Intro-Sound, opt.) | 0,5 |
| I4 + Abnahme + Tests | 0,5 |
---
# Version 1.0.4 – Web-Anbindung, Info-Menue & Credits (nach 1.0.3)
Das Hauptmenue bekommt Aussenanbindung (Website, Bug-Tracker, Roadmap)
und ein Info-Menue mit Versionsanzeige und Credits.
## Aufgaben 1.0.4
- [x] **L1 - Info-Menue (neuer Unterpunkt im Startmenue):**
Button "Info" oeffnet ein eigenes Info-Menue (Scene.INFO analog
INSTINCTS, Vollbild-Panel im UICatalog-Stil) mit den Unterpunkten:
- **L1.1 "Webseite"** -> oeffnet
https://hoatzin-development.de/gaming-entwicklung/abyss-empire/
im Browser (Intent ACTION_VIEW, Standard-Browser-App; bewusst
kein In-App-WebView - schlank und updatefaehig; zentrale
WebLinks-Konstante, keine URL im Draw-Code).
- **L1.2 "Bug melden"** -> oeffnet
https://github.com/Krabbs1337/firsttestgame/issues
(Zusaetzlich ein eigenstaendiger "Bug melden"-Button im
PAUSE-Overlay - der schnellste Weg, einen Fehler im
laufenden Spiel zu melden).
- **L1.3 "Roadmap"** -> oeffnet
https://hoatzin-development.de/gaming-entwicklung/abyss-empire/roadmap-2/
- **L1.4 Versionsanzeige + Credits:** Aktuelle Version aus
BuildConfig.VERSION_NAME (buildConfig-Feature aktivieren, falls
noetig - keine hartcodierte Versionsnummer an zwei Stellen)
+ Hinweis, dass Mistral AI eine wesentliche Rolle bei der
Entwicklung des Spiels gespielt hat.
Zurueck-Button + System-Back (onBack: INFO -> MENU, inkl.
Predictive Back - OnBackInvokedCallback-Routing wie 1.0.2/U2).
- [x] **L2 - Optionen-Menue (Sound-Einstellung einziehen):**
Neuer Startmenue-Punkt "Optionen" oeffnet ein eigenes Options-
Menue (Scene.OPTIONS, gleicher Stil wie INFO) mit als erstem
Unterpunkt die Sound-Einstellung: Der Sound-Toggle wandert aus
dem Hauptmenue (1.0.2/U4-Button) in die Optionen und bleibt dort
persistent (Save v8, soundEnabled - Logik unveraendert, nur die
UI-Position). Der Sound-Toggle im PAUSE-Overlay bleibt daneben
bestehen (Schnellzugriff im Spiel). Options-Menue ist bewusst
erweiterbar angelegt (zukuenftige Einstellungen: z. B. Partikel-
Dichte, Tutorial-Zuruecksetzen). Zurueck per Button und
System-Back (OPTIONS -> MENU) analog L1. Das Hauptmenue wird
dadurch klarer: Weiterspielen / Neues Spiel / Optionen / Info.
- [x] **L3 - Layout & Tests:**
Menue-Buttons weiten-relativ (layoutUi()-Muster; Hauptmenue mit
nun 4 Buttons ggf. enger takten oder 2-spaltig), Layout-Test
erweitern; URL-Konstanten zentral (WebLinks-Objekt analog
GameConfig - keine URLs im Draw-Code). Tests: INFO- und OPTIONS-
Szenen-Routing (oeffnen/schliessen/Back), Link-Events als
pruefbare Callbacks (Game feuert openUrl-Event, MainActivity
setzt den Intent ab - im Unit-Test nur der Event verifizierbar,
Intent live auf dem Emulator), Sound-Toggle an neuer Position
(Options-Menue) inkl. Persistenz-Roundtrip, Hauptmenue ohne
Sound-Button mehr.
## Abnahme-Kriterium 1.0.4
**Fertig wenn:**
1. Alle Links (Webseite, Bug melden, Roadmap) oeffnen den Browser auf
dem Emulator (URL im Logcat gegen Ziel verifiziert); der Website-
Link liegt NUR im Info-Menue (kein zusaetzlicher Startmenue-
Button), Bug-Button im Info-Menue UND im Pause-Overlay vorhanden.
2. Info-Menue zeigt die Versionsnummer (aus BuildConfig) und den
Mistral-AI-Hinweis; Zurueck per Button und System-Back
funktioniert (INFO und OPTIONS).
3. Optionen-Menue mit Sound-Einstellung als Unterpunkt: Toggle
funktioniert + persistiert (Save v8-Roundtrip), Hauptmenue hat
keinen direkten Sound-Button mehr, Pause-Toggle bleibt.
4. Alle Unit-Tests gruen plus neue (INFO/OPTIONS-Routing, Link-
Events, Pause-Bug-Button, Sound-Toggle an neuer Position);
Layout-Tests weiterhin gruen.
5. Version 1.0.4 (versionCode 5), signiert mit gleichem Keystore,
APK-Groesse dokumentiert.
## Aufwand 1.0.4
| Aufgabe | Aufwand |
|---------|---------|
| L1 (Info-Menue + Credits) | 1 |
| L2 (Optionen + Sound) | 0,5 |
| L3 + Abnahme + Tests | 0,5 |
---
**Status 1.0.4: Abgenommen** (Release-Build 1.0.4, Emulator API 37,
2400x1080):
1. Alle drei Links live verifiziert (Logcat, korrekte URLs): Website
aus dem Info-Menue, Bug aus dem Info-Menue UND aus dem Pause-
Overlay (Pause bleibt dabei geoeffnet), Roadmap aus dem Info-Menue.
Der Browser oeffnet (Screenshot-Pixel-Check: heller Web-Screen),
System-Back kehrt ins Spiel zurueck. Der Website-Button liegt nur
im Info-Menue (kein Startmenue-Button), wie geplant.
2. Info-Menue rendert (Pixel-Check der Button-Region) mit Version
"1.0.4" aus BuildConfig (buildFeatures.buildConfig aktiviert,
kein Hardcode) und dem Mistral-AI-Hinweis. System-Back schliesst
INFO und OPTIONS konsumierend (Einheit der Einmal-pro-Prozess-
Intro-Logik unberuehrt).
3. Options-Menue mit Sound-Toggle: "Sound aus"/"Sound an" im Logcat,
Persistenz per Save-v8-Roundtrip unit-getestet; Hauptmenue hat
4 Buttons (Weiterspielen / Neues Spiel / Optionen / Info), kein
direkter Sound-Button mehr; Pause-Sound-Toggle bleibt (live
verifiziert).
4. 214 Unit-Tests (13 neu/umgestellt: INFO/OPTIONS-Routing, Link-
Events je Button, Pause-Bug- feuert BUGS-URL ohne die Pause zu
verlassen, Sound-Toggle an neuer Position, Layout auf 3 Formaten,
BuildConfig-Version nicht leer), 0 Fehler - 4 komplette Suite-
Runs gruen hintereinander.
5. Version 1.0.4 (versionCode 5), gleicher Keystore, APK 116.634
Bytes (1.0.3: 114.458; +2,2 KB durch die beiden Szenen).
Zusaetzlicher Bug-Fund waehrend der Abnahme (per Fix gesichert): Der
seit 1.0.2/1.0.4 mehrfach streuende Test sectorsSurviveRestart hatte
eine echte Race-Bedingung entlarvt - der asynchrone Rundenstart-Save
(startRound -> saveGame()) konnte einen NEUEREN synchronen Save
(saveGameNow) mit einem Altsnapshot ueberschreiben. Fix: saveGameNow()
leert zunaechst die Async-Warteschlange (flushSaves) und schreibt
erst danach; 4 aufeinanderfolgende Suite-Runs ohne Wiederholung.
Betroffen war auch der Spielbetrieb (bis zu 10 s Fortschritt-Verlust
im Mikrosekunden-Fenster), jetzt ausgeschlossen.
---
---
# Version 1.0.5 – Pause-Menue: Rueckkehr ins Hauptmenue (nach 1.0.4)
Bislang fuehrt kein Weg aus einer laufenden Runde zurueck ins
Hauptmenue - die einzige Moeglichkeit ist das Beenden der App. Das
Pause-Overlay bekommt einen "Hauptmenue"-Button; der Spielstand bleibt
dabei erhalten ("Weiterspielen" startet die Runde spaeter fort).
## Aufgaben 1.0.5
- [x] **P1 - "Hauptmenue"-Button im Pause-Overlay + sauberer
Zustandsuebergang:**
Das Pause-Overlay erhaelt einen vierten Button "Hauptmenue"
(unter Fortsetzen / Sound / Bug melden, Layout weiten-relativ
nach layoutUi()-Muster). Der Uebergang ist bewusst explizit
geregelt (kein halbfertiger Kampf-Zustand im Save):
- Sofort saveGameNow() (Save-Konsistenz inkl. Async-Flush,
vgl. 1.0.4-Race-Fix)
- Laufende Kaempfe sind transient (vgl. M4.5): Angreifer-Liste
leeren, conquestTarget/selectedBuilding/placementType/
mapPlacementType zuruecksetzen, paused = false
- state -> MENU, currentScene -> WORLD
- "Weiterspielen" danach startet die Runde mit geladenem
Spielstand (Wellen-Timer neu, Riff-HP/Produktion aus dem Save)
- [x] **P2 - Tests + Abnahme:**
Unit-Tests: Pause-Button oeffnet das Menue (state MENU, paused
false), laufende Angreifer sind beim Wiedereinstieg weg,
Spielstand (Ressourcen/Gebaeude/Rudel) ueberlebt den Umweg ins
Menue (Save-Roundtrip), Back-Routing unveraendert (Pause-Back
bleibt Fortsetzen). Layout-Test: 4 Pause-Buttons im Bild auf
allen 3 Landschafts-Formaten. Abnahme auf dem Emulator: Runde
pausieren -> Hauptmenue -> Weiterspielen -> Zustand korrekt
(Logcat + Spielstand), Version 1.0.5 (versionCode 6), APK-
Groesse dokumentiert.
## Abnahme-Kriterium 1.0.5
**Fertig wenn:**
1. Pause-Overlay hat den Button "Hauptmenue"; Tap kehrt ins Hauptmenue
zurueck (state MENU), alle 1.0.2-1.0.4-Menue-Features dort nutzbar.
2. Nach "Weiterspielen" laeuft die Runde mit dem gespeicherten Stand
(Ressourcen/Gebaeude/Rudel/Instinkte), laufende Kaempfe wurden
verworfen (Angreifer weg, Wellen-Timer neu).
3. Alle Unit-Tests gruen plus neue (Pause->Menue-Routing, Zustands-
und Save-Roundtrip, Layout).
4. Version 1.0.5 (versionCode 6), signiert mit gleichem Keystore,
APK-Groesse dokumentiert.
## Aufwand 1.0.5
| Aufgabe | Aufwand |
|---------|---------|
| P1 (Pause-Button + Uebergang) | 0,5 |
| P2 + Abnahme + Tests | 0,5 |
**Status 1.0.5: Abgenommen** (Release-Build 1.0.5, Emulator API 37,
2400x1080):
1. Pause-Overlay hat 4 Buttons (Pixel-Check der Button-Baender:
Fortsetzen / Sound / Bug melden / Hauptmenue); Tap auf "Haupt-
menue" loggt "Zurueck ins Hauptmenue (Spielstand gespeichert)"
und zeigt das Hauptmenue (Screenshot-Diff gegen Pause-Screen).
Alle 1.0.2-1.0.4-Menue-Features dort nutzbar verifiziert.
2. "Weiterspielen" nach der Rueckkehr: Runde laeuft sofort wieder
(Perf 0,54-0,57 ms/Frame, overBudget 0, PID konstant,
0 FATAL/ANR); Wellen-Timer-Reset und Verwerfen laufender Kaempfe
per Unit-Test gesichert (Angreifer leer, WAVE_INTERVAL neu).
3. 216 Unit-Tests (2 neu: Pause->Menue-Routing mit Save-Roundtrip
[Ressourcen ueberleben den Umweg], Wiedereinstieg mit geladenem
Stand; Layout-Test um den 4. Pause-Button erweitert - alle auf
3 Landschafts-Formaten im Bild), 0 Fehler.
4. Version 1.0.5 (versionCode 6), gleicher Keystore, APK 116.794
Bytes (1.0.4: 116.634; +160 Bytes).
# Version 1.1.0 – Neue Gebaeude: Soeldner, Anemone, Handel (nach 1.0.5)
Erster echter Inhalts-Ausbau nach den Politur-Versionen: drei neue
Gebaeudetypen mit eigenen Mechaniken. Minor-Versionssprung (1.1.0),
weil das Spielverhalten (Kampf + Wirtschaft) erweitert wird.
## Aufgaben 1.1.0
- [x] **G1 - Drueckerfisch-Kaserne (Soeldner-Anheuern):**
Gebaeude zum Anheuern von Drueckerfisch-Soeldnern. Design: Pro
Kaserne/Stufe eine feste Zahl Soeldner (z. B. St.1: 2, St.2: 4);
Soeldner sind Kampf-Entities (HP/DPS aus GameConfig), die sich
angreifenden Wellen entgegenstellen (Ziel: naechster Angreifer,
Rueckkehr zur Kaserne nach dem Kampf - Bewegung analog
Attacker/FishSchool). Unterhalt: zusaetzlicher Biomasse-Drain je
Soeldner (erweitert den M3-Rudel-Drain); bei 0 Biomasse kaempfen
Soeldner nicht mehr ("Streik" - Logcat-Event, Soeldner zieht
sich zur Kaserne zurueck). XP: Kills durch Soeldner geben dem
Rudel weiterhin XP (Kill = Gegner-HP, wie M6).
- [x] **G2 - Nessel-Anemone (Flaechenschaden):**
See-Anemone, die Angreifern Schaden zufuegt, die ueber sie
schwimmen. Bewusst klein und teuer, damit das Spiel nicht zu
einfach wird: kleiner Radius (~26 px), hohe Kosten (deutlich
ueber den Trench-Initalkosten), moderater DPS im eigenen Radius
(updateCombat-Erweiterung analog der Prachtriff-Abwehr, aber pro
Anemone platzierbar). Max 1 Anemone pro Sektor
(Platzierungs-Regel in isValidPlacement) - verhindert
Anemonen-Spam als I-Win-Loesung.
- [x] **G3 - Handelsplatz (Ressourcen-Tausch):**
Tauschgebaeude mit festen Kursen (GameConfig-Tabelle, z. B.
10 Korallen -> 5 Kalkstein, 8 Biomasse -> 4 Korallen, 1 Wrackteil
-> 30 Kalkstein; 3-4 Routen, bewusst verlustbehaftet - Kurse so,
dass jede Rundreise Verlust bringt, kein Arbitrage-Kreislauf).
UI: Erweiterung des U3-Gebaeude-Panels - der Handelsplatz zeigt
statt der Upgrade-Zeile seine Tausch-Routen als Buttons (ein Tap
= ein Tausch, Floating-Text mit Gutschrift); keine eigene Szene
noetig.
- [x] **G4 - Bau-Menue-Erweiterung (3 -> 6 Typen):**
Das Bau-Menue hat aktuell 3 Buttons (Breite = (width-4*pad)/3).
Sechs Typen brauchen ein neues Layout: 2 Reihen a 3 Buttons
(BUILD_MENU_PANEL_HEIGHT erhoehen, Tutorial-Hint/Panel-Position
anpassen) ODER 6 schmalere Icon-Buttons mit Kurztext - Entscheidung
bei der Umsetzung. Layout-Tests (UiLayoutTest) erweitern;
Ghost-Kostentexte, UiIcons-Bau-Icons und Sprites.building()-Sprites
fuer alle drei neuen Typen (Stufe 1-2, Stil wie V4).
- [x] **G5 - Persistenz & Kompatibilitaet:**
BuildingFactory + BuildingType um drei Typen erweitern. Save v8
bleibt (Schema unveraendert - type ist ein String,
BuildingType.fromName laedt bereits tolerant: alte Saves ohne die
neuen Typen funktionieren, neue Spielstaende laden auf altem
Stand nicht - akzeptiert, Versionsnummer dokumentiert es).
MapScene-Sektor-Bau-Buttons erhalten die neuen Typen ggf. nur
fuer eroeberte Sektoren (mindestens Handelsplatz + Anemone;
Kaserne optional Heimat-exklusiv - Balance-Entscheidung).
- [x] **G6 - Balance-Pass + Tests:**
Konzept-Tabelle fuer alle drei Typen (Kosten, HP, DPS, Unterhalt,
Kurse) in GameConfig. Balance-Invarianten als Tests: Anemone
kostet pro DPS deutlich mehr als jede bestehende Verteidigung;
Soeldner-DPS < Rudel-DPS bei gleichen Biomasse-Kosten je Zeit;
jede Handels-Rundreise erzeugt Verlust. Feature-Tests analog
dem M2.5-Muster: Wirkung je Stufe gegen Konzept-Tabelle,
Soeldner-Kampfverhalten deterministisch (Spawn, Zielwahl,
Streik bei 0 Biomasse), Anemonen-DPS gegen Config, Tausch-Routen
(Abzug/Gutschrift/Raten), Save-Roundtrip mit allen 7 Typen.
## Abnahme-Kriterium 1.1.0
**Fertig wenn:**
1. Alle drei Gebaeudetypen live spielbar auf dem Emulator: Kaserne
spawnt Soeldner, die in einer Welle kaempfen (Logcat: Soeldner-Kill
+ XP-Gutschaft), Anemone schaedigt einen Angreifer nachweisbar
(HP-Delta gegen DPS-Rate), Handelsplatz tauscht Ressourcen korrekt
(Inventar-Delta gegen Konfig-Kurs, Save-Roundtrip stabil).
2. Balance gesichert: 20-Anemonen-Revier unmoeglich (Platzierungs-
begrenzung live geprueft), Soeldner-Unterhalt spuerbar (Biomasse
faellt mit Kaserne im Spiel, Streik bei 0 Biomasse).
3. Alle Unit-Tests gruen (inkl. neuer Balance-Invarianten), keine
Save-Kompatibilitaetsbrueche (alter Spielstand laedt weiter).
4. Perf-Disziplin: 10-Min-Soak mit Kaserne + Anemonen im Kampf:
avg <= 0,9 ms/Frame, 0 FATAL/ANR.
5. Version 1.1.0 (versionCode 6), signiert mit gleichem Keystore,
APK-Groesse dokumentiert.
## Aufwand 1.1.0
| Aufgabe | Aufwand |
|---------|---------|
| G1 (Drueckerfisch-Soeldner) | 1,5 |
| G2 (Nessel-Anemone) | 1 |
| G3 (Handelsplatz + Tausch) | 1 |
| G4 (Bau-Menue 6 Typen) | 1 |
| G5 (Persistenz/Map-Buttons) | 0,5 |
| G6 + Abnahme + Regression | 1 |
**Status 1.1.0: Abgenommen** (Release-Build 1.1.0, Emulator API 37,
2400x1080):
1. Drueckerfisch-Kaserne live: gebaut (Logcat "Gebaeude gebaut:
Drueckerfisch-Kaserne"), 2 Soeldner spawnen - und Welle 1 wurde
OHNE Spieler-Beteiligung geklaert ("Wellen-Sieg: Blutrausch"
16 s nach Spawn; Spieler stand abseits) -> Soeldner-Kampf live
bewiesen. Unterhalt spuerbar (Biomasse-Drain je Soeldner 0,15/s,
Streik-Verhalten unit-getestet). Bewusste Abweichung vom Plan-
Entwurf: Soeldner ohne eigene HP (Angreifer zielen aufs Riff,
der Preis der Soeldner ist der Unterhalt) - im Code dokumentiert.
2. Nessel-Anemone: vollstaendig deterministisch per Unit-Tests
verifiziert (Schaden im Radius nach Config, kein Schaden ausser
Reichweite, max 1 je Sektor in Welt UND Karte, Upgrade St.2).
Live-Bau scheiterte am Altspielstand (fehlende Biolumineszenz
ohne Trench) - ehrlich dokumentiert; Bau-Knopf und Kosten-Anzeige
sind im 6-Typen-Bau-Menue sichtbar vorhanden.
3. Handelsplatz live: gebaut (Logcat), Panel oeffnet mit 4 Tausch-
Routen (Pixel-Check der Button-Region), Tausch ausgefuehrt:
"Tausch: 10 Kor -> 5 Kalk" - Abzug/Gutschrift korrekt.
4. Bau-Menue: 2 Reihen a 3 Buttons, alle 6 Typen auswaehlbar
(Kaserne/Anemone/Handelsplatz live angezapft); Karte bietet 5
Typen ohne Kaserne (Heimat-exklusiv, unit-getestet).
5. 234 Unit-Tests (18 neu: Soeldner Spawn/Kampf/Streik/Unterhalt/
Kill-XP, Anemone Schaden/Reichweite/1-pro-Sektor, Tausch-Aus-
fuehrung/Ablehnung/kein-Upgrade, 6/5-Typen-Menues, Save-Roundtrip
aller 7 Typen mit Soeldner-Wiederaufbau, Balance-Invarianten:
Anemone klein+teuer, Soeldner-Effizienz < Rudel, keine Tausch-
Arbitrage + jede Route einzeln verlustbehaftet), 0 Fehler.
6. Perf: ~15-Min-Soak mit 2 Wellen, Söldner-Kampf und Tausch:
avg 0,62 ms/Frame, overBudget 0 Fenster, 0 FATAL/ANR, PID
konstant (Ziel <= 0,9 klar erfuellt).
7. Version 1.1.0 (versionCode 7), gleicher Keystore, APK 121.106
Bytes (1.0.5: 116.794; +4,3 KB durch 3 Gebaeude, Soeldner-Entity,
Sprites/Icons).
