diff --git a/Assets/Scripts/Gameplay/Weapons/Projectile.cs b/Assets/Scripts/Gameplay/Weapons/Projectile.cs index 4e38ad549..64d84fb4e 100644 --- a/Assets/Scripts/Gameplay/Weapons/Projectile.cs +++ b/Assets/Scripts/Gameplay/Weapons/Projectile.cs @@ -8,7 +8,7 @@ using static CultMath.math; // (origin, direction, speed, fire time, arrival, range: the PendingShot copy taken at spawn), so this object stores no // velocity or position of its own and integrates nothing: each frame it asks RoundAt where the round is at sim time // plus the clock's Lead (the same draw-ahead ships use), and the simulation's ShotResolved ends a round that hit or -// burst. A round that missed flies on to the FireRange point RoundAt clamps at, and is done there. The barrel is only +// burst. A round that missed flies on to the MaxRange point RoundAt clamps at, and is done there. The barrel is only // where the round is first seen: its offset from the sim line decays to zero over BlendTime sim seconds. The trail's // fade after the end stays real time (pure presentation, ruling sim-speed-presentation). public class Projectile : MonoBehaviour @@ -50,7 +50,7 @@ public class Projectile : MonoBehaviour if (!_alive) return; var time = _zone.Time + ActionGameManager.Clock.Lead; transform.position = At(FireControl.RoundAt(_shot, time), time); - var end = _shot.Speed > .01f ? _shot.FireTime + _shot.FireRange / _shot.Speed : _shot.FireTime; + var end = _shot.Speed > .01f ? _shot.FireTime + _shot.MaxRange / _shot.Speed : _shot.FireTime; if (time >= end) Finish(); } diff --git a/Assets/Scripts/ServerShared/FireControl.cs b/Assets/Scripts/ServerShared/FireControl.cs index 097c3cc79..40e3e25a8 100644 --- a/Assets/Scripts/ServerShared/FireControl.cs +++ b/Assets/Scripts/ServerShared/FireControl.cs @@ -515,12 +515,12 @@ public static class FireControl } // Where a ballistic round is at a sim time: the one statement of the round's line, from its frozen origin along its - // frozen direction at its frozen speed, held at the FireRange point once it has flown that far. Pure: it reads the + // frozen direction at its frozen speed, held at the MaxRange point once it has flown that far. Pure: it reads the // shot alone, and the simulation's own arithmetic (Step, Commit, Apply) does not call it. Presenters draw rounds here. public static float2 RoundAt(in PendingShot shot, float time) { if (shot.Speed <= .01f) return shot.FireOrigin.xz; - var flown = clamp(time - shot.FireTime, 0f, shot.FireRange / shot.Speed); + var flown = clamp(time - shot.FireTime, 0f, shot.MaxRange / shot.Speed); return shot.FireOrigin.xz + shot.TravelDirection * (shot.Speed * flown); } @@ -766,6 +766,7 @@ public static class FireControl FireRange = fireRange, FireTime = now, Speed = weapon.Velocity, + MaxRange = weapon.Range, FireOrigin = origin, FireTargetPosition = targetPosition, FireTargetVelocity = targetVelocity, @@ -2012,6 +2013,9 @@ public struct PendingShot public float FireTime; // The weapon's Velocity at Fire: frozen with the rest, so RoundAt states the same line whatever happens to the stat later. public float Speed; + // The weapon's Range at Fire, likewise frozen: how far the round can fly, which RoundAt clamps at. FireRange above is the + // distance to the engaged target (0 for a round with none), not how far a round that misses flies on. + public float MaxRange; public float CommitTime; public float ArrivalTime; diff --git a/tests/Aetheria.Shared.Tests/BallisticFlightTests.cs b/tests/Aetheria.Shared.Tests/BallisticFlightTests.cs index cd3582d70..c9589a0db 100644 --- a/tests/Aetheria.Shared.Tests/BallisticFlightTests.cs +++ b/tests/Aetheria.Shared.Tests/BallisticFlightTests.cs @@ -48,7 +48,7 @@ public sealed partial class FireControlCut124Tests Assert.Equal(burst.BurstPosition.x, arrival.x, 3); Assert.Equal(burst.BurstPosition.z, arrival.y, 3); - // Past the range it is held at the FireRange point, however late it is asked. + // Past the weapon's range it is held at the range point, however late it is asked. var held = FireControl.RoundAt(burst, burst.FireTime + NoLockRange / BallisticSpeed + 50f); Assert.Equal(origin.x + aim.x * NoLockRange, held.x, 3); Assert.Equal(origin.z + aim.y * NoLockRange, held.y, 3); @@ -57,7 +57,7 @@ public sealed partial class FireControlCut124Tests Assert.Equal(origin.x, before.x, 3); Assert.Equal(origin.z, before.y, 3); - // Direct round at a stationary target 100 ahead (+z): arrives on the target, and holds at the range point. + // Direct round at a stationary target 100 ahead (+z): arrives on the target, and a miss would fly on to the weapon's range. var d = Build(TestSettings(), SolidShape(5, 4), velocity: BallisticSpeed, weaponRange: 1000f); var dOrigin = d.Shooter.Position; FireControl.Fire(d.Weapon, d.WeaponItem, d.Shooter); @@ -66,8 +66,8 @@ public sealed partial class FireControlCut124Tests Assert.Equal(d.Target.Position.x, hit.x, 2); Assert.Equal(d.Target.Position.z, hit.y, 2); Assert.Equal(dOrigin.z + 100f / 2f, FireControl.RoundAt(direct, direct.FireTime + 2.5f).y, 2); - var heldDirect = FireControl.RoundAt(direct, direct.FireTime + direct.FireRange / BallisticSpeed + 99f); - Assert.Equal(dOrigin.z + direct.FireRange, heldDirect.y, 2); + var heldDirect = FireControl.RoundAt(direct, direct.FireTime + 1000f / BallisticSpeed + 99f); + Assert.Equal(dOrigin.z + 1000f, heldDirect.y, 2); } // A round with no speed (the weapon authors Velocity 0, or effectively 0) does not fly: it is at its origin at any