Aetheria/Assets/Scripts/Gameplay/ItemPickup.cs
Meta Vens b57207045d Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.

Not yet built or run (Unity presenter files are verified by compile only on
Starfire).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00

69 lines
2.5 KiB
C#

using System;
using TMPro;
using CultMath;
using CultMath.UnityBridge;
using UnityEngine;
using static CultMath.math;
using Random = UnityEngine.Random;
// How one floating item looks. Zone owns the item's every fact (existence, position, expiry, pickup); once bound,
// this reads the latest sim body and draws, spun for show, and writes nothing back (rulings unity-presents-only-r3
// and sim-speed-presentation). An unbound pickup (FieldTester's test scene) leaves its transform alone.
public class ItemPickup : MonoBehaviour
{
public float RotationSpeed = 1f;
public float GridOffset;
public float LabelFadeDuration = .5f;
public float LabelPersistDuration = 3;
public float LabelDisplayAngle = 15;
public float LabelDisplayMaxDistance = 500;
public Transform ScanLabelContainer;
public TextMeshPro ScanLabel;
public ItemInstance Item { get; set; }
public float3 ViewOrigin { get; set; }
public float3 ViewDirection { get; set; }
private float _displayTime;
private float _timeOffset;
private Zone _zone;
private FloatingItem _floating;
public void Bind(Zone zone, FloatingItem floating)
{
_zone = zone;
_floating = floating;
Item = floating.Item;
_timeOffset = Random.value * 100;
Place();
}
private void Place()
{
var lead = ActionGameManager.Clock.Lead;
var p = DrawAhead.Position(_floating.Body, lead);
transform.position = new Vector3(p.x, DrawAhead.Height(_zone, p, lead) + GridOffset, p.y);
}
private void Update()
{
if (_floating != null)
{
Place();
transform.localRotation = Quaternion.Euler(
sin(Time.time - _timeOffset * RotationSpeed) * 90, 0, cos(Time.time - _timeOffset * RotationSpeed) * 90);
}
var diff = transform.position.ToCultMath() - ViewOrigin;
var toThis = normalize(diff);
var viewAngle = acos(dot(toThis, ViewDirection)) * Mathf.Rad2Deg;
if (length(diff) < LabelDisplayMaxDistance && viewAngle < LabelDisplayAngle)
_displayTime = Time.time;
if (_floating?.Holder != null) _displayTime = Time.time;
var targetAlpha = Time.time - _displayTime < LabelPersistDuration ? 1 : 0;
var c = ScanLabel.color;
c.a = c.a + sign(targetAlpha - c.a) * (Time.deltaTime / LabelFadeDuration);
ScanLabel.color = c;
ScanLabelContainer.rotation = Quaternion.LookRotation((-toThis).ToUnity());
}
}