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:
@@ -128,7 +128,7 @@ namespace AfterHours.Networking
|
||||
Vector3 start = box.transform.position + Vector3.up * 0.3f;
|
||||
Vector3 end = shelf.GetSlotWorldPosition(landingIndex);
|
||||
|
||||
FlyingPackage.Spawn(prefab, start, end, shelf.transform.rotation, _flightDuration);
|
||||
FlyingPackage.Spawn(prefab, start, end, shelf.GetSlotWorldRotation(), _flightDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace AfterHours.Shop
|
||||
[SerializeField] private int _displayColumns = 3;
|
||||
[SerializeField] private int _displayRows = 3;
|
||||
[SerializeField] private Vector3 _displaySpacing = new(0.12f, 0.1f, 0.12f);
|
||||
[SerializeField] private Vector3 _displayRotationEuler = Vector3.zero;
|
||||
|
||||
// Eine synchronisierte Variable, die den Zustand des Kartons speichert
|
||||
private NetworkVariable<bool> istOffen = new NetworkVariable<bool>(
|
||||
@@ -60,7 +61,7 @@ namespace AfterHours.Shop
|
||||
private void Awake()
|
||||
{
|
||||
_carryable = GetComponent<Carryable>();
|
||||
_packageDisplay = new PackageDisplay(_contentsRoot, _displayColumns, _displayRows, _displaySpacing);
|
||||
_packageDisplay = new PackageDisplay(_contentsRoot, _displayColumns, _displayRows, _displaySpacing, _displayRotationEuler);
|
||||
|
||||
// Start-Rotationen (Geschlossen) direkt beim Laden sichern
|
||||
if (deckelLinks != null) linksGeschlossen = deckelLinks.localRotation;
|
||||
|
||||
@@ -17,15 +17,17 @@ namespace AfterHours.Shop
|
||||
private readonly int _columns;
|
||||
private readonly int _rows;
|
||||
private readonly Vector3 _spacing;
|
||||
private readonly Quaternion _rotation;
|
||||
private readonly List<GameObject> _instances = new();
|
||||
private GameObject _prefab;
|
||||
|
||||
public PackageDisplay(Transform root, int columns, int rows, Vector3 spacing)
|
||||
public PackageDisplay(Transform root, int columns, int rows, Vector3 spacing, Vector3 rotationEuler = default)
|
||||
{
|
||||
_root = root;
|
||||
_columns = Mathf.Max(1, columns);
|
||||
_rows = Mathf.Max(1, rows);
|
||||
_spacing = spacing;
|
||||
_rotation = Quaternion.Euler(rotationEuler);
|
||||
}
|
||||
|
||||
/// <summary>Baut die Anzeige auf <paramref name="count"/> Instanzen an (gedeckelt bei maxVisible).</summary>
|
||||
@@ -47,7 +49,7 @@ namespace AfterHours.Shop
|
||||
{
|
||||
var instance = Object.Instantiate(_prefab, _root);
|
||||
instance.transform.localPosition = SlotLocalPosition(_instances.Count);
|
||||
instance.transform.localRotation = Quaternion.identity;
|
||||
instance.transform.localRotation = _rotation;
|
||||
_instances.Add(instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace AfterHours.Shop
|
||||
[SerializeField] private int _displayColumns = 4;
|
||||
[SerializeField] private int _displayRows = 3;
|
||||
[SerializeField] private Vector3 _displaySpacing = new(0.1f, 0.1f, 0.1f);
|
||||
[SerializeField] private Vector3 _displayRotationEuler = Vector3.zero;
|
||||
|
||||
private readonly NetworkVariable<int> _productId = new(-1);
|
||||
private readonly NetworkVariable<int> _quantity = new(0);
|
||||
@@ -41,7 +42,7 @@ namespace AfterHours.Shop
|
||||
|
||||
private PackageDisplay _packageDisplay;
|
||||
|
||||
private void Awake() => _packageDisplay = new PackageDisplay(_displayRoot, _displayColumns, _displayRows, _displaySpacing);
|
||||
private void Awake() => _packageDisplay = new PackageDisplay(_displayRoot, _displayColumns, _displayRows, _displaySpacing, _displayRotationEuler);
|
||||
|
||||
/// <summary>Weltposition des Rasterplatzes mit gegebenem Index – Ziel fürs Flug-Visual (siehe PlayerCarry).</summary>
|
||||
public Vector3 GetSlotWorldPosition(int index)
|
||||
@@ -49,6 +50,13 @@ namespace AfterHours.Shop
|
||||
return _displayRoot != null ? _displayRoot.TransformPoint(_packageDisplay.SlotLocalPosition(index)) : transform.position;
|
||||
}
|
||||
|
||||
/// <summary>Endrotation eines Pakets im Regal – muss zur ruhenden Anzeige passen, siehe PlayerCarry.</summary>
|
||||
public Quaternion GetSlotWorldRotation()
|
||||
{
|
||||
Quaternion baseRotation = _displayRoot != null ? _displayRoot.rotation : transform.rotation;
|
||||
return baseRotation * Quaternion.Euler(_displayRotationEuler);
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
_quantity.OnValueChanged += (_, _) => RefreshVisuals();
|
||||
|
||||
Reference in New Issue
Block a user