diff --git a/ShapeEngine/Core/GameDef/Game.cs b/ShapeEngine/Core/GameDef/Game.cs
index b1b8b802..c5515583 100644
--- a/ShapeEngine/Core/GameDef/Game.cs
+++ b/ShapeEngine/Core/GameDef/Game.cs
@@ -111,7 +111,7 @@ public partial class Game
/// This value is calculated as 1.0 / FixedPhysicsFramerate and represents
/// the duration of each physics step in seconds.
///
- public float FixedPhysicsTimestep { get; private set; }
+ public double FixedPhysicsTimestep { get; private set; }
///
/// Gets the game time information for the variable update loop.
@@ -348,7 +348,7 @@ private bool IsIdleFrameRateLimitActive()
private readonly List shapeFlashes = [];
private readonly List deferred = [];
- private float physicsAccumulator;
+ private double physicsAccumulator;
private List? customScreenTextures;
#endregion
@@ -540,7 +540,7 @@ public Game(GameSettings gameSettings, WindowSettings windowSettings, InputSetti
{
if (fixedFramerate < 30) fixedFramerate = 30;
FixedPhysicsFramerate = fixedFramerate;
- FixedPhysicsTimestep = 1f / FixedPhysicsFramerate;
+ FixedPhysicsTimestep = 1.0 / FixedPhysicsFramerate;
FixedPhysicsEnabled = true;
}
diff --git a/ShapeEngine/Core/GameDef/GameGameloop.cs b/ShapeEngine/Core/GameDef/GameGameloop.cs
index 5708a5b3..a309d49a 100644
--- a/ShapeEngine/Core/GameDef/GameGameloop.cs
+++ b/ShapeEngine/Core/GameDef/GameGameloop.cs
@@ -164,7 +164,8 @@ private void RunGameloop()
if (FixedPhysicsEnabled)
{
ResolveUpdate(true);
- AdvanceFixedUpdate(dt);
+ // Use double-precision frameDelta for more accurate fixed-step physics timing
+ AdvanceFixedUpdate(frameDelta);
}
else ResolveUpdate(false);
@@ -341,25 +342,27 @@ private void GameTextureOnTextureResized(int w, int h)
ResolveOnGameTextureResized(w, h);
}
- private void AdvanceFixedUpdate(float dt)
+ private void AdvanceFixedUpdate(double dt)
{
- const float maxFrameTime = 1f / 30f;
- float frameTime = dt;
- // var t = 0.0f;
+ const double maxFrameTime = 1.0 / 30.0;
+ double frameTime = dt;
if (frameTime > maxFrameTime) frameTime = maxFrameTime;
physicsAccumulator += frameTime;
while (physicsAccumulator >= FixedPhysicsTimestep)
{
- FixedTime = FixedTime.TickF(FixedPhysicsFramerate);
+ FixedTime = FixedTime.Tick(FixedPhysicsTimestep);
ResolveFixedUpdate();
// t += FixedPhysicsTimestep;
physicsAccumulator -= FixedPhysicsTimestep;
}
- float alpha = physicsAccumulator / FixedPhysicsTimestep;
- ResolveInterpolateFixedUpdate(alpha);
+ double alpha = physicsAccumulator / FixedPhysicsTimestep;
+ // alpha is computed in double precision for timing accuracy, but interpolation
+ // uses float because ResolveInterpolateFixedUpdate (e.g., via IUpdateable) has
+ // a float-based public API. This precision downgrade is intentional.
+ ResolveInterpolateFixedUpdate((float)alpha);
}
}
\ No newline at end of file
diff --git a/ShapeEngine/Core/Structs/GameTime.cs b/ShapeEngine/Core/Structs/GameTime.cs
index bbb511f8..51213274 100644
--- a/ShapeEngine/Core/Structs/GameTime.cs
+++ b/ShapeEngine/Core/Structs/GameTime.cs
@@ -107,6 +107,15 @@ public GameTime(double totalSeconds, int totalFrames, double elapsedSeconds)
///
public readonly float Delta => (float)ElapsedSeconds;
+ ///
+ /// Gets the elapsed time since the last frame as a double-precision value.
+ ///
+ ///
+ /// Use when double precision is required instead of the single-precision .
+ /// This property simply returns the underlying value.
+ ///
+ public readonly double DeltaDouble => ElapsedSeconds;
+
///
/// Gets the current frames per second (FPS) based on the elapsed time between frames.
///