Skip to content

Commit

Permalink
Advanced targeting
Browse files Browse the repository at this point in the history
  • Loading branch information
Just-a-Unity-Dev committed Jul 10, 2024
1 parent 2076d0e commit 4454e1f
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 17 deletions.
6 changes: 6 additions & 0 deletions Content.Server/NPC/Components/NPCRangedCombatComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public sealed partial class NPCRangedCombatComponent : Component
[ViewVariables(VVAccess.ReadWrite)]
public float LOSAccumulator = 0f;

/// <summary>
/// Does this predict where the target is moving towards, and then fires there?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool Advanced = false;

/// <summary>
/// Is the target still considered in LOS since the last check.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public override void Startup(NPCBlackboard blackboard)
base.Startup(blackboard);
var ranged = _entManager.EnsureComponent<NPCRangedCombatComponent>(blackboard.GetValue<EntityUid>(NPCBlackboard.Owner));
ranged.Target = blackboard.GetValue<EntityUid>(TargetKey);
ranged.Advanced = blackboard.GetValueOrDefault<bool>("AdvancedTargeting", _entManager);

if (blackboard.TryGetValue<float>(NPCBlackboard.RotateSpeed, out var rotSpeed, _entManager))
{
Expand Down
1 change: 1 addition & 0 deletions Content.Server/NPC/NPCBlackboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
{"MovementRangeClose", 0.2f},
{"MovementRange", 1.5f},
{"RangedRange", 10f},
{"AdvancedTargeting", false},
{"RotateSpeed", float.MaxValue},
{"VisionRadius", 10f},
};
Expand Down
45 changes: 30 additions & 15 deletions Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Numerics;
using Content.Server.NPC.Components;
using Content.Shared.CombatMode;
using Content.Shared.Interaction;
Expand All @@ -20,9 +21,6 @@ public sealed partial class NPCCombatSystem
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TransformComponent> _xformQuery;

// TODO: Don't predict for hitscan
private const float ShootSpeed = 20f;

/// <summary>
/// Cooldown on raycasting to check LOS.
/// </summary>
Expand Down Expand Up @@ -121,20 +119,42 @@ private void UpdateRanged(float frameTime)

comp.LOSAccumulator -= frameTime;

var worldPos = _transform.GetWorldPosition(xform);
var targetPos = _transform.GetWorldPosition(targetXform);
var (x, worldRot) = _transform.GetWorldPositionRotation(xform);
var v = gun.ProjectileSpeed; // bullet velocity
var (xt, targetRot) = _transform.GetWorldPositionRotation(targetXform);
var vt = targetBody.LinearVelocity; // target velocity

// We'll work out the projected spot of the target and shoot there instead of where they are.
var distance = (targetPos - worldPos).Length();
var oldInLos = comp.TargetInLOS;
Vector2 targetSpot;
Angle goalRotation;
var dx = xt - x; // target displacement from gun
var distance = dx.Length(); // distance to target

if (comp.Advanced)
{
var phi = (-dx).ToWorldAngle() - vt.ToWorldAngle();
var theta = Math.Asin(vt.Length() / v * Math.Sin(phi.Theta));
goalRotation = dx.ToWorldAngle() + theta;
var psi = Math.PI - phi - theta;
var intercept_dist = (float)(distance * Math.Sin(theta)/Math.Sin(psi));
targetSpot = xt + vt.Normalized() * intercept_dist;
}
else
{
// We'll work out the projected spot of the target and shoot there instead of where they are.
targetSpot = xt + vt * distance / v;
goalRotation = (targetSpot - x).ToWorldAngle();
}

// TODO: Should be doing these raycasts in parallel
// Ideally we'd have 2 steps, 1. to go over the normal details for shooting and then 2. to handle beep / rotate / shoot
var oldInLos = comp.TargetInLOS;

if (comp.LOSAccumulator < 0f)
{
comp.LOSAccumulator += UnoccludedCooldown;
// For consistency with NPC steering.
comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, Transform(comp.Target).Coordinates, distance + 0.1f);
comp.TargetInLOS = _interaction.InRangeUnobstructed(comp.Owner, comp.Target, distance + 0.1f) &&
(!comp.Advanced | _interaction.InRangeUnobstructed(comp.Owner, new MapCoordinates(targetSpot, xform.MapID), distance + 0.1f));
}

if (!comp.TargetInLOS)
Expand Down Expand Up @@ -162,11 +182,6 @@ private void UpdateRanged(float frameTime)
continue;
}

var mapVelocity = targetBody.LinearVelocity;
var targetSpot = targetPos + mapVelocity * distance / ShootSpeed;

// If we have a max rotation speed then do that.
var goalRotation = (targetSpot - worldPos).ToWorldAngle();
var rotationSpeed = comp.RotationSpeed;

if (!_rotate.TryRotateTo(uid, goalRotation, frameTime, comp.AccuracyThreshold, rotationSpeed?.Theta ?? double.MaxValue, xform))
Expand All @@ -187,7 +202,7 @@ private void UpdateRanged(float frameTime)

EntityCoordinates targetCordinates;

if (_mapManager.TryFindGridAt(xform.MapID, targetPos, out var gridUid, out var mapGrid))
if (_mapManager.TryFindGridAt(xform.MapID, xt, out var gridUid, out var mapGrid))
{
targetCordinates = new EntityCoordinates(gridUid, mapGrid.WorldToLocal(targetSpot));
}
Expand Down
2 changes: 0 additions & 2 deletions Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,6 @@ private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVeloci
if (!HasComp<ProjectileComponent>(uid))
{
RemoveShootable(uid);
// TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack.
ThrowingSystem.TryThrow(uid, mapDirection, gun.ProjectileSpeedModified, user);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,25 @@
- type: NpcFactionMember
factions:
- PointDefenseGun
- type: BallisticAmmoProvider
proto: Cartridge20mm
capacity: 1500
- type: Gun
fireRate: 20
selectedMode: FullAuto
availableModes:
- FullAuto
- type: HTN
rootTask:
task: TurretCompound
blackboard:
RotateSpeed: !type:Single
15.705 # 3.141 * 5
SoundTargetInLOS: !type:SoundPathSpecifier
path: /Audio/Effects/double_beep.ogg
AdvancedTargeting: !type:Bool
true
RangedRange: !type:Single
60.0
VisionRadius: !type:Single
100.0

0 comments on commit 4454e1f

Please sign in to comment.