Sim speed fix: scripted poses are not drawn ahead; a step cannot reset its clock; DrawAhead.Time deleted
DrawAhead leaves a ship in a wormhole animation where the step put it. The clock is one static instance; a zone entered inside a step ends that frame's stepping and the clock resets between frames (SimClock.Reset throws inside Advance). DrawAhead.Time had no consumer. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
cff4e0ffa7
commit
257a8a4795
4 changed files with 68 additions and 14 deletions
|
|
@ -10,11 +10,16 @@ using static CultMath.math;
|
|||
// one, a previous state or a velocity of its own.
|
||||
public static class DrawAhead
|
||||
{
|
||||
// A ship in a wormhole animation has its pose scripted by the step, not integrated from Velocity and TurnRate,
|
||||
// so it is drawn where the step put it: extrapolating a scripted pose draws a streak that resets every step.
|
||||
public static float3 Position(Entity entity, float lead) =>
|
||||
entity.Position + float3(entity.Velocity.x, 0, entity.Velocity.y) * lead;
|
||||
entity is Ship { WormholeAnimationInProgress: true }
|
||||
? entity.Position
|
||||
: entity.Position + float3(entity.Velocity.x, 0, entity.Velocity.y) * lead;
|
||||
|
||||
// The ship's rotation turned about its own up axis by the rate its last step turned, for lead seconds.
|
||||
public static quaternion Rotation(Ship ship, float lead) => Turned(ship.Rotation, ship.TurnRate * lead);
|
||||
public static quaternion Rotation(Ship ship, float lead) =>
|
||||
ship.WormholeAnimationInProgress ? ship.Rotation : Turned(ship.Rotation, ship.TurnRate * lead);
|
||||
|
||||
// q turned about its own up axis by the angle, in the sense Direction turns for a positive TurnRate.
|
||||
public static quaternion Turned(quaternion q, float angle)
|
||||
|
|
@ -32,7 +37,4 @@ public static class DrawAhead
|
|||
t.w * q.z + t.x * q.y - t.y * q.x + t.z * q.w,
|
||||
t.w * q.w - t.x * q.x - t.y * q.y - t.z * q.z));
|
||||
}
|
||||
|
||||
// Zone time for a presenter that evaluates a sim function of time (FireControl.RoundAt).
|
||||
public static float Time(Zone zone, float lead) => zone.Time + lead;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public sealed class SimClock
|
|||
|
||||
private readonly double _period;
|
||||
private double _accumulator;
|
||||
private bool _advancing;
|
||||
|
||||
public SimClock(float step, float stepsPerRealSecond = 60)
|
||||
{
|
||||
|
|
@ -36,19 +37,32 @@ public sealed class SimClock
|
|||
// Sim seconds since the last step, 0 <= Lead < Step.
|
||||
public float Lead => (float) (_accumulator * StepsPerRealSecond * Step);
|
||||
|
||||
// Forgets the real time paid toward the next step (a new zone starts between steps). A step cannot do this to the
|
||||
// clock that is running it.
|
||||
public void Reset()
|
||||
{
|
||||
if (_advancing) throw new InvalidOperationException("A step cannot reset the clock that is running it.");
|
||||
_accumulator = 0;
|
||||
}
|
||||
|
||||
// Feeds real seconds (negative counts as none, one frame counts at most MaxFrameSeconds) and runs the whole
|
||||
// steps they pay for. Returns how many ran.
|
||||
public int Advance(float realSeconds, Action<float> step)
|
||||
{
|
||||
_accumulator += Math.Min(Math.Max(realSeconds, 0f), MaxFrameSeconds);
|
||||
var ran = 0;
|
||||
while (_accumulator >= _period)
|
||||
_advancing = true;
|
||||
try
|
||||
{
|
||||
_accumulator -= _period;
|
||||
step(Step);
|
||||
Steps++;
|
||||
ran++;
|
||||
while (_accumulator >= _period)
|
||||
{
|
||||
_accumulator -= _period;
|
||||
step(Step);
|
||||
Steps++;
|
||||
ran++;
|
||||
}
|
||||
}
|
||||
finally { _advancing = false; }
|
||||
return ran;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue