Aetheria/Assets/Scripts/Gameplay/TractorBeam.cs
Meta Vens 48b42992ee Loot 3 group A: the grab is presented, not simulated
IGrabPresenter.Grab(GrabEvent) only; the binder's Transform and velocity resolvers go. TractorBeam
presents a running grab (aims at Started's TargetPosition, emits at Power, dark otherwise). FieldDriver
draws its tendril from GrabEvents alone with a real-time phase clock over each event's PhaseDuration and
writes no transform and destroys nothing; its grab times move to FieldTester, now the scene's stand-in sim
that owns its pickup's timeline and pose. ItemPickup keeps its label lit while held. ImpactPresenterSmoke
becomes CapabilityPresentationSmoke with a grab section; its two untracked-ship expectations follow
DrawsAt since contact-hud. Builds (Unity 6000.3.24f1 batchmode: smoke ok, scene opens, no missing script).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:43:15 +02:00

51 lines
1.8 KiB
C#

using System;
using UnityEngine;
using CultMath.UnityBridge;
// Presents the ship's grab: while the simulation holds an item, the beam looks along the ground-plane vector to the
// point the item was held from and emits at Power. Zone pulls the held item along the segment from the ship to that
// point (docs/aetheria-release-map.md L11), which is why GrabEvent.TargetPosition on Started is the exact aim and no
// pose lookup is needed. Idle, the beam turns with Direction and emits nothing. The simulation decides every grab fact.
public class TractorBeam : MonoBehaviour, IGrabPresenter
{
public ParticleSystem ParticleSystem;
public float Power { get; set; }
public Vector3 Direction { get; set; }
private bool _grabbing;
private Vector3 _heldPoint;
private Vector3 _heldDirection;
// Cancelled can carry no position (a vanished item), so only Started is read for one.
public void Grab(GrabEvent e)
{
switch (e.Phase)
{
case GrabPhase.Started:
_grabbing = true;
_heldPoint = e.TargetPosition.ToUnity();
_heldDirection = Direction;
break;
case GrabPhase.Completed:
case GrabPhase.Cancelled:
_grabbing = false;
break;
}
}
public void Update()
{
var look = Direction;
if (_grabbing)
{
var toHeld = _heldPoint - transform.position;
toHeld.y = 0;
if (toHeld.sqrMagnitude > 1e-6f) _heldDirection = toHeld;
look = _heldDirection;
}
transform.rotation = Quaternion.LookRotation(look);
var emission = ParticleSystem.emission;
emission.rateOverTimeMultiplier = _grabbing ? Power : 0;
}
}