champions-of-luneraria/docs/port/U2-WORLD.md
Martin Stickelbroeck 323cc3ae00 U2D Playable Unity Match
Vollständige Bot-Partien sichtbar in Unity, gleich der Partie des Kerns
(Vertical Function Test vor dem vollständigen Asset-Import).

- VerticalFunctionTests (PlayMode): Seed 2 von Runde 1 bis zum Fall des
  Blau-Ancient (9 Runden; Türme fallen ab Runde 7, Grottenboss in Runde 8
  gewonnen und in Runde 9 auf der Bot-Lane eingesetzt, bis zu 4 Helden) und
  Seed 9 ab Runde 21 mit der Fixture des Golden-Szenarios high_wave_21 (bis zu
  125 Einheiten, 6 Helden, Fall des Rot-Ancient). Beide Fingerabdrücke gleich
  dem Kernlauf; 14 Bilder der Schlüsselmomente.
- macOS-Player-Build (LunePlayerBuild) und LuneBenchmark: 1080p, VSync aus,
  116 Einheiten: 161-199 fps, Hauptthread 1,3 ms, Simulation unter 0,1 ms;
  Ausreißer beim Present (p95 18-26 ms) analysiert und für U5 vorgemerkt.
- Dokumentation: U2-WORLD (U2D, Abnahme), PORT-STATUS, PORT-QA,
  KNOWN-BEHAVIOR-DIFFERENCES (U2 ändert kein Verhalten), README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 17:31:19 +02:00

26 KiB
Raw Blame History

U2 · Unity-Spielwelt

Stand: 1. Oktober 2026.

Teil Inhalt Zustand
U2A Blender→FBX-Pipeline, sechs repräsentative Assets vollständig geprüft fertig
U2B Weltgeometrie (G1-Karte, Türme, Ancients, Grotte, Aufstellungsbereiche), Materialsystem fertig
U2C Simulation/Darstellung: fester Takt, Interpolation, Bildraten-Unabhängigkeit fertig
U2D spielbare Unity-Partie, Vertical Function Test fertig

Voraussetzung U1.5 ist erfüllt (U1.5-UNITY.md).

Ziel

Die bestehende Partie läuft sichtbar in Unity (URP). Das ist noch keine grafische Neugestaltung; die kommt erst mit U5.

Zuerst kommen:

  • die G1-Drei-Lane-Karte,
  • die G2-Türme (Grenzwacht, Bastion, Kernwacht),
  • die G2-Ancients,
  • die Bossgrotte und die Schlundkrone,
  • repräsentative vorhandene Einheiten.

Vorgaben

  • Adapter: Unity treibt LuneMatch im festen Takt (0,05 s) über einen Akkumulator, unabhängig von der Bildrate. Ansichten lesen nur; sie schreiben nie in die Regeln. Beispiel: Gebäude-HP = 0 führt zu Einsturz und Ruine, nie umgekehrt eine Animation zu einer Regelwirkung.
  • Gemeinsames Materialsystem (URP): Stein, Metall, Holz, Vegetation, Kristall, Runen, Wasser. Die G2-Shader aus Godot (stone, metal, crystal, rune, cloth, vein, water_glow, hide) dienen als fachliche Vorlage.
  • Assets: Quelle sind die Blender-Dateien und Generatoren im Referenz-Repository. Ein zentraler, reproduzierbarer Blender-Export erzeugt FBX; GLB nur, wo keine bearbeitbare Quelle existiert.
  • Reihenfolge: Erst sechs repräsentative Assets vollständig prüfen, dann die Welt und eine vollständige Bot-Partie. Den Batchlauf über alle Assets gibt es erst nach dem Vertical Function Test.

U2A · Blender→FBX-Pipeline

Aufbau

Datei Aufgabe
tools/blender/export_manifest.json Asset-Liste: Blender-Quelle, Art (statisch, starre Teile, Skelett), Exportregeln und Verweis auf den Godot-Manifesteintrag des GLB, das die Referenz benutzt
tools/blender/lune_fbx_export.py Blender im Hintergrund: Quelle öffnen, Regeln anwenden, prüfen, FBX schreiben, FBX wieder einlesen und erneut prüfen
tools/blender/export_fbx.sh Einstieg; macht die FBX-Dateien byteidentisch reproduzierbar
Assets/Luneraria/Art/<Gruppe>/<id>.fbx und <id>.export.json Ergebnis: Modell und Protokoll (Blender-Fakten und Prüfungen)
Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs Importregeln in Unity
Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs Unity-Prüfung jedes importierten Modells gegen das Blender-Protokoll
Assets/Luneraria/Editor/Art/LuneAssetPreview.cs Vorschaubilder in URP
sh tools/blender/export_fbx.sh
/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LuneAssetVerifier.VerifyAll -logFile -

Weitere Einstiege: LuneAssetVerifier.ReimportArt (nach geänderten Importregeln) und LuneAssetPreview.RenderAll.

Exportregeln

Die Regeln wiederholen, was die Godot-Pipeline beim GLB-Export getan hat. Sonst entstünde ein anderes Modell:

  • Phase-4-Einheiten: Die Modifikatoren „HIGH RES“ (Unterteilung und Mikrorelief) kamen erst nach dem Laufzeitexport in die .blend-Datei. Sie werden nicht angewendet (bei g01: 36 Stück).
  • Logische Namen: Die Namen stammen aus den Eigenschaften part_name und material_name; Blender hatte teils Suffixe wie .004 ergänzt.
  • Figuren mit Skelett: Die .blend-Datei ist vor dem Zusammenfügen gespeichert. Der Export fügt die Teile wie in Godot zu einem Skin-Mesh zusammen (Funkenlanze: 104 Teile → FunkenBody).
  • Achsen: Die FBX-Datei behält Blenders Z-oben-Achsen; Unity rechnet sie beim Import mit „Bake Axis Conversion“ um, also ohne Wurzelrotation. Blender (x, y, z) wird dabei Unity (x, z, y); die Vorderseite (Blender −Y) läge auf Unity −Z.
    • Deshalb dreht der Export jedes Asset vorher um 180° um die Hochachse und wendet die Drehung an. Danach gilt Unity = (−x, y, z) der Godot-/glTF-Koordinaten, und die Vorderseite liegt auf +Z wie in Godot.
    • Blenders „Apply Transform“ ist für Skelette als fehlerhaft dokumentiert und wird nicht benutzt.
  • Maßstab und Inhalt: 1 Blender-Einheit = 1 m; Normalen, Tangenten (MikkTSpace, wo UVs existieren), lineare Vertexfarben; nur Deform-Bones, keine Leaf-Bones; jede Action wird ein Clip.
  • Reproduzierbarkeit: Blenders FBX-Schreiber stempelt die Uhrzeit ein und leitet Objekt-IDs aus Pythons String-Hash ab. Der Export fixiert beides (feste Uhrzeit, PYTHONHASHSEED=0 mit --python-use-system-env). Zwei Läufe liefern byteidentische FBX-Dateien und identische Protokolle.

Prüfungen

Blender-Seite, vor und nach dem Schreiben (Rundreise durch einen FBX-Import):

Prüfpunkt Wie
Einheiten, Maßstab metrisch, scale_length 1, keine Objektskalierung, keine negative Skalierung
Achsen, Vorderseite Drehung angewendet; Vorwärtsmarker (Phase 4: Empty Forward) liegt in Unity auf +Z
Mesh-Namen eindeutig; gleich den Knoten des Godot-GLB
Dreiecke gleich dem Godot-GLB, auch nach dem Wiedereinlesen
Materialslots keine leeren Slots; Materialien gleich dem Godot-GLB
Normalen Einheitslänge an allen Ecken
Tangenten Voraussetzungen (UVs, keine N-Ecke); Meshes ohne UVs sind vermerkt und werden triplanar oder unbeleuchtet schattiert
Maße Ruhelage gleich den bounds_godot des Godot-Manifests (Türme und Ancient: ohne Schadens- und Ruinenteile, wie dort gemessen)
Skelett genau eine Armature, ein Root Bone Root, Bone-Namen und -Anzahl wie im Godot-GLB, portable Namen
Clips Namen und Längen wie im Godot-GLB; Pflichtclips vorhanden; Loop-Flag und Kontaktzeit aus den Action-Eigenschaften
Blend Shapes keine in den Quellen

