Pocket Planet Wiki

Planetensimulation

Regionsraster, Klima, Wasser, Biome, Ereignisse und Offline-Fortschritt.

Konzeptphase. Interne Planungsfassung, Stand 04.11.2026. Pocket Planet ist noch in Entwicklung – Inhalte, Zahlen und Abläufe können sich ändern.

Ziel: spielerisch glaubwürdig, nachvollziehbar, deterministisch, billig. Kein Teil der Simulation kennt Nodes oder Grafik. Alles läuft als reine GDScript-Klassen (RefCounted) und ist headless testbar (11).

3.1 Raster: 642 Regionen

[Vorschlag] Geodätisches Raster aus einem Ikosaeder, 3-mal unterteilt: 642 Regionen (630 Sechsecke + 12 Fünfecke), je Region 5–6 Nachbarn.

KandidatRegionenBewertung
Unterteilung 2162zu grob, Küstenlinien eckig
Unterteilung 3642Kontinente und Inseln gut formbar, Simulation sehr billig
Unterteilung 42562schönere Details, aber 4× Rechenzeit offline

Die Darstellung ist feiner als das Raster: Das Planeten-Mesh hat 10 242 (niedrig) bzw. 40 962 (hoch) Vertices, jede Vertex kennt ihre Region (UV2). Übergänge zwischen Regionen werden im Shader weich gemischt (07).

3.2 Weltzustand (Datenlayout)

Alle Regionsfelder sind PackedFloat32Array/PackedByteArray mit 642 Einträgen (Structure of Arrays). Das ist cachefreundlich, schnell zu speichern und direkt in eine Datentextur zu kopieren.

FeldTypBereichBedeutung
heightf32−4 … +6 StufenHöhe relativ zum Meeresspiegel 0
tempf32°C, −40 … +60berechnet
moistf320 … 1Feuchte
vegf320 … 1Vegetationsdecke
icef320 … 1Eisbedeckung
mineralsu80 … 3Rohstoffe (Vulkane, Gesteinsmeteoriten, Gebirge)
biomeu8Enumabgeleitet, s. 3.5
fertilityf320 … 1Bodenfruchtbarkeit (Vulkanasche, Flussdelta)
riveru80/1Fluss fließt hindurch
protected_untili32ZyklusSchutzgebiet
pollutionf320 … 1ab Epoche 6
dirtyu8BitDarstellung muss aktualisieren

Global: cycle, epoch, sea_level, base_temp_offset (Spieler-Regler), co2 (0–2, 1 = Normal), atmosphere (0–1, Epoche 1–2), oxygen (0–1), seed (u64), rng_state.

Speicherbedarf: 642 × ~40 Byte ≈ 26 KB pro Planet, komprimiert ≈ 8 KB.

3.3 Zyklus-Reihenfolge

step(cycle):
  1  apply_queued_actions()      # Spieleraktionen dieses Zyklus (Command-Liste)
  2  climate.update()            # Temperatur, Eis
  3  hydrology.update()          # Feuchte, Flüsse, Meeresspiegel
  4  terrain.update()            # laufende Verformungen, Erosion (alle 10 Zyklen)
  5  biomes.classify()           # nur Regionen mit Änderung > Schwelle
  6  vegetation.update()
  7  life.update()               # Populationen; alle 20 Zyklen: Mutation, Wanderung
  8  civ.update()                # alle 5 Zyklen: Wachstum; alle 10: Ereignisprüfung
  9  events.update()             # geplante/ausgelöste Ereignisse
 10  progression.check()         # Epochen- und Zielbedingungen
 11  chronicle.flush()           # neue Einträge
 → TickReport { events[], dirty_regions[], kpis }

Budget [Vorschlag]: ≤ 4 ms pro Zyklus auf dem schwachen Referenzgerät (Samsung Galaxy A13, 12), gemessen ab T-06. Da ein Zyklus aktiv nur alle 2 s (Zeitraffer 0,67 s) läuft, sind das < 1 % der Rechenzeit. Die Simulation läuft trotzdem im WorkerThreadPool, damit kein Frame stockt; die Darstellung liest nur abgeschlossene Zustände (Doppelpuffer).

3.4 Klima

Temperatur je Region:

temp = T_breite(lat)                 # +28 °C Äquator … −22 °C Pol, Kosinusverlauf
     + base_temp_offset              # Klima-Regler des Spielers (±10)
     + 6 · (co2 − 1)                 # Treibhaus: Vulkane +, Pflanzen −, Industrie +
     − 4 · max(height, 0)            # Höhenkälte je Stufe
     + ozean_daempfung               # Küsten ±3 °C näher an 12 °C
     − 8 · global_ice_fraction       # Eis-Albedo-Rückkopplung (Eiszeit-Gefahr!)
     + ereignis_offsets              # Aschewinter, Hitzewelle …

