2026-10-08 14:18:41 +02:00
|
|
|
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;
|
2026-10-22 15:45:02 +02:00
|
|
|
var anchor = _agent.View.SideTrack(task.Anchor.Value);
|
|
|
|
|
if (anchor == null) return;
|
2026-10-08 14:18:41 +02:00
|
|
|
|
2026-10-22 15:45:02 +02:00
|
|
|
var toAnchor = anchor.Value.Position.xz - _agent.Ship.Position.xz;
|
2026-10-08 14:18:41 +02:00
|
|
|
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));
|
2026-10-22 15:45:02 +02:00
|
|
|
var desired = anchor.Value.Velocity + pull * _agent.TopSpeed;
|
2026-10-08 14:18:41 +02:00
|
|
|
|
2026-10-22 00:32:11 +02:00
|
|
|
_agent.Ship.Command.Aim = float3(direction.x, 0, direction.y);
|
2026-10-08 14:18:41 +02:00
|
|
|
_agent.Accelerate(desired);
|
|
|
|
|
}
|
|
|
|
|
}
|