One view per side over its members' sensors and books. Flight, Combat, Follow and Minion read contacts as ContactId and fire-control readouts as view calls; FollowTask.Anchor is a handle. Own-ship reads stay direct. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
28 lines
1.1 KiB
C#
28 lines
1.1 KiB
C#
using CultMath;
|
|
using static CultMath.math;
|
|
using float2 = CultMath.float2;
|
|
|
|
// Hold a standoff from the anchor: match its velocity, and close or open the gap in proportion to the error.
|
|
public class FollowState : BaseState
|
|
{
|
|
public FollowState(Agent agent) : base(agent) { }
|
|
|
|
public override void Update(float delta)
|
|
{
|
|
var task = _agent.Task as FollowTask;
|
|
if (task?.Anchor == null) return;
|
|
var anchor = _agent.View.SideTrack(task.Anchor.Value);
|
|
if (anchor == null) return;
|
|
|
|
var toAnchor = anchor.Value.Position.xz - _agent.Ship.Position.xz;
|
|
var distance = length(toAnchor);
|
|
var direction = distance > 0 ? toAnchor / distance : _agent.Ship.Direction;
|
|
// Positive error: too far, close. Negative: too near, open.
|
|
var error = distance - task.Standoff;
|
|
var pull = direction * (float) sign(error) * saturate(abs(error) / max(task.Standoff, 1f));
|
|
var desired = anchor.Value.Velocity + pull * _agent.TopSpeed;
|
|
|
|
_agent.Ship.Command.Aim = float3(direction.x, 0, direction.y);
|
|
_agent.Accelerate(desired);
|
|
}
|
|
}
|