PerfectBox is a simple 2d physics engine. I wasn't thinking of it's name when I created the project, so I just made up a name. The purpose is to have an almost error-free physics environment. Therefore exact motion calculations were considered and weak estimations were avoided. So there's a big limitation that this engine is not applicable for mesh objects with high vertices. (they can be simulated but they need much processing work, and also rotation objects collision time calculation may need estimations) Another limitation is that it can't handle dynamic forces like friction, and all collisions must be elastic.

Algorithm

Given a time period, PerfectBox checks if there are any collisions that will occur in this period, considers the closest collision to occur, update the objects to the time the collision occurs, performs the collision, and repeats the process until all collisions have resolved.

Implementation

The System class does all the processing work in its Process method. There's also a Updater class which calls the System.Process method providing the elapsed time (configured to 60 FPS the elapsed time passed to System.Process is almost 16.6 milliseconds). After processing, Updater waits until the next refresh.

A basic structure of System.Process is as follows.

public void Process(double elapsed)
{
    var collisions = new List<Collision>();
    double remaining = elapsed;
    
    do
    {
        collisions.Clear();
 
        collisions = GetAllCollisions(); // collect all collisions
        collisions = FilterCollisions(collisions); // filter the possible collisions in the remaining time
 
        if (collisions.Count == 0// No collisions left to preform
            break;
 
        // calculate the min time and the collision it corresponds to
        (double mintime, Collision collision) = ClosestCollision(collisions);
 
        // update all objects to mintime
        for (int i = 0; i < objects.Count; i++)
            objects[i].Update(mintime);
 
        // perform the collision (update velocities)
        collision.Perform();
 
        // Subtract mintime from remaining
        remaining -= mintime;
 
    } while (true);
 
    for (int i = 0; i < objects.Count; i++) // Since there's no collisions left, simply update the objects to current time
        objects[i].Update(remaining);
}