Unity-Seite (LuneAssetVerifier, gegen das Blender-Protokoll):

Prüfpunkt Wie
Importregeln Maßstab 1, Dateieinheiten, Achsen-Bake, Normalen und Tangenten aus der Datei
Achsen Wurzel und alle Nicht-Bone-Knoten ohne Rotation und Skalierung
Mesh-Namen, Dreiecke Menge und Anzahl je Mesh gleich
Maße aus den Vertices berechnet, Abweichung höchstens 2 mm; gemessen höchstens 0,05 mm
Materialslots Namen je Renderer gleich den Blender-Slots
Normalen, Tangenten, UVs, Vertexfarben vorhanden und gültig, wo Blender sie hat; Tangenten mit w = ±1
Vorderseite Vorwärtsmarker auf +Z
Skelett Root Bone, Bone-Namen, gültiger Generic-Avatar
Clips Namen, Längen (auf einen halben Frame genau), Loop-Flags, Kontakt-Events (OnLuneContact)

Ergebnis: sechs repräsentative Assets und drei Szenenbauten

Asset vertritt Dreiecke (= Godot-GLB) Blender-Prüfungen Unity-Prüfungen
g01 Kohlenbeißer normale Einheit, 131 benannte Teile 79.780 18/18 14/14
funkenlanze Einheit mit Skelett (Held), 26 Bones, 9 Clips 24.036 26/26 18/18
grenzwacht Turm (mit Schadens- und Ruinenteilen) 6.516 18/18 13/13
ancient Mondherz Ancient 19.032 18/18 13/13
schlundkrone Schlundkrone (Boss), 24 Bones, 11 Clips 5.712 28/28 18/18
map_props Vegetation und Kartenrequisiten (Eichen, Kiefern, Sträucher, Felsen, Brücke, Randsteine) 7.338 14/14 13/13
bastion, kernwacht, bossgrotte für die Szene in U2B (Innen- und Basisturm, Mondschlund) 9.364, 9.224, 15.182 je 18/18 je 13/13

