private static void CalculateSolidEarliestTimeOfImpact(SolidRigidbody solid)
        {
            Console.WriteLine("running on " + solid.Entity);

            float earliest = 1f;

            // Regional check against all statics
            foreach (var staticbody in AllStatics)
            {
                foreach (var collider in solid.Colliders)
                {
                    if (earliest == 0f)
                    {
                        break;
                    }

                    if (PhysicsMath.IntersectMoving(collider, staticbody.MainCollider, solid.ProcessingData.CalcVel, Vector2.Zero, out float first))
                    {
                        Console.WriteLine($"{solid.Entity} ({collider.LocalPosition}) hit {staticbody.Entity} at time {first}");
                        earliest = Math.Min(earliest, first);
                    }
                }
            }

            // Regional check against all solids
            foreach (var otherSolid in AllSolids)
            {
                if (earliest == 0f)
                {
                    break;
                }

                // Skip self
                if (ReferenceEquals(solid, otherSolid))
                {
                    continue;
                }

                if (PhysicsMath.IntersectMoving(solid.MainCollider, otherSolid.MainCollider, solid.ProcessingData.CalcVel, otherSolid.ProcessingData.CalcVel, out float first))
                {
                    Console.WriteLine($"{solid.Entity} hit {otherSolid.Entity} at time {first}");
                    earliest = Math.Min(earliest, first);
                }
            }

            solid.ProcessingData.TimeOfImpact = earliest;
        }
        /// <summary>
        /// Collides the given actor against all other rigidbodies and calculate the allowed velocity during this frame.
        /// </summary>
        /// <remarks>This function will immediately return if the calculated velocity becomes zero.</remarks>
        private static void CalculateActorVelocity(ActorRigidbody actor)
        {
            actor.ProcessingData.CalcVel = actor.Velocity;

            if (actor.Velocity == Vector2.Zero)
            {
                return;
            }


            foreach (var staticbody in AllStatics)
            {
                if (actor.ProcessingData.CalcVel == Vector2.Zero)
                {
                    return;
                }

                if (PhysicsMath.IsOverlapping(actor.MainCollider, staticbody.MainCollider))
                {
                    if (!PhysicsMath.IsSlidingCorner(actor.MainCollider, staticbody.MainCollider))
                    {
                        actor.ProcessingData.CalcVel = VelocityMath.IntoPlane(actor.ProcessingData.CalcVel, PhysicsMath.GetNormal(actor.MainCollider, staticbody.MainCollider));
                    }
                }
            }

            foreach (var solid in AllSolids)
            {
                foreach (var solidCollider in solid.Colliders)
                {
                    if (actor.ProcessingData.CalcVel == Vector2.Zero)
                    {
                        return;
                    }

                    if (PhysicsMath.IsOverlapping(actor.MainCollider, solidCollider))
                    {
                        if (!PhysicsMath.IsSlidingCorner(actor.MainCollider, solidCollider))
                        {
                            actor.ProcessingData.CalcVel = VelocityMath.IntoPlane(actor.ProcessingData.CalcVel, PhysicsMath.GetNormal(actor.MainCollider, solidCollider));
                        }
                    }
                }
            }
        }
 private static void ResolvingPhase()
 {
     foreach (var actor in AllActors)
     {
         foreach (var collider in AllColliders)
         {
             if (actor.Colliders.Contains(collider))
             {
                 continue;                                                         // skip self
             }
             if (PhysicsMath.IsInsideExact(actor.MainCollider, collider))
             {
                 var newPos = PhysicsMath.Depenetrate(actor.MainCollider, collider);
                 Console.WriteLine("Corrected by {0}", (actor.Entity.Position - newPos).ToStringFixed(8));
                 actor.Entity.Position = newPos;
             }
         }
     }
 }
        private static void MoveSolid(SolidRigidbody solid)
        {
            List <ActorRigidbody> pushList     = new List <ActorRigidbody>();
            List <ActorRigidbody> relocateList = new List <ActorRigidbody>();

            // Run global check to see if any actors are attached.
            foreach (var actor in AllActors)
            {
                if (actor.IsAttached(solid))
                {
                    pushList.Add(actor);
                }
            }

            // Run regional check to find any actors that need to be moved during this movement update.
            foreach (var actor in AllActors)
            {
                // Skip if actor has already indicated it should be moved.
                if (pushList.Contains(actor))
                {
                    continue;
                }

                if (PhysicsMath.IntersectPush(solid.MainCollider, actor.MainCollider, solid.Velocity, solid.ProcessingData.TimeOfImpact, out Vector2 delta))
                {
                    pushList.Add(actor);
                    actor.ProcessingData.MoveDelta = delta;
                }
                else if (PhysicsMath.ShouldDrag(actor.MainCollider, solid.MainCollider, actor.Velocity, solid.ProcessingData.CalcVel))
                {
                    relocateList.Add(actor);
                }
            }

            foreach (var actor in pushList)
            {
                actor.Entity.Position += actor.ProcessingData.MoveDelta;

                foreach (var otherSolid in AllSolids)
                {
                    // Skip solid that actor was pushed by
                    if (ReferenceEquals(solid, otherSolid))
                    {
                        continue;
                    }

                    // If resultant position is inside another solid, then actor has to be crushed.
                    if (PhysicsMath.IsInside(actor.MainCollider, otherSolid.MainCollider))
                    {
                        Console.WriteLine($"Crush {actor} against {otherSolid}");
                        actor.Crush();
                    }
                }
            }

            Vector2 solidDelta = solid.ProcessingData.CalcVel * solid.ProcessingData.TimeOfImpact;

            solid.Entity.Position += solidDelta;

            foreach (var actor in relocateList)
            {
                actor.Entity.Position += solidDelta;
                Console.WriteLine($"relocated {actor} by {solidDelta}");
            }
        }
        private static void CalculateSolidVelocity(SolidRigidbody solid)
        {
            solid.ProcessingData.CalcVel = solid.Velocity;

            if (solid.Velocity == Vector2.Zero)
            {
                return;                                             // Early exit if no velocity.
            }
            // Regional check against all static rigidbodies
            foreach (var staticbody in AllStatics)
            {
                foreach (var collider in solid.Colliders)
                {
                    if (solid.ProcessingData.CalcVel == Vector2.Zero)
                    {
                        return;
                    }

                    if (PhysicsMath.IsOverlapping(collider, staticbody.MainCollider))
                    {
                        if (!PhysicsMath.IsSlidingCorner(collider, staticbody.MainCollider))
                        {
                            solid.ProcessingData.CalcVel = VelocityMath.IntoPlane(solid.ProcessingData.CalcVel, PhysicsMath.GetNormal(collider, staticbody.MainCollider));

                            Console.WriteLine($"Solid collision against {staticbody.Entity} ({collider.LocalPosition}) to yield {solid.ProcessingData.CalcVel}");
                        }
                    }
                }
            }

            // Regional check against other solids
            foreach (var otherSolid in AllSolids)
            {
                if (solid.ProcessingData.CalcVel == Vector2.Zero)
                {
                    return;
                }

                // Skip self
                if (ReferenceEquals(solid, otherSolid))
                {
                    continue;
                }

                // Skip if other solid has already processed this solid
                if (otherSolid.ProcessingData.CheckedAgainst.Contains(solid))
                {
                    continue;
                }


                if (PhysicsMath.IsOverlapping(solid.MainCollider, otherSolid.MainCollider))
                {
                    if (!PhysicsMath.IsSlidingCorner(solid.MainCollider, otherSolid.MainCollider))
                    {
                        VelocityPair result = Ruleset.Get(solid, otherSolid);

                        Console.WriteLine($"Collided {solid.Entity} against {otherSolid.Entity} to yield {result.left} and {result.right}");

                        solid.ProcessingData.CalcVel      = result.left;
                        otherSolid.ProcessingData.CalcVel = result.right;

                        solid.ProcessingData.CheckedAgainst.Add(otherSolid);
                        otherSolid.ProcessingData.CheckedAgainst.Add(solid);
                    }
                }
            }
        }