feat(shop): configurable package display rotation, pocoregal shelf model

Add _displayRotationEuler to Lieferkarton/ShelfSlot so package prefabs
with a non-upright export orientation can be corrected per-container
without touching PackageDisplay code. Fixes a bug where flying packages
landed with a different rotation than the resting shelf display
(PlayerCarry used the raw shelf transform instead of
ShelfSlot.GetSlotWorldRotation()).

Also adds the pocoregal shelf model (Blender export) and its materials,
places it in the Shop scene, registers ShelfSlot as a network prefab,
and rescales EmptyBox. See docs/PACKAGE_DISPLAY_SETUP.md for the
display-grid setup/troubleshooting reference.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 16:13:32 +02:00
co-authored by Claude Sonnet 5
parent 8ca4858082
commit 9eb588e491
19 changed files with 1126 additions and 285 deletions
+108
View File
@@ -0,0 +1,108 @@
# Package-Anzeige einrichten (Karton & Regalfach)
Wie man `PackageDisplay` (Karton-Inhalt, Regal-Bestand) so einstellt, dass
Verpackungen sauber ausgerichtet und ohne Überlappen im Raster liegen.
Betrifft `Lieferkarton.cs` und `ShelfSlot.cs` — beide haben dieselben vier
Inspector-Felder unter „Anzeige-Raster".
## Kurzfassung: ja, das ist alles konfigurierbar
Kein Code nötig. Vier Felder pro Objekt:
| Feld | Bedeutung |
|--------------------------|--------------------------------------------------------------|
| `_displayColumns` | Päckchen pro Reihe (X-Achse im lokalen Raum) |
| `_displayRows` | Reihen pro Lage (Z-Achse), bevor eine neue Lage nach oben beginnt |
| `_displaySpacing` | Abstand zwischen Päckchen-Mittelpunkten (X/Y/Z in Metern) |
| `_displayRotationEuler` | Zusätzliche Rotation (Grad), mit der jedes Päckchen platziert wird |
Die Formel dahinter (`PackageDisplay.SlotLocalPosition`):
```
Lage = Index / (Spalten × Reihen)
Rest = Index % (Spalten × Reihen)
Reihe = Rest / Spalten
Spalte= Rest % Spalten
Position = (Spalte × spacing.x, Lage × spacing.y, Reihe × spacing.z)
```
## Warum die Päckchen "komisch" aussehen
Zwei typische Ursachen — beide liegen am **Prefab selbst**, nicht am Raster-Code:
### 1. Falscher Pivot (Ursprung) im Prefab
`PackageDisplay` setzt `transform.localPosition` direkt auf die berechnete
Rasterposition — **bezogen auf den Ursprung (Pivot) des Prefabs**, nicht auf
seine sichtbare Bounding Box. Sitzt der Pivot z. B. an einer Ecke statt im
Zentrum/am Boden-Mittelpunkt der Verpackung, wirkt die Platzierung „verschoben"
oder die Päckchen scheinen im Boden zu versinken bzw. zu schweben.
**Fix:** Pivot des `PackagePrefab` im 3D-Tool (Blender) auf den Boden-
Mittelpunkt setzen, bevor es exportiert/als Prefab gebaut wird. Faustregel:
wenn's wie eine Kiste auf dem Boden stehen soll, Pivot unten-mittig; wenn's im
Regal frei "schwebend zentriert" wirken soll, Pivot im geometrischen Zentrum.
### 2. Falsche Grundausrichtung im Prefab
Bisher wurde jedes Päckchen mit `Quaternion.identity` platziert — also exakt
so gedreht, wie es importiert wurde. Wurde das Modell in Blender nicht
"aufrecht" (Unity: +Y = oben, +Z = vorne) exportiert, liegen die Päckchen im
Raster auf der Seite oder verdreht.
**Fix jetzt eingebaut:** `_displayRotationEuler` gleicht das aus, ohne das
Modell neu exportieren zu müssen. Einfach im Inspector die nötige Korrektur
eintragen (z. B. `(-90, 0, 0)`, falls das Modell "liegend" exportiert wurde
und eigentlich aufrecht stehen sollte) — Werte am besten per Trial-and-Error
im Play-Mode justieren, man sieht die Wirkung sofort.
## Spacing & Größe aufeinander abstimmen
`_displaySpacing` ist der Abstand zwischen den **Mittelpunkten** benachbarter
Päckchen, keine automatische Kollisionsvermeidung. Zu klein → Päckchen
überlappen sich sichtbar. Zu groß → unnötige Lücken, und es passen weniger
rein als gedacht.
So ermittelst du einen guten Wert:
1. Das `PackagePrefab` per Drag&Drop in eine leere Szene ziehen (oder im
Project-Fenster anklicken und die Bounds im Scene-View-Gizmo ablesen).
2. Größte Kantenlänge in Metern ablesen (Unity: 1 Unit = 1 Meter).
3. `_displaySpacing` je Achse auf **Kantenlänge × ca. 1,11,3** setzen (kleiner
Puffer gegen Berührung/Z-Fighting).
Beispiel: Päckchen ist 0,08 m breit/tief, 0,12 m hoch →
`_displaySpacing ≈ (0.10, 0.14, 0.10)`.
## Spalten/Reihen an die Behälter-Größe anpassen
- **Lieferkarton**: `_displayColumns`/`_displayRows` grob an die
Innenmaße des Kartons anpassen (Spalten × Reihen × Spacing sollte nicht
größer sein als die Kartonöffnung — sonst "schwebt" ein Teil der Päckchen
sichtbar über dem Kartonrand).
- **ShelfSlot**: analog zur `_capacityUnits`/Fachbreite. Aktuell Default
4×3 = 12 Plätze pro Lage, passend zur Standard-`_capacityUnits: 12` bei
`ShelfSize.Small`. Bei größeren Produkten (`Medium`/`Large`, siehe
`ProductDefinition.ShelfSize`) verringert sich die effektive Kapazität
automatisch (`ShelfSlot.Capacity()`) — Raster-Werte ggf. mit anpassen,
damit die sichtbare Anzeige zur tatsächlichen Kapazität passt.
## Troubleshooting
| Symptom | Wahrscheinliche Ursache | Fix |
|--------------------------------------------|---------------------------------------------|-----|
| Päckchen liegen auf der Seite / verdreht | Prefab-Grundausrichtung falsch | `_displayRotationEuler` justieren |
| Päckchen schweben über/versinken im Boden | Pivot des Prefabs nicht am Boden-Mittelpunkt| Pivot in Blender korrigieren, oder `_displaySpacing.y`/Lagenhöhe grob kompensieren |
| Päckchen überlappen sich sichtbar | `_displaySpacing` kleiner als Prefab-Größe | Spacing erhöhen (siehe Formel oben) |
| Zu viele/wenige Päckchen sichtbar | `_maxVisiblePackages` (Karton) bzw. `Capacity()` (Regal) vs. Raster-Kapazität passen nicht zusammen | `_displayColumns × _displayRows` an tatsächliche Kapazität anpassen |
| Fliegendes Päckchen landet anders gedreht als die ruhenden im Regal | War bis eben ein Bug (Flug nutzte rohe Transform-Rotation statt `_displayRotationEuler`) | Bereits gefixt: `ShelfSlot.GetSlotWorldRotation()` berücksichtigt jetzt beide |
## Kurz zusammengefasst
Keine der Zahlen ist "fest verdrahtet" — alle vier Felder sind Inspector-
Werte, extra dafür da, unterschiedliche Produkt-Prefabs ohne Code-Änderung
einzupassen. Der eigentliche Hebel für "richtig ausgerichtet" ist aber meist
der Pivot/die Grundrotation des Prefabs selbst — das Raster kann nur die
*Anordnung*, nicht die *Modellierung* korrigieren (außer über
`_displayRotationEuler` als Ausgleich).