Summe: 176 Blender-Prüfungen und 128 Unity-Prüfungen, alle bestanden. Protokolle:

  • Assets/Luneraria/Art/*/*.export.json (Blender).
  • docs/port/logs/u2a/unity-verify.json (Unity).

Bilder unter docs/port/screenshots/u2a/:

  • je Asset eine Ansicht von vorn-rechts,
  • die Grenzwacht zusätzlich als Ruine,
  • Funkenlanze und Schlundkrone zusätzlich im Kontaktframe von attack_a (Clips laufen).

Bekannte Grenzen

  • Materialien: Die Vorschau benutzt URP-Lit-Materialien, die Unity aus den FBX-Materialbeschreibungen erzeugt (Blender-Palettenfarben). Das eigentliche Materialsystem (Stein, Metall, Kristall, Runen, Stoff, Wasser; Teamfarben; Vertex-AO) folgt in U2B.
    • Stoff (Wimpel, Banner) ist einseitig modelliert und braucht dort doppelseitiges Rendern; in der Vorschau fehlt er deshalb.
  • Ohne UVs: Diese Meshes haben keine Tangenten (Unity meldet das beim Import): Kristalle, Trümmer, Felsen, Kartenrequisiten und einige Phase-4-Kleinteile. Sie brauchen triplanare oder unbeleuchtete Materialien.
  • Starre Einheiten: Die Phase-4-Einheiten werden in Godot aus benannten Teilen prozedural animiert. Die Teile kommen mit, die Animation folgt mit den Einheitenansichten.
  • Größe: Die FBX-Dateien liegen direkt im Repository (9 Dateien, 16 MB). Für den Batchlauf über alle Assets ist Git LFS zu erwägen.

Batchlauf (nach dem Vertical Function Test)

Das Manifest enthält bisher die 9 Assets der Szene. Die übrigen Assets kommen erst nach U2D in das Manifest und werden dann mit denselben Regeln und Prüfungen exportiert:

  • 58 weitere Phase-4-Modelle.
  • 5 Figuren mit Skelett.
  • 7 Völker-Modelle. Für Zwerg und Troll fehlt die .blend-Datei im Referenz-Repository; sie entsteht aus dem Generator build_peoples.py.

Bauten aus einer GLB ohne Quelle folgen nur nach Einzelfallprüfung.

U2B · Weltgeometrie

Quellen

Die Szene Assets/Luneraria/Scenes/G1_Map.unity entsteht reproduzierbar aus drei Quellen, ohne Handarbeit:

Quelle liefert Weg nach Unity
Godot-Generator der G1-Welt (lune_world.gd, lune_terrain.gd) Gelände, Wasser, Lanebeläge, Plattform, Brücke, Randsteine, Basen, Landmarken, Vegetation, Adern, Grottentreppen, Aufstellungsbereiche, Licht tools/godot-golden/world_export.gd backt die Welt nach Assets/Luneraria/World/Bake/ (JSON und Binärdaten); LuneWorldBuilder baut daraus Meshes und Szene
Blender-Pipeline (U2A) Türme, Ancients, Grotte, Requisiten FBX-Modelle, in der Szene als Prefab-Instanzen
C#-Kern Gebäude-IDs, Positionen, Ausrichtung LuneMap direkt; die Szene enthält keine eigenen Kartendaten

Warum gebacken statt portiert:

  • Gelände und Vegetation hängen an Godots FastNoiseLite und Zufallsgenerator. Ein Nachbau wäre nicht nachweisbar exakt; der Bake ist es.
  • Es gibt für diese Welt keine Blender-Quelle; ihre Quelle ist der Generator. Der Bake ist dessen reproduzierbarer Export, kein GLB-Umweg.
  • U5 bekommt ohnehin eine neue Weltquelle.
HEADLESS=0 sh tools/godot-golden/run_godot.sh world_export --out="$PWD/Assets/Luneraria/World/Bake"
/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LuneWorldBuilder.BuildScene -logFile -

Der Bake braucht einen echten Renderer (HEADLESS=0). Godots Headless-Renderer liefert für MultiMesh-Instanzen Einheitstransformationen; so lag im ersten Versuch die ganze Vegetation im Kartenmittelpunkt. Das Werkzeug bricht jetzt ab, wenn es so einen Bake erkennt.

Inhalt

Teil Umfang
Gelände 121 × 121 Punkte (1 m) plus Bergring 67 × 67 (4 m), Zonenfarbe und Felsanteil als Vertexfarbe, Dreiecksmuster wie in Godot
Welt 59 Knoten: 35 Einzelmeshes, 98 MultiMesh-Instanzen (Randsteine ausgenommen), 532 Requisiten (372 Vegetation und Felsen, 159 Randsteine, Brücke)
Bauten 16 Türme (Grenzwacht, Bastion, Kernwacht), 2 Ancients, Bossgrotte; Positionen und Blickrichtung aus dem Kern; Teammaterialien
Aufstellungsbereiche 3 je Team und Grotteneingänge, ausgeblendet (Planungsphase schaltet sie ein)
Höhen LuneGround: Lauf-Höhe (1-m-Raster) und Standhöhe mit Plaza, Stufen und Grottenterrasse (0,5-m-Raster) für Figuren
Licht Sonne und Aufhellung aus dem Bake, flaches Umgebungslicht, prozeduraler Himmel, ACES, Bloom, Kontrast/Sättigung wie lighting.gd; kein Nebel (wie in Godot)

Koordinaten: Unity = (−x, Höhe, y) der Kartenpunkte. Mit dem Wechsel der Händigkeit bleiben Bild und Vorderseiten der Dreiecke erhalten; die Indexfolge bleibt deshalb unverändert. Gemeinsame Umrechnung: Assets/Luneraria/View/LuneSpace.cs.

Reproduzierbarkeit:

  • Der Bake ist deterministisch (Godot-Generator mit festen Seeds).
  • Der Builder aktualisiert Meshes und Materialien an Ort und Stelle; ihre GUIDs bleiben über Builds gleich.
  • Nur die Datei-IDs der Szenenobjekte wechseln; das ist bei per Skript erzeugten Szenen unvermeidlich.

Materialsystem

Alle Materialien verwenden Luneraria/Surface (URP, HLSL, SRP-Batcher-fähig) oder Luneraria/Pad. Portiert sind:

  • das Gelände (lune_terrain.gdshader),
  • die Kluft-Oberflächen (sanctuary.gdshader: Stein, Pflaster, Erde, Rinde, Laub mit Wind),
  • der Fluss (river.gdshader),
  • die Energieadern (lune_vein.gdshader),
  • die Aufstellungsbereiche (lune_pad.gdshader).

Mit dabei sind jeweils triplanarer Kalkstein und Relief aus Bildschirmableitungen, wie in Godot.

Die G2-Oberflächen (LN_*) haben Werte und Teamvarianten aus lune_materials.gd: Kristall, Rune, Teammetall, Stoff; Blau, Rot und neutral. Vertex-AO wird mit verrechnet. LuneMaterialSet.Dress tauscht die Importmaterialien wie Godots dress gegen die geteilten Materialien.

Vereinfacht gegenüber Godot, bis U5 die Oberflächen neu macht:

  • Quaderfugen der Steinshader, Runenglyphen (stattdessen ein schwach leuchtendes Band), Kristalltiefe, Stoffembleme.
  • Beschädigungs- und Einsturzparameter der Materialien.

Befund beim Einrichten: Unity reicht [HDR]-Farben unverändert als linear weiter, gewöhnliche Farben konvertiert es aus Gamma. Das war am blassen Kristall zu sehen. Emission wird deshalb als linearer Wert gesetzt (LuneMaterialFactory.Hdr).

Vergleich mit Godot

LuneWorldCapture.CaptureAll fotografiert die Szene mit den Kameraeinstellungen der Godot-G2-Aufnahmen (g2_views.gd: Fokus, Zoom, Drehung; Kamera wie lune_camera.gd). Die Bilder liegen unter docs/port/screenshots/u2b/, das Gegenstück unter ../saumwacht-godot/docs/luneraria/screenshots/g2/nachher/.

Bild Befund
15-gesamtkarte Anordnung gleich: Blau unten links, Rot oben rechts, Grotte links, Kluft von der Quelle unter der Plattform zum Delta mit Brücke; Waldinseln, Randsteine, Mauern, Runensteine an denselben Stellen
01-ancient-100, 07-basistuerme Ancient und Basistürme in gleicher Lage und Ausrichtung, Teamfarben richtig
05-tower1-grenzwacht, 06-tower2-bastion Turm, Tür, Wimpel, Randsteine und Plattformsteine decken sich im Bildausschnitt
10-grotte Arena, Tor, Säulen und Treppen gleich; der schlafende Boss und die Grottenzustände kommen mit der Anbindung (U2C/U2D)

Unterschiede:

  • Godot zeigt in allen Bildern das HUD (U3) und in der Planungsphase die Aufstellungsbereiche.
  • Die Materialien sind vereinfacht (siehe oben).
  • Die Beleuchtung ist ähnlich, aber nicht identisch abgestimmt.

U2C · Simulation und Darstellung

Aufbau

Teil Aufgabe
LuneClock fester Takt: Bildzeit geht in einen Akkumulator, heraus kommen ganze Schritte zu 0,05 s (LuneBalance.SimStep); Alpha ist der Bruchteil des nächsten Schritts
LuneMatchRunner Host-Ablauf einer Bot-Partie: Planung (die sechs Bots planen über die Befehlsschnittstelle), Kampf in festen Schritten, Pause nach der Abrechnung, nächste Runde, bis ein Ancient fällt; reine Logik ohne Unity
LuneMatchDriver MonoBehaviour: Update reicht nur Bildzeit × Spieltempo an den Takt weiter
LuneMatchView liest den Kern (nach dem Driver): eine Einheitenansicht je Einheit und Kampf, Gebäudezustände aus den autoritativen HP, Turmblitze aus den Angriffsereignissen der Türme
LuneUnitView Position zwischen den letzten beiden Schritten interpoliert, Blickrichtung, Clips aus echten Kampfereignissen, Teamring, Lebensbalken
LuneBuildingView fünf Zustände wie in Godot (intakt, leicht, schwer beschädigt, Einsturz, Ruine); fällt ein Gebäude unter den Augen des Betrachters, stürzt es 1,7 s lang ein
LuneTrace Fingerabdruck einer Partie (FNV-1a über jeden Schritt und jede Abrechnung) zum Vergleich mit dem reinen Kernlauf

Regeln bleiben im Kern:

  • Die Szene besitzt keine. Update() entscheidet nie über den Kampf; die Bildrate bestimmt nur, wie viele Schritte in ein Bild fallen, nie, was ein Schritt tut.
  • Ansichten schreiben nichts zurück; eine Animation löst keine Regelwirkung aus.
  • Umgekehrt führen Kernzustände zu Darstellung: Gebäude-HP 0 → Einsturz und Ruine; Angriffszähler → Clip und Turmblitz.

Nachweis Bildraten-Unabhängigkeit

Logisch (EditMode, FrameRateIndependenceTests): Der Runner bekommt verschiedene Bildzeitfolgen. Jede muss Schritt für Schritt und Runde für Runde den Fingerabdruck des Kernlaufs ergeben (LuneTrace.RunCore).

Bildfolge Seed 2 (volle Partie) Seed 9 ab Runde 21
30 fps 19.315 Bilder, gleich 6.342 Bilder, gleich
60 fps 38.597 Bilder, gleich 12.678 Bilder, gleich
120 fps 77.169 Bilder, gleich 25.352 Bilder, gleich
unbegrenzt (0,4–3,9 ms, schwankend) 569.627 Bilder, gleich 99.090 Bilder, gleich
Ruckler (Stillstände bis 0,4 s) 26.845 Bilder, gleich 8.796 Bilder, gleich
Spieltempo 8× gleich –

Seed 2 ergibt jedes Mal 12.690 Schritte mit Fingerabdruck DCE95C96556F3A1A, Seed 9 jedes Mal 4.195 Schritte mit 7B8E43AEFC0D60C5.

In der echten Szene (PlayMode, SceneFrameRateTests): Die Partie mit Seed 2 läuft mit allen Ansichten bei Application.targetFrameRate 30, 60, 120 und unbegrenzt (VSync aus), bei Spieltempo 24×.

Ziel gemessen Bilder Schritte je Bild höchstens Ergebnis
30 fps 30,0 fps 816 17 gleich dem Kern
60 fps 60,0 fps 1.626 9 gleich dem Kern
120 fps 120,0 fps 3.227 6 gleich dem Kern
unbegrenzt 4.696 fps 125.732 3 gleich dem Kern

Im Batchmodus zeichnet Unity kein Bild auf einen Bildschirm; daher die sehr hohe Rate bei „unbegrenzt“. Die Bildzeiten mit Grafik stehen bei U2D (Player). Protokoll: logs/u2c/scene-frame-rates.json.

Bekannte Grenzen

  • Einheitenmodelle: Bis zum Batch-Import zeigen Einheiten die repräsentativen Modelle. Truppen, Monster und Champions sind der Kohlenbeißer (131 Teile zu einem Mesh zusammengefasst), Helden die Funkenlanze, Bosse die Schlundkrone. Teamringe (rund, Raute, Sechseck) und Balken unterscheiden die Seiten wie in Godot.
  • Animation: Die starren Figuren haben nur Schrittwippen und Angriffsausfall; Godots prozedurale Gliederbewegung folgt mit dem Batch-Import. Figuren mit Skelett spielen die Blender-Clips (idle, walk, attack_a/b, ability, death).
  • Weitere Vereinfachungen: Turmblitze sind kurze Linien. Die Einsturzsequenz ist vereinfacht (Kippen und Absinken). Der schlafende Boss zwischen den Kämpfen und die Planungsflächen fehlen noch.
  • Kamera: wie lune_camera.gd (WASD, Mausrad, Q/E, R, O, mittlere Maustaste), vorerst mit dem klassischen Input Manager.

U2D · Spielbare Unity-Partie

Szene und Steuerung

Assets/Luneraria/Scenes/G1_Map.unity, Play im Editor oder der macOS-Player: Eine Bot-Partie läuft (Standard: Seed 2) mit 3 Lanes, 2 Basen, 16 Türmen, 2 Ancients, Grotte und Aufstellungsbereichen auf dem echten C#-Kern.

Teil Funktion
Kamera wie Godot: WASD/Pfeile, Mausrad, Q/E, R, O, mittlere Maustaste
LuneDebugOverlay Runde, Phase, Türme, Ancients, Einheiten, Helden, Boss, Sieger. Das ist eine vorläufige Anzeige, kein HUD; das G3-HUD wird in U3 portiert, nicht neu erfunden
LuneMatchDriver Seed, Startrunde, Fixture-Gold und Spieltempo im Inspector

Menschliche Befehle (Kaufen, Aufstellen, Bereit) kommen mit dem HUD (U3) und dem Netzwerk (U4); bis dahin planen alle sechs Plätze als Bots über dieselbe Befehlsschnittstelle.

Vertical Function Test

VerticalFunctionTests (PlayMode, Test Runner) spielt beide Partien sichtbar in der Szene. Das Spieltempo ist 6×, die Zielbildrate 60. Ein Kameraregisseur fotografiert die Schlüsselmomente; jede Partie muss den Fingerabdruck des reinen Kernlaufs ergeben.

Partie Verlauf Ergebnis
Seed 2, ab Runde 1 siehe unten Rot gewinnt („Ancient von Blau zerstört.“); 12.690 Schritte, Fingerabdruck DCE95C96556F3A1A = Kern
Seed 9, ab Runde 21 (Fixture wie das Golden-Szenario high_wave_21: Runde 21, je 4.000 Gold) Wellen über 20 mit bis zu 125 Einheiten und 6 Helden; Runde 21: 3 Rot-Türme fallen; Runde 22: Rot-Turm, beide Rot-Basistürme, ein Blau-Turm und der Rot-Ancient fallen Blau gewinnt („Ancient von Rot zerstört.“); 4.195 Schritte, 7B8E43AEFC0D60C5 = Kern

Verlauf der Partie mit Seed 2:

  • 9 Runden, bis zu 84 Einheiten.
  • Runde 7: erster Turm fällt (blau_bot_outer).
  • Runde 8: Rot gewinnt den Grottenboss; rot_top_outer und rot_top_inner fallen.
  • Runde 9: Der Boss zieht für Rot über die Bot-Lane. Bis zu 4 Helden kämpfen. Blaus Bot-Innenturm, beide Basistürme und der Ancient fallen.

Kein Bot-Spiel erreicht von Runde 1 aus die Welle 20: Ein Durchlauf über 200 Partien (5 Profile × 40 Seeds) endete immer nach 8 bis 12 Runden. Deshalb zeigt die zweite Partie die hohen Wellen mit derselben öffentlichen Fixture wie die Golden-Referenz.

Bilder (docs/port/screenshots/u2d/):

Bild zeigt
01-runde1-aufmarsch, 02-runde1-mid-kampf Aufmarsch auf drei Lanes, erster Kampf in der Mitte mit Turmblitz
03-turm-faellt, 04-turm-ruine Einsturz eines Turms und seine Ruine (Kamera von der Lane aus)
05-grotte-bosskampf Schlundkrone kämpft in der Grotte
06-held-kaempft Helden im Kampf
07-boss-auf-der-lane eingesetzter Boss mit Rots Armee auf der Deltabrücke
08-ancient-faellt, 09-ancient-ruine, 10-ende-uebersicht Fall des Blau-Ancient, Ruine, Endstand
11-welle21-uebersicht, 12-welle21-kampf, 13-ancient-rot-faellt, 14-welle-ende Welle 21: Übersicht, Massenkampf, Fall des Rot-Ancient

Protokoll: logs/u2d/vertical-function-test.json, mit Runden, Ereignissen, Bosslog und Bildliste.

Leistung

Player (macOS, Mono, Release; Apple M5, Metal; 1920 × 1080 im Fenster, VSync aus): Seed 9 in Runde 21, Spieltempo 1×, gemessen ab 10 s Kampf mit LuneBenchmark.

Ansicht Einheiten fps (Mittel) Bildzeit Median p95 Hauptthread (Mittel/p95) Render-Thread Warten auf Present (Mittel/p95)
ganze Karte (Zoom 64) 116 161–199 2,3–2,9 ms 18–26 ms 1,3 / 2,0 ms 1,3 ms 4,9 / 24 ms
Mid-Lane nah (Zoom 22) 63 274–354 1,9–2,5 ms 9–13 ms 0,9 / 1,3 ms 0,9 ms 2,7 / 13 ms

Die Spannen stammen aus vier Läufen.

Was die Zahlen zeigen:

  • Je Bild kosten die Simulation 0,02–0,07 ms und die Ansichten 0,12–0,14 ms.

  • Die Ausreißer sind Wartezeit beim Present. Nur 4–27 der langsamen Bilder fielen mit einem Simulationsschritt zusammen.

  • Garbage Collection war nicht die Ursache. Die Debug-Anzeige erzeugte zwar Müll in jedem Bild; das ist behoben (78 statt 111 Sammlungen in 20 s), änderte die Ausreißer aber nicht.

  • Metal liefert in Unity keine GPU-Zeitstempel. Ob GPU oder Fenster-Compositor wartet, bleibt deshalb offen. Kandidaten:

    • die Platzhaltermodelle (80.000 Dreiecke je Einheit, über 9 Millionen Dreiecke in der Übersicht),
    • vier Schattenkaskaden bis 190 m,
    • der Fenstermodus.

    Das gehört zu U5 (LOD, Dreiecksbudget, Vollbild).

Rohdaten: logs/u2d/player-benchmark-macos.json. Windows- und Linux-Player brauchen die fehlenden Build-Module (U1.5-UNITY.md).

/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LunePlayerBuild.BuildMac -logFile -
Builds/macOS/Luneraria.app/Contents/MacOS/luneraria-unity -screen-width 1920 -screen-height 1080 -screen-fullscreen 0 -luneBenchmark "$PWD/tools/out/player-benchmark.json"

Abnahme U2

Vorgabe Stand
Reproduzierbarer Blender→FBX-Export mit Prüfung von Einheiten, Maßstab, Achsen, Vorderseite, Root Bone, Bone-Namen, Mesh-Namen, Materialslots, Normalen, Tangenten, Clips; keine Handarbeit erfüllt (U2A)
Sechs repräsentative Assets vollständig in Unity geprüft, vor dem Batchlauf erfüllt (U2A); Batchlauf erst nach diesem Test, also jetzt freigegeben
Erste spielbare Szene mit echter Karte (3 Lanes, 2 Basen, 16 Türme, 2 Ancients, Grotte, Aufstellungsbereiche), an den echten Kern gebunden erfüllt (U2B, U2D)
Szene besitzt keine Regeln; Zustand → Darstellung, nie umgekehrt erfüllt (U2C)
Fester Takt, Update() entscheidet nie über den Kampf, Darstellung interpoliert erfüllt (U2C)
Gleiches Ergebnis bei 30, 60, 120 fps und unbegrenzt erfüllt, logisch und in der echten Szene (U2C)
Vertical Function Test: vollständige Bot-Partie sichtbar, 3 Lanes, Wellen > 20, Türme fallen, Helden kämpfen, Boss nutzbar, Ancient fällt, Partie endet, gleich der Kernpartie erfüllt; Wellen > 20 über die Golden-Fixture (siehe oben)

Bekannte Grenzen

  • Platzhaltermodelle: Alle Einheiten zeigen bis zum Batch-Import die repräsentativen Modelle (siehe U2C).
  • Debug-Anzeige statt HUD: Das G3-HUD folgt in U3. Es gibt noch keine menschlichen Befehle und kein Planungsbild für einen Spieler.
  • Materialien vereinfacht (siehe U2B); keine Partikeleffekte; Turmblitze sind einfache Linien.
  • Leistungsspitzen beim Present offen (siehe oben).

Abnahme (gesamt)

  • Die Partie läuft sichtbar.
  • Die Kamera entspricht der Godot-Kamera.
  • Screenshots neben den Godot-G2-Bildern mit vergleichbarer Kamera.
  • Leistung gemessen, einschließlich Mono-Simulationszeit.
  • Bekannte Unterschiede dokumentiert.
  • Commits U2A bis U2D auf luneraria/u2.