NPC steering blending (#25666)

* NPC steering blending

Significantly more stable than using LastSteerDirection and also AntiStuck never got tripped locally when I was running around. I also left future notes for me to cleanup the pathfinder in future.

* Remove index
This commit is contained in:
metalgearsloth
2024-02-28 17:41:15 +11:00
committed by GitHub
parent 1c015d1fd5
commit f819404f6d
3 changed files with 56 additions and 48 deletions

View File

@@ -9,6 +9,7 @@ using Content.Shared.Movement.Components;
using Content.Shared.NPC;
using Content.Shared.Physics;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent;
@@ -16,7 +17,7 @@ namespace Content.Server.NPC.Systems;
public sealed partial class NPCSteeringSystem
{
private void ApplySeek(float[] interest, Vector2 direction, float weight)
private void ApplySeek(Span<float> interest, Vector2 direction, float weight)
{
if (weight == 0f || direction == Vector2.Zero)
return;
@@ -25,13 +26,10 @@ public sealed partial class NPCSteeringSystem
for (var i = 0; i < InterestDirections; i++)
{
if (interest[i].Equals(-1f))
continue;
var angle = i * InterestRadians;
var dot = MathF.Cos(directionAngle - angle);
dot = (dot + 1) * 0.5f;
interest[i] += dot * weight;
dot = (dot + 1f) * 0.5f;
interest[i] = Math.Clamp(interest[i] + dot * weight, 0f, 1f);
}
}
@@ -72,7 +70,7 @@ public sealed partial class NPCSteeringSystem
TransformComponent xform,
Angle offsetRot,
float moveSpeed,
float[] interest,
Span<float> interest,
float frameTime,
ref bool forceSteer)
{
@@ -274,7 +272,8 @@ public sealed partial class NPCSteeringSystem
}
// If not in LOS and no path then get a new one fam.
if (!inLos && steering.CurrentPath.Count == 0)
if ((!inLos && steering.ArriveOnLineOfSight && steering.CurrentPath.Count == 0) ||
(!steering.ArriveOnLineOfSight && steering.CurrentPath.Count == 0))
{
needsPath = true;
}
@@ -465,12 +464,12 @@ public sealed partial class NPCSteeringSystem
int layer,
int mask,
TransformComponent xform,
float[] danger)
Span<float> danger)
{
var objectRadius = 0.15f;
var objectRadius = 0.25f;
var detectionRadius = MathF.Max(0.35f, agentRadius + objectRadius);
var ents = _entSetPool.Get();
_lookup.GetEntitiesInRange(uid, detectionRadius, ents, LookupFlags.Static);
_lookup.GetEntitiesInRange(uid, detectionRadius, ents, LookupFlags.Dynamic | LookupFlags.Static);
foreach (var ent in ents)
{
@@ -478,6 +477,7 @@ public sealed partial class NPCSteeringSystem
if (!_physicsQuery.TryGetComponent(ent, out var otherBody) ||
!otherBody.Hard ||
!otherBody.CanCollide ||
otherBody.BodyType == BodyType.KinematicController ||
(mask & otherBody.CollisionLayer) == 0x0 &&
(layer & otherBody.CollisionMask) == 0x0)
{
@@ -506,7 +506,7 @@ public sealed partial class NPCSteeringSystem
}
else
{
weight = distance / detectionRadius;
weight = (detectionRadius - distance) / detectionRadius;
}
if (obstacleDirection == Vector2.Zero)
@@ -541,7 +541,7 @@ public sealed partial class NPCSteeringSystem
int mask,
PhysicsComponent body,
TransformComponent xform,
float[] danger)
Span<float> danger)
{
var objectRadius = 0.25f;
var detectionRadius = MathF.Max(0.35f, agentRadius + objectRadius);
@@ -614,4 +614,35 @@ public sealed partial class NPCSteeringSystem
// TODO: Alignment
// TODO: Cohesion
private void Blend(NPCSteeringComponent steering, float frameTime, Span<float> interest, Span<float> danger)
{
/*
* Future sloth notes:
* Pathfinder cleanup:
- Cleanup whatever the fuck is happening in pathfinder
- Use Flee for melee behavior / actions and get the seek direction from that rather than bulldozing
- Must always have a path
- Path should return the full version + the snipped version
- Pathfinder needs to do diagonals
- Next node is either <current node + 1> or <nearest node + 1> (on the full path)
- If greater than <1.5m distance> repath
*/
// IDK why I didn't do this sooner but blending is a lot better than lastdir for fixing stuttering.
const float BlendWeight = 10f;
var blendValue = Math.Min(1f, frameTime * BlendWeight);
for (var i = 0; i < InterestDirections; i++)
{
var currentInterest = interest[i];
var lastInterest = steering.Interest[i];
var interestDiff = (currentInterest - lastInterest) * blendValue;
steering.Interest[i] = lastInterest + interestDiff;
var currentDanger = danger[i];
var lastDanger = steering.Danger[i];
var dangerDiff = (currentDanger - lastDanger) * blendValue;
steering.Danger[i] = lastDanger + dangerDiff;
}
}
}