Back to all projects

Engine & Gameplay Programmer

Simple Custom Physics Engine

I developed this engine to deepen my low-level gameplay and simulation programming skills. The project covers the full loop from broadphase collision culling to contact resolution and frame-stable integration.

C++OpenGLGLFWImGuiCMake

Duration

6 months

Team

Solo project

Engine

Custom C++ Engine

Platforms

Windows

Gameplay Pillars

  • >Deterministic simulation steps
  • >Debuggability first, visuals second
  • >Extensible architecture for gameplay experiments

My Responsibilities

  • >Implemented SAT-based collision detection and contact manifold generation.
  • >Built impulse solver with configurable restitution and friction coefficients.
  • >Added fixed timestep loop and interpolation for smoother render output.
  • >Created debug overlays for collider normals, impulse vectors, and sleep states.

Systems Breakdown

Fixed Timestep Simulation

Simulation runs on a fixed step independent from rendering framerate.

Impact: Eliminated jitter and made movement tests reproducible across machines.

SAT Contact Solver

Separating axis tests produce robust contact normals and penetration depths.

Impact: Reduced tunneling and stabilized stack behavior in stress tests.

Gameplay Debug Instrumentation

ImGui panels expose runtime tuning for drag, friction, and impulse clamping.

Impact: Accelerated balancing passes and simplified issue reproduction.

Media Gallery

Screenshots and clips from gameplay, debug tools, and iteration passes.

Collider debug render

Collider wireframes with normal vectors and penetration depth readouts.

Impulse graph diagnostics

Runtime impulse diagnostics used to tune stack stability.

Stack stress test with alternating mass ratios and restitution values.

Video Walkthroughs

Focused clips showing implementation outcomes, tuning passes, and polished gameplay moments.

Collision Solver Walkthrough

Step-by-step playback of broadphase, narrowphase, and impulse resolution.

Code Snippets

Practical samples from gameplay systems and runtime tools used in production.

Semi-Implicit Euler Integration

RigidBody.cpp | cpp

Stable integration step used for velocity and position updates.

void RigidBody::Integrate(float dt)
{
    if (isStatic)
    {
        return;
    }

    linearVelocity += (forceAccum * inverseMass) * dt;
    angularVelocity += torqueAccum * inverseInertia * dt;

    position += linearVelocity * dt;
    orientation += angularVelocity * dt;
    orientation.Normalize();

    forceAccum = Vec3::Zero();
    torqueAccum = Vec3::Zero();
}

Impulse Resolution

ContactSolver.cpp | cpp

Computes normal impulse and applies equal/opposite responses.

void ContactSolver::ResolveVelocity(Contact& contact)
{
    const Vec3 relativeVelocity =
        contact.bodyB->linearVelocity - contact.bodyA->linearVelocity;
    const float separatingVelocity = Dot(relativeVelocity, contact.normal);

    if (separatingVelocity > 0.0f)
    {
        return;
    }

    const float newSepVelocity = -separatingVelocity * contact.restitution;
    const float deltaVelocity = newSepVelocity - separatingVelocity;
    const float totalInverseMass =
        contact.bodyA->inverseMass + contact.bodyB->inverseMass;

    if (totalInverseMass <= 0.0f)
    {
        return;
    }

    const float impulseMagnitude = deltaVelocity / totalInverseMass;
    const Vec3 impulse = contact.normal * impulseMagnitude;
    contact.bodyA->linearVelocity -= impulse * contact.bodyA->inverseMass;
    contact.bodyB->linearVelocity += impulse * contact.bodyB->inverseMass;
}

Production Outcomes

  • >Stack stress tests remained stable over long simulation windows.
  • >Debug overlays made collision edge cases far quicker to diagnose.
  • >Engine architecture became a reusable playground for gameplay experiments.
Discuss this project