Files
svenm_adminandClaude Sonnet 5 a999b0182a feat(shop): add box pickup/carry, pour-into-shelf, and package flight visuals
- Carryable: generic pickup/carry component, cosmetic per-peer follow of
  the carrier's HandSocket instead of NGO reparenting (camera pitch isn't
  networked, so root-level reparenting wouldn't tilt with the view)
- PlayerCarry: mutual exclusion with PlayerHands, server-timed hold-to-pour
  tick (client only signals start/stop, never per-unit requests)
- IPourSource/IPourTarget: decouple PlayerInteractor from concrete Shop
  types, same pattern as IInteractable
- Lieferkarton: gains product data (productId/quantity), two-stage
  Interact() (open, then pick up), IPourSource
- ShelfSlot: implements IPourTarget, fills the previous RefreshVisuals TODO
- PackageDisplay: renders quantity as a proper column x row grid that
  stacks into further layers as space runs out, reused by both containers
- FlyingPackage: small non-networked cosmetic visual that arcs a package
  from the carried box to its exact landing slot in the shelf grid on
  every successful pour tick, broadcast via Rpc(SendTo.Everyone)
- StorageCrate: rejects pickup while the player is carrying a box

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 20:28:55 +02:00

55 lines
1.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
namespace AfterHours.Shop
{
/// <summary>
/// Rein kosmetisches, nicht genetzwertes Flug-Visual für ein Stück Ware,
/// das vom Karton ins Regal wandert. Jeder Peer erzeugt seine eigene
/// Instanz (ausgelöst über PlayerCarry.PlayFlightRpc) keine
/// Server-Autorität nötig, der eigentliche Bestand ist längst per
/// NetworkVariable synchron.
/// </summary>
public sealed class FlyingPackage : MonoBehaviour
{
private const float ArcHeight = 0.35f;
private Vector3 _start;
private Vector3 _end;
private Quaternion _startRotation;
private Quaternion _endRotation;
private float _duration;
private float _elapsed;
public static void Spawn(GameObject prefab, Vector3 start, Vector3 end, Quaternion endRotation, float duration)
{
if (prefab == null) return;
var instance = Instantiate(prefab, start, Quaternion.identity);
var flight = instance.AddComponent<FlyingPackage>();
flight.Init(start, end, endRotation, duration);
}
private void Init(Vector3 start, Vector3 end, Quaternion endRotation, float duration)
{
_start = start;
_end = end;
_startRotation = transform.rotation;
_endRotation = endRotation;
_duration = Mathf.Max(0.05f, duration);
}
private void Update()
{
_elapsed += Time.deltaTime;
float t = Mathf.Clamp01(_elapsed / _duration);
Vector3 flat = Vector3.Lerp(_start, _end, t);
float arc = ArcHeight * Mathf.Sin(t * Mathf.PI);
transform.position = flat + Vector3.up * arc;
transform.rotation = Quaternion.Slerp(_startRotation, _endRotation, t);
if (t >= 1f) Destroy(gameObject);
}
}
}