TechNeko
Alle Notizen
LAB NOTE / 2026-07-03

TBA Dev-Log #1: Von der Headless-Simulation zum laufenden Ödland-Trupp

Ein postapokalyptisches Idle-RPG, das in der Taskleiste wohnt, gebaut in Godot 4 mit GDScript, der Code von einem KI-Agenten auf der Kommandozeile geschrieben. Dieser Eintrag dokumentiert die ersten zwei Wochen von Anfang bis Ende: Kampfmathematik und Wirtschaftskreislauf wurden ganz ohne Grafik bewiesen, dann kam eine Pixel-Art-Darstellungsschicht obendrauf. Unterwegs haben wir ein selbstgebautes Schichten-Rig auf Eis gelegt und KI-generierte Fake-Pixel-Art verworfen.

Was es ist

TBA (TaskBarApocalypse) ist ein Idle-RPG im Ödland-Setting, das in der Taskleiste sitzt. Ein Trupp aus drei Figuren marschiert, trifft Gegner, kämpft und sammelt Ausrüstung in einem transparenten Streifen von 760×200 Pixeln am unteren Bildschirmrand. Du arbeitest, sie leveln. Das Design hat drei Schleifen: automatischer Echtzeitkampf des Haupttrupps, ein Unterschlupf zum Ausbauen und ein Expeditionssystem, das ab der Spielmitte freigeschaltet wird (Mitglieder für 8 bis 12 Stunden losschicken, mit einem Schwung hochwertiger Ausrüstung eines bestimmten Typs zurückbekommen).

Unsere Vorgabe an uns selbst: klein und poliert, Mundpropaganda und Bindung zuerst, lokal zuerst, kein zentraler Server, kein Echtgeldmarkt. Inspiration ist das bestehende Genre der Taskleisten-Idle-Spiele, die Größenordnung der Zahlen orientiert sich an deren öffentlichen Daten, aber jeder Absolutwert wird auf unser eigenes Tempo neu geeicht.

Stadtruinen: der Trupp gegen kleine Zombies und einen Goblin-Schützen

Erst Regeln, dann Code

Bevor eine Zeile geschrieben wurde, entstand ein technisches Design- und Übergabedokument, das Architektur und ein paar eiserne Regeln festlegt. Jede Entwicklungsaufgabe seitdem verweist darauf.

Vier Schichten, einseitige Abhängigkeiten: Darstellung → Simulation ↔ Daten / Persistenz. Die Darstellungsschicht liest die Simulation nur; die Simulation kennt keinen einzigen visuellen Knoten.

Vier eiserne Regeln:

  • Die Simulation läuft auf einem Akkumulator mit festem Zeitschritt (ein Tick = 0,1 s), entkoppelt von der Bildrate. Fenster winzig machen oder verstecken, die Logik läuft weiter; Offline-Nachrechnung ist nur „N Ticks vorspulen".
  • Die Simulation ist deterministisch: gleicher Seed plus gleiche Eingaben ergibt identische Ergebnisse. Der Zufall nutzt einen serialisierbaren Seed, der samt Zustand in den Spielstand wandert.
  • Der Spielstand ist die einzige Wahrheit. Ohne Serverabgleich gibt es kein Lokal-gegen-Server-Problem.
  • Kein Anti-Cheat. Die Spielstandprüfung ist leicht und verhindert nur, dass eine kaputte Datei das Spiel abstürzen lässt. Wer an der Uhr dreht, schadet nur sich selbst.

Die Entwicklung wurde dann in vertikale Scheiben geschnitten, die jeweils von Anfang bis Ende laufen, zuerst Headless-Simulation mit Platzhaltergrafik, die Darstellung kommt danach obendrauf:

ScheibeInhaltStatus
0 SkelettGodot-Projekt, Verzeichnisse, fester Tick-Loop, Debug-PanelFertig
1 Headless-KampfDreistufige Werte, Schadensformel, Minderungs-Pipeline, Drops ins InventarFertig
2 WirtschaftskreislaufDoppelmotor Vorräte / Ausrüstung, Unterschlupf und Werkbank, TiefenbremseFertig
3 Figuren-Compositor5-Schichten-Rig + 5 Zustände + Pivots pro FrameBewiesen, dann auf Eis
DarstellungPixel-Art-Kampfbühne, an echte Zahlen und Wirtschaft angeschlossenSpielbar
4 ExpeditionenEntsenden, Einsatzsperre, echte Zeitstempel, gestufte AbrechnungNicht begonnen
5 PersistenzLokaler Spielstand, Offline-Nachrechnung, Taskleisten-FenstermodusNicht begonnen

Scheiben 0 + 1: Kampf ohne Bild

Die erste Kampfversion war reiner Text. Drei Truppmitglieder gegen fünf Schergen, Angriffstimer rücken jeden Tick vor, die Konsole druckt pro Treffer eine Zeile: „Nahkampf trifft D1Scherge3 für 18 (HP 72/90)". Das Ziel war eindeutig: erst beweisen, dass die Mathematik stimmt und die Schleife Spaß macht, dann Grafik.

Werte folgen einem dreistufigen Stapel im Stil von Diablo 2:

final = (base + Σflat) × (1 + Σadditive) × Π(1 + jede multiplikative Ebene)

Die multiplikativen Ebenen sind „mehrere unabhängige Ebenen, einzeln multipliziert", nicht summiert und einmal angewendet. Das ist Absicht: Das Schwungrad und das Gefühl „ein voller Satz gewürfelter Affixe lässt die Stärke springen" kommen beide von hier. Beim Start läuft ein Selbsttest: base 10, flat 5, additive 50 %, zwei multiplikative Ebenen mit 20 % und 10 %, erwartet 29,7, und bei Abweichung steht FAIL da.

Die Minderungs-Pipeline hat strikt sieben Schritte in fester Reihenfolge: Ausweichen → Blocken (fester Abzug) → Elementarresistenz → abnehmende physische Rüstung → allgemeine Schadensminderung → Absorptionsschild → Boden (jeder Treffer macht mindestens 1). Der Rüstungsschritt ist an die Regionentiefe gekoppelt:

Minderung = Rüstung / (Rüstung + Schwelle), Schwelle = 14 × Tiefe + 12

Rüstung gleich Schwelle halbiert den Schaden exakt. Diese Formel ist der mathematische Haken, der „Tiefe" zu einem Stärketor macht: Derselbe Brustpanzer wird umso schwächer, je tiefer man geht, was ganz natürlich zum Umrüsten drängt.

Der Zufall steckt in einem DetRNG, dessen Seed und interner Zustand gelesen und geschrieben werden können, damit die Schnittstelle für die Offline-Nachrechnung in Scheibe 5 bereitsteht.

Scheibe 2: die Wirtschaft von allein drehen lassen

Die Wirtschaft hat zwei Motoren:

  • Skalenmotor: Region säubern für Vorräte → Unterschlupf ausbauen → Prozentboni für den ganzen Trupp, plus alle drei Stufen ein weiterer Expeditionsplatz.
  • Ausrüstungsmotor: Region säubern für Material → Werkbank ausbauen → schmieden → anlegen → Stärke.

Beide sind über die Expeditionsplätze gekoppelt, und die Bremskette lautet „Regionentiefe → benötigte Stärke → gedeckelt durch Schmiedetiefe / Werkbankstufe". Das Tempo wird nicht durch Zählen von Gegenständen begrenzt.

Das automatische Ausgeben im Leerlauf ist eine deterministische Greedy-Strategie in fester Reihenfolge: Unterschlupf ausbauen, wenn möglich, Werkbank ausbauen, wenn möglich, dann eine Waffe schmieden versuchen. Beim Schmieden gilt eine Schlüsselregel: Ein geschmiedeter Gegenstand wird nur bezahlt und behalten, wenn er eindeutig besser ist als der angelegte; sonst wird er verworfen und kein Material ausgegeben. Stößt das Schmieden also an eine Decke, sammelt sich Material ganz von selbst und fließt in die Werkbank, die ausgebaute Werkbank produziert dann stärkere Stücke, und die beiden Motoren überholen sich gegenseitig ohne jeden zusätzlichen Planungscode.

Verifiziert wird mit einem Headless-Lauf über 12.000 Ticks (20 Minuten Spielzeit) mit Abschlussbericht: Siege und Niederlagen, tiefste erreichte Region, Ressourcenstände, Stufen von Unterschlupf und Werkbank, Inventargröße. Zwei Läufe mit demselben Seed liefern byteidentische Ausgabe; Determinismus bestanden.

Scheibe 3: ein selbstgebautes Schichten-Rig, bewiesen, dann weggelegt

Das Figurenkonzept im Designdokument war aufwendig. Fünf Sprite-Schichten (rechter Arm / Körper / rechte Waffe / linker Arm / linker Gegenstand) in z-Reihenfolge gestapelt, keine Knocheninterpolation (eine 40 Pixel hohe Figur zittert, sobald man interpoliert), stattdessen frame-getriebene Animation mit Pivots pro Frame: Jeder Frame liest einen Satz Koordinaten für rechte Schulter, rechte Hand, linke Schulter und linke Hand, Waffe und Gegenstand rasten an ihren Pivots ein. Die Waffenklasse der rechten Hand ist der einzige Treiber und wählt den Animationssatz für beide Arme; der linke Gegenstand folgt passiv der linken Hand; der Körper ist gemeinsam und wechselt nur bei beidhändigen Nahkampfangriffen auf einen vorgebeugten Körper.

Wir haben das Ganze mit farbigen Rechtecken als Platzhalter durchlaufen lassen: fünf Zustände, Wechsel zwischen vier Waffenklassen, Spiegelung, Pivot-Visualisierung, alles korrekt.

Platzhalter-Rig-Prüfstand: Einhandschwert mit Schild (links) und vorgebeugter Zweihandangriff (rechts); die farbigen Punkte sind die vier Pivots

Dann haben wir eine pragmatische Entscheidung getroffen: auf Eis legen. Die Logik zum Laufen zu bringen ist leicht; fünf Schichten mal fünf Zustände an Pixel-Frames für jede Waffenklasse zu zeichnen ist eine andere Größenordnung, und das ist nicht die Phase, in der man dort Zeit verbringt. Der Bauplan bleibt, der Code bleibt, und die Spielfiguren wechseln auf „Spur B": Ganzkörper-Framesequenzen aus einem fertigen Asset-Pack. Beide Spuren werden vom selben AnimState-Enum getrieben, ein späterer Rückwechsel berührt den Kampfcode also nicht.

Ein Umweg über die Grafik

Zuerst sollte die KI die Pixelfiguren zeichnen. Die Ausgabe kam schnell, aber was ankam, war Fake-Pixel-Art: Es sieht aus wie ein Raster, aber die tatsächliche Zellgröße ist ungleichmäßig, Kanten sind geglättet, und ein „Pixel" enthält mehrere Farben. Auf native Auflösung zurückskaliert wird daraus Brei.

KI-generierter Fake-Pixel-Trupp: aus der Ferne überzeugend, aber hineingezoomt passt das Raster nicht und die Kanten werden weich

Dafür haben wir ein kleines lokales Werkzeug geschrieben: FFT über das Gradientenprofil des Bildes, um die dominante räumliche Periode zu finden, die den wahren Rasterfaktor und die Phase liefert; pro Zelle die dominante Farbe nehmen und auf native Auflösung herunterrechnen; optional die Palette per Median-Cut reduzieren und den transparenten Hintergrund binarisieren. Selbsttests mit synthetischen Fake-Pixel-Bildern rekonstruierten korrekt.

Das Werkzeug funktioniert, aber am Ende sind wir diesen Weg nicht gegangen: Die Zeit fürs Nachbessern ist nicht mehr wert als einfach kaufen. Die aktuelle Grafik stammt aus zwei Asset-Packs: einem postapokalyptischen Paket (ein modularer Held aus handlosem Körper plus Waffenschichten, drei Zombies, eine große Menge Kulissenobjekte) und einem Dark-Series-Monsterpaket (gut zwanzig Monster als einzeilige 90×90-Streifen, vier Sätze sechsschichtiger Parallax-Hintergründe). Beide sind kostenpflichtige kommerzielle Lizenzen, die Weiterverbreitung verbieten, deshalb bleibt das gesamte art/-Verzeichnis außerhalb von git.

Die Packs haben uneinheitliche Groß-/Kleinschreibung in Dateinamen und kodieren Frame-Zahlen im Dateinamen, also haben wir eine ArtDB geschrieben, die alles kleingeschrieben indiziert und das ein für alle Mal löst. Sie indiziert derzeit 1.338 Clips.

Die Darstellungsschicht: so sieht es heute laufend aus

Die Hauptszene ist ein transparenter Streifen von 760×200 mit aktivierter pixelgenauer Transparenz in Godot. Darin läuft eine Schleife aus Marsch → Kontakt → Kampf → Sieg / Niederlage:

  • Marsch: Sechs Parallax-Ebenen scrollen nach Faktor, 0,02 ganz hinten und 1,0 ganz vorn; die Himmelsebene ist abschaltbar.
  • Kontakt: Gegner kommen von links herein, der Nahkämpfer stürmt vor, Pistolen- und Gewehrschütze bleiben auf ihrer jeweiligen Reichweite stehen.
  • Kampf: Jeder Treffer ruft Damage.resolve_hit der Simulation auf, dieselbe Mathematik wie im Headless-Lauf, nur die Choreografie ist jetzt bildratengetrieben. Kugeln fliegen wirklich, Hülsen werden wirklich ausgeworfen und landen, Treffer blitzen weiß mit einem Pixel Rückstoß, dazu Schadenszahlen, Blockmarken und MISS-Text.
  • Kamera: zentriert auf den Trupp, wenn keine Gegner da sind, sonst auf den Mittelpunkt zwischen Trupp und Gegnergruppe, mit Totzone und Geschwindigkeitsdeckel, damit ein einzelner sterbender Gegner das Bild nicht ruckeln lässt.
  • Koordinaten-Rebase: Nach jeder Welle wird die ganze Welt auf die Standardplätze zurückverschoben und die Kamera um dieselbe Strecke entgegengesetzt. Das Bild bewegt sich keinen Pixel, aber Truppmitglieder müssen nie „rückwärts laufen", um sich neu aufzustellen.

Der Wirtschaftskreislauf ist angeschlossen: Wellen-Drops gehen ins Inventar, Vorräte und Material werden gutgeschrieben, Auto-Ausbau- und Schmiede-Ereignisse erscheinen als Toasts. Wird die Stärkeschwelle erreicht, geht es in die nächste Region und der Hintergrund wechselt; eine Niederlage zieht sich eine Region zurück zum Farmen. Es gibt 8 Regionen mit je 10 Wellen, Welle 10 ist ein Boss in 1,5-facher Größe. Ein niedergestrecktes Mitglied bleibt liegen und steht nach 12 Sekunden Aufladung wieder auf, oben rechts erscheint ein kleines weinendes Porträt; außerhalb des Kampfes regeneriert es 5 % pro Sekunde, im Kampf nichts.

Tiefer drin: ein Skelettschütze hält außerhalb der Reichweite Stellung; oben rechts der Stufenfortschritts-Cursor

Schlüsselentscheidungen

EntscheidungWahlWarum
RenderingZwei Spuren: CharacterRig (auf Eis) / ActorSprite (in Gebrauch), gleicher AnimStateBauplan behalten, Optik zuerst mit vorhandenen Assets liefern
TruppSchläger / Pistole / Gewehr, ein Körper per Tönung unterschiedenDas Asset-Pack hat einen Heldenkörper
TodNiedergestreckt, wartet auf Rettung, steht nach Aufladung an Ort und Stelle aufUnterbricht den Idle-Rhythmus nicht
ZahlenDarstellung und Headless teilen Combatant / DamageZwei Mathematiken laufen früher oder später auseinander
GrafikBezahlte Asset-Packs, nicht in gitLizenz verbietet Weiterverbreitung

Werkzeugkette

Engine Godot 4.6, Sprache GDScript, Code von Claude Code auf der Kommandozeile geschrieben. Ein MCP-Plugin im Editor lässt den Agenten den Editor direkt steuern, Szenen starten und Screenshots machen, sodass niemand ständig zwischen Fenstern wechseln muss. Die Headless-Verifikation läuft mit godot --headless, druckt ihren Bericht und beendet sich von selbst.

Als Nächstes

  • Tempo feinjustieren: Monsterwachstum, Dropraten und Regionenschwellen sind alle noch Platzhaltergrößen.
  • Eine UI-Hülle: Seitenpanel und Basiszugang, damit der Spieler Trupp und Beutel sehen kann.
  • Scheibe 4 Expeditionen; Scheibe 5 Spielstände + Offline-Nachrechnung + echtes Taskleistenverhalten (rahmenlos, immer im Vordergrund, an den unteren Rand gedockt).

Dieser Artikel wurde von Claude Code aus dem Projektquellcode und dem Designdokument zusammengestellt. Die Screenshots stammen aus dem aktuellen Build.

Alle Notizen
TOP