Zusätzlich wird temp je Zyklus nur zu 20 % an den Zielwert angenähert (Trägheit). So sieht der Spieler Klimawandel kommen, statt dass er springt.

  • Eis: ice → 1 bei temp < −5 °C, → 0 bei temp > 2 °C (je 5 % pro Zyklus).
  • CO₂-Haushalt: +0,02 je aktivem Vulkan und Zyklus, −0,001 × globale Vegetation, +pollution (Epoche 6). Klemmt auf 0,3–2,0.
  • Eiszeit-Kipppunkt: Steigt global_ice_fraction über 0,35, verstärkt die Rückkopplung sich selbst → Ereignis „Eiszeit“ (§3.6). Das ist bewusst ein spielbarer Kipppunkt, den die Vorschau ankündigt („Achtung: Eis nähert sich dem Kipppunkt“).

3.5 Wasser, Wetter, Biome

Feuchte: Grundwert aus Breitenzonen (Tropen 0,8 · Wendekreise 0,25 · gemäßigt 0,6 · polar 0,3), dazu Nähe zum Ozean (+0,2 bei Küste), Regenschatten (Westwind-Modell: Region hinter Gebirge −0,3) und Spielerregen (zerfällt 3 % pro Zyklus).

Meeresspiegel: Wassermenge water (global) wird auf die Senken verteilt: sea_level = Höhe, bei der das Volumen der Regionen darunter water entspricht (Bisektion, 12 Schritte, nur bei Änderung). Eis bindet Wasser → Meeresspiegel sinkt in Eiszeiten (Landbrücken! → Artenwanderung).

Flüsse [Vorschlag]: Keine Fluidsimulation. Regionen mit moist > 0,55 und Gefälle leiten zum tiefsten Nachbarn; erreicht eine Kette den Ozean, wird sie als Fluss markiert. Neuberechnung alle 10 Zyklen. Flussregionen: fertility +0,2, Siedlungsbonus.

Biome (Whittaker-Tabelle, Höhe vor Klima):

BiomBedingung (vereinfacht)MVPFarbe (Basis)
Tiefseeheight ≤ −2✓#1E4E8C
Flachwasser/Küste−2 < height ≤ 0✓#3FA7D6
Eisice > 0,6✓#EAF4FA
Tundratemp < 2✓#9DB4A0
Gebirgeheight ≥ 4✓#8A7F78
Wüstemoist < 0,25✓#E3C27A
Grasland/Savannemoist 0,25–0,5✓#B9CF6A
Waldmoist 0,5–0,75, temp 2–24✓#4F9A58
Regenwaldmoist > 0,75, temp > 24Phase 3#2E7D4F
Sumpfmoist > 0,85, height ≤ 1Phase 3#5E7F5A
KorallenriffFlachwasser, temp > 22Phase 3#FF9E80
Vulkanlandaktiver Vulkan / frische Lava✓ (Zustand)#3A2A28 + Glut

Vegetation: veg nähert sich der Biom-Kapazität (Wald 0,9, Grasland 0,6, Wüste 0,08 …) mit 4 %/Zyklus, × fertility-Bonus. Gebremst durch Pflanzenfresserdichte (04) und Siedlungsfläche (05).

3.6 Ereignisse

Ereignisse sind Daten (data/events.json): Bedingung, Wahrscheinlichkeit pro Prüfung, Vorwarnzeit, Wirkung, Chronik-Text.

EreignisBedingungVorwarnungWirkungHäufigkeit (Richtwert)
Eiszeitglobal_ice > 0,3515 Zyklen−6 °C, 60 Zyklenselten, durch Spieler auslösbar
Hitzewelleco2 > 1,410+4 °C regional, Dürremittel
DürreRegion moist < 0,3 + Siedlung8Vegetation −50 %mittel
ÜberschwemmungFlussregion + Spielerregen ≥ 35Siedlung in Senke beschädigtselten
Meteorschauerzufällig, ab Epoche 3201–3 Einschlägesehr selten (≤ 1/Woche Echtzeit)
Supervulkan≥ 3 aktive Vulkane in Nachbarschaft20Aschewinter −4 °Cselten
SeucheSiedlungsdichte hoch, Stabilität < 4010Bevölkerung −30 %mittel (Epoche 5+)
Blütezeit (positiv)Gesundheit > 80 für 30 Zyklen–Mutationen 2× schneller, +SEbelohnend

Zufall: PCG32, initialisiert aus seed, ein eigener Strom pro Subsystem (climate, life, civ, events), damit eine Änderung am Lebensmodul die Ereignisfolge nicht verschiebt. Jede Ziehung ist reproduzierbar: gleicher Spielstand + gleiche Aktionen = gleiche Geschichte (Testbarkeit, Benachrichtigungen, Fehlersuche).

3.7 Offline-Fortschritt

Verfahren

  1. Beim Pausieren (NOTIFICATION_APPLICATION_PAUSED) speichern: Weltzustand, last_seen_unix, max_seen_unix (höchster je gesehener Zeitstempel), last_seen_ticks_msec.
  2. Beim Fortsetzen: delta = now_unix − last_seen_unix.
  3. Zeitsicherheit (ohne Server):
    • delta < 0 oder now < max_seen_unix − 300 (Uhr zurückgestellt) → delta = 0, Ereignis clock_rollback lokal protokollieren. Nichts wird abgezogen – nur nichts gutgeschrieben.
    • delta wird auf 12 h gedeckelt. Ein Vorstellen der Uhr bringt also höchstens 12 h Fortschritt und volle Energie – das, was ehrliches Warten auch bringt. Ein Anreiz zum Betrügen entsteht nicht, weil Energie ohnehin bei 100 gedeckelt ist und nichts verkauft wird.
    • Läuft die App nur kurz im Hintergrund (Prozess lebt), wird zusätzlich Time.get_ticks_msec() verglichen (monoton, nicht verstellbar).
  4. Makroschritte: n = floor(delta / 600 s), höchstens 72. Jeder Makroschritt = 75 Zyklen mit vergröbertem Verfahren:
    • Klima/Vegetation/Populationen: analytische Näherung über 75 Zyklen (logistische Lösung statt 75 Einzelschritte).
    • Ereignisse: Prüfungen einmal pro Makroschritt mit hochgerechneter Wahrscheinlichkeit, aus einem eigenen RNG-Strom offline (Seed = seed ⊕ Makroschritt-Index).
    • Mutationen: höchstens 1 pro Art und Makroschritt; Evolutionssprünge werden als anstehende Evolutionskarte gespeichert (max. 3), nicht automatisch entschieden.
    • Schutzregel aus 02 §2.8: katastrophale Ereignisse werden zu anstehenden Ereignissen.
  5. Rest delta mod 600 s geht nicht verloren: Er wird als offline_carry gespeichert und beim nächsten Mal mitgezählt.
  6. Ausführung im WorkerThreadPool; währenddessen spielt die Rückkehr-Animation. Budget: 72 Makroschritte ≤ 1,5 s auf dem schwachen Referenzgerät (≈ 20 ms je Makroschritt).
  7. Ergebnis: ReturnSummary (Top-5-Ereignisse nach Gewicht, Kennzahlen vorher/nachher) → Rückkehr-Karte.

Warum feste Makroschritte?

Weil das Ergebnis dann nur von der Zahl der Makroschritte abhängt, nicht vom genauen Öffnungszeitpunkt. Damit kann das Spiel beim Pausieren eine Vorausberechnung machen (13): „Nach 6 Makroschritten entsteht ein Dorf“ → Benachrichtigung in 60 Minuten. Öffnet der Spieler die App später, rechnet sie exakt dieselben Schritte – die Benachrichtigung war wahr.

Fairness bei langer Abwesenheit

  • Nach 12 h stoppt der Fortschritt, aber nichts verfällt: Energie voll, Tagesaufgaben neu, bis zu 3 anstehende Entscheidungen.
  • Ab 3 Tagen Abwesenheit: „Willkommen zurück“-Geschenk (+50 SE Überladung, einmalig pro Woche) – ohne Strafe, ohne Druck.

3.8 Chronik (Ereignisprotokoll)

{ "c": 412, "k": "ice_age_start", "r": [118, 119, 140],
  "p": { "cause": "ash_winter", "volcano": "Glutkamm", "species": ["sp_17"] },
  "w": 80 }
  • c Zyklus · k Ereignisart · r Regionen · p Parameter · w Gewicht (für Zusammenfassungen).
  • Texte entstehen erst beim Anzeigen aus Vorlagen (data/chronicle_templates/<lang>.json) – das Protokoll bleibt sprachneutral und klein.
  • Begrenzung: 2000 Einträge pro Planet; ältere niedrig gewichtete Einträge werden zu „Zeitalter“-Zusammenfassungen verdichtet.

3.9 Ortsnamen

Kontinente, Gebirge und Meere bekommen automatisch Namen aus Silbentabellen pro Sprache („Glutkamm“, „Nordmeer von Ilva“), sobald sie entstehen (Zusammenhangskomponenten im Raster, Prüfung alle 20 Zyklen). Der Spieler kann umbenennen. Namen machen die Chronik lebendig und kosten nichts.

3.10 Testbarkeit

  • tests/test_sim_determinism.gd: gleicher Seed + gleiche Aktionsliste → identischer Zustands-Hash nach 1000 Zyklen.
  • tests/test_offline.gd: Vorausberechnung beim Pausieren = Nachrechnung beim Öffnen (Hash-Vergleich); Uhr zurück → kein Fortschritt; 48 h → genau 72 Makroschritte.
  • tests/bench_sim.gd: Zyklus- und Makroschritt-Zeit, Ausgabe als JSON (Grenzwerte aus 12).