Fix physac's fixed time step
This commit is contained in:
parent
589152b658
commit
35634f37c8
2 changed files with 37 additions and 37 deletions
|
@ -51,6 +51,9 @@ int main()
|
||||||
circleC->restitution = 1;
|
circleC->restitution = 1;
|
||||||
|
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
// Restitution demo needs a very tiny physics time step for a proper simulation
|
||||||
|
SetPhysicsTimeStep(1.0/60.0/100 * 1000);
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
|
|
71
src/physac.h
71
src/physac.h
|
@ -96,8 +96,6 @@
|
||||||
#define PHYSAC_MAX_VERTICES 24
|
#define PHYSAC_MAX_VERTICES 24
|
||||||
#define PHYSAC_CIRCLE_VERTICES 24
|
#define PHYSAC_CIRCLE_VERTICES 24
|
||||||
|
|
||||||
#define PHYSAC_DESIRED_DELTATIME 1.0/60.0
|
|
||||||
#define PHYSAC_MAX_TIMESTEP 0.02
|
|
||||||
#define PHYSAC_COLLISION_ITERATIONS 100
|
#define PHYSAC_COLLISION_ITERATIONS 100
|
||||||
#define PHYSAC_PENETRATION_ALLOWANCE 0.05f
|
#define PHYSAC_PENETRATION_ALLOWANCE 0.05f
|
||||||
#define PHYSAC_PENETRATION_CORRECTION 0.4f
|
#define PHYSAC_PENETRATION_CORRECTION 0.4f
|
||||||
|
@ -197,6 +195,7 @@ extern "C" { // Prevents name mangling of fun
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
PHYSACDEF void InitPhysics(void); // Initializes physics values, pointers and creates physics loop thread
|
PHYSACDEF void InitPhysics(void); // Initializes physics values, pointers and creates physics loop thread
|
||||||
PHYSACDEF void RunPhysicsStep(void); // Run physics step, to be used if PHYSICS_NO_THREADS is set in your main loop
|
PHYSACDEF void RunPhysicsStep(void); // Run physics step, to be used if PHYSICS_NO_THREADS is set in your main loop
|
||||||
|
PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default
|
||||||
PHYSACDEF bool IsPhysicsEnabled(void); // Returns true if physics thread is currently enabled
|
PHYSACDEF bool IsPhysicsEnabled(void); // Returns true if physics thread is currently enabled
|
||||||
PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force
|
PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force
|
||||||
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters
|
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters
|
||||||
|
@ -279,16 +278,15 @@ static pthread_t physicsThreadId; // Physics thread id
|
||||||
#endif
|
#endif
|
||||||
static unsigned int usedMemory = 0; // Total allocated dynamic memory
|
static unsigned int usedMemory = 0; // Total allocated dynamic memory
|
||||||
static bool physicsThreadEnabled = false; // Physics thread enabled state
|
static bool physicsThreadEnabled = false; // Physics thread enabled state
|
||||||
|
|
||||||
static double baseTime = 0.0; // Offset time for MONOTONIC clock
|
static double baseTime = 0.0; // Offset time for MONOTONIC clock
|
||||||
static double startTime = 0.0; // Start time in milliseconds
|
static double startTime = 0.0; // Start time in milliseconds
|
||||||
static double deltaTime = 0.0; // Delta time used for physics steps
|
static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time used for physics steps, in milliseconds
|
||||||
static double currentTime = 0.0; // Current time in milliseconds
|
static double currentTime = 0.0; // Current time in milliseconds
|
||||||
static uint64_t frequency = 0; // Hi-res clock frequency
|
static uint64_t frequency = 0; // Hi-res clock frequency
|
||||||
|
|
||||||
static double accumulator = 0.0; // Physics time step delta time accumulator
|
static double accumulator = 0.0; // Physics time step delta time accumulator
|
||||||
static unsigned int stepsCount = 0; // Total physics steps processed
|
static unsigned int stepsCount = 0; // Total physics steps processed
|
||||||
static Vector2 gravityForce = { 0.0f, 9.81f/1000 }; // Physics world gravity force
|
static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force
|
||||||
static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array
|
static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array
|
||||||
static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter
|
static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter
|
||||||
static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array
|
static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array
|
||||||
|
@ -322,13 +320,12 @@ static bool BiasGreaterThan(float valueA, float valueB);
|
||||||
static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points
|
static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points
|
||||||
|
|
||||||
static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer
|
static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer
|
||||||
static uint64_t GetTimeCount(void); // Get hi-res MONOTONIC time measure in seconds
|
static uint64_t GetTimeCount(void); // Get hi-res MONOTONIC time measure in mseconds
|
||||||
static double GetCurrentTime(void); // // Get hi-res MONOTONIC time measure in seconds
|
static double GetCurrentTime(void); // Get current time measure in milliseconds
|
||||||
|
|
||||||
static int GetRandomNumber(int min, int max); // Returns a random number between min and max (both included)
|
static int GetRandomNumber(int min, int max); // Returns a random number between min and max (both included)
|
||||||
|
|
||||||
// Math functions
|
// Math functions
|
||||||
static void MathClamp(double *value, double min, double max); // Clamp a value in a range
|
|
||||||
static Vector2 MathCross(float value, Vector2 vector); // Returns the cross product of a vector and a value
|
static Vector2 MathCross(float value, Vector2 vector); // Returns the cross product of a vector and a value
|
||||||
static float MathCrossVector2(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors
|
static float MathCrossVector2(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors
|
||||||
static float MathLenSqr(Vector2 vector); // Returns the len square root of a vector
|
static float MathLenSqr(Vector2 vector); // Returns the len square root of a vector
|
||||||
|
@ -363,6 +360,8 @@ PHYSACDEF void InitPhysics(void)
|
||||||
#if defined(PHYSAC_DEBUG)
|
#if defined(PHYSAC_DEBUG)
|
||||||
printf("[PHYSAC] physics module initialized successfully\n");
|
printf("[PHYSAC] physics module initialized successfully\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
accumulator = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if physics thread is currently enabled
|
// Returns true if physics thread is currently enabled
|
||||||
|
@ -917,6 +916,18 @@ PHYSACDEF void ClosePhysics(void)
|
||||||
#if !defined(PHYSAC_NO_THREADS)
|
#if !defined(PHYSAC_NO_THREADS)
|
||||||
pthread_join(physicsThreadId, NULL);
|
pthread_join(physicsThreadId, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Unitialize physics manifolds dynamic memory allocations
|
||||||
|
for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]);
|
||||||
|
|
||||||
|
// Unitialize physics bodies dynamic memory allocations
|
||||||
|
for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]);
|
||||||
|
|
||||||
|
#if defined(PHYSAC_DEBUG)
|
||||||
|
if (physicsBodiesCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes]\n", physicsBodiesCount, usedMemory);
|
||||||
|
else if (physicsManifoldsCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes]\n", physicsManifoldsCount, usedMemory);
|
||||||
|
else printf("[PHYSAC] physics module closed successfully\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -1011,7 +1022,6 @@ static void *PhysicsLoop(void *arg)
|
||||||
|
|
||||||
// Initialize physics loop thread values
|
// Initialize physics loop thread values
|
||||||
physicsThreadEnabled = true;
|
physicsThreadEnabled = true;
|
||||||
accumulator = 0;
|
|
||||||
|
|
||||||
// Physics update loop
|
// Physics update loop
|
||||||
while (physicsThreadEnabled)
|
while (physicsThreadEnabled)
|
||||||
|
@ -1019,18 +1029,6 @@ static void *PhysicsLoop(void *arg)
|
||||||
RunPhysicsStep();
|
RunPhysicsStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unitialize physics manifolds dynamic memory allocations
|
|
||||||
for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]);
|
|
||||||
|
|
||||||
// Unitialize physics bodies dynamic memory allocations
|
|
||||||
for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]);
|
|
||||||
|
|
||||||
#if defined(PHYSAC_DEBUG)
|
|
||||||
if (physicsBodiesCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes]\n", physicsBodiesCount, usedMemory);
|
|
||||||
else if (physicsManifoldsCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes]\n", physicsManifoldsCount, usedMemory);
|
|
||||||
else printf("[PHYSAC] physics module closed successfully\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1147,17 +1145,18 @@ PHYSACDEF void RunPhysicsStep(void)
|
||||||
currentTime = GetCurrentTime();
|
currentTime = GetCurrentTime();
|
||||||
|
|
||||||
// Calculate current delta time
|
// Calculate current delta time
|
||||||
deltaTime = currentTime - startTime;
|
const double delta = currentTime - startTime;
|
||||||
|
|
||||||
// Store the time elapsed since the last frame began
|
// Store the time elapsed since the last frame began
|
||||||
accumulator += deltaTime;
|
accumulator += delta;
|
||||||
|
|
||||||
// Clamp accumulator to max time step to avoid bad performance
|
|
||||||
MathClamp(&accumulator, 0.0, PHYSAC_MAX_TIMESTEP);
|
|
||||||
|
|
||||||
// Fixed time stepping loop
|
// Fixed time stepping loop
|
||||||
while (accumulator >= PHYSAC_DESIRED_DELTATIME)
|
while (accumulator >= deltaTime)
|
||||||
{
|
{
|
||||||
|
#ifdef PHYSAC_DEBUG
|
||||||
|
//printf("currentTime %f, startTime %f, accumulator-pre %f, accumulator-post %f, delta %f, deltaTime %f\n",
|
||||||
|
// currentTime, startTime, accumulator, accumulator-deltaTime, delta, deltaTime);
|
||||||
|
#endif
|
||||||
PhysicsStep();
|
PhysicsStep();
|
||||||
accumulator -= deltaTime;
|
accumulator -= deltaTime;
|
||||||
}
|
}
|
||||||
|
@ -1166,6 +1165,11 @@ PHYSACDEF void RunPhysicsStep(void)
|
||||||
startTime = currentTime;
|
startTime = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PHYSACDEF void SetPhysicsTimeStep(double delta)
|
||||||
|
{
|
||||||
|
deltaTime = delta;
|
||||||
|
}
|
||||||
|
|
||||||
// Finds a valid index for a new manifold initialization
|
// Finds a valid index for a new manifold initialization
|
||||||
static int FindAvailableManifoldIndex()
|
static int FindAvailableManifoldIndex()
|
||||||
{
|
{
|
||||||
|
@ -1557,8 +1561,8 @@ static void IntegratePhysicsForces(PhysicsBody body)
|
||||||
|
|
||||||
if (body->useGravity)
|
if (body->useGravity)
|
||||||
{
|
{
|
||||||
body->velocity.x += gravityForce.x*(deltaTime/2.0);
|
body->velocity.x += gravityForce.x*(deltaTime/1000/2.0);
|
||||||
body->velocity.y += gravityForce.y*(deltaTime/2.0);
|
body->velocity.y += gravityForce.y*(deltaTime/1000/2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!body->freezeOrient) body->angularVelocity += body->torque*body->inverseInertia*(deltaTime/2.0);
|
if (!body->freezeOrient) body->angularVelocity += body->torque*body->inverseInertia*(deltaTime/2.0);
|
||||||
|
@ -1592,7 +1596,7 @@ static void InitializePhysicsManifolds(PhysicsManifold manifold)
|
||||||
|
|
||||||
// Determine if we should perform a resting collision or not;
|
// Determine if we should perform a resting collision or not;
|
||||||
// The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution
|
// The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution
|
||||||
if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime, gravityForce.y*deltaTime }) + PHYSAC_EPSILON)) manifold->restitution = 0;
|
if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime/1000, gravityForce.y*deltaTime/1000 }) + PHYSAC_EPSILON)) manifold->restitution = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1953,13 +1957,6 @@ static int GetRandomNumber(int min, int max)
|
||||||
return (rand()%(abs(max - min) + 1) + min);
|
return (rand()%(abs(max - min) + 1) + min);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp a value in a range
|
|
||||||
static inline void MathClamp(double *value, double min, double max)
|
|
||||||
{
|
|
||||||
if (*value < min) *value = min;
|
|
||||||
else if (*value > max) *value = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the cross product of a vector and a value
|
// Returns the cross product of a vector and a value
|
||||||
static inline Vector2 MathCross(float value, Vector2 vector)
|
static inline Vector2 MathCross(float value, Vector2 vector)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue