public static void CollideAndCorrect(BounceBall ball, Vector3 wallNormal, float delta, float collisionTime)
    {
        ball.transform.position += ball.velocity * collisionTime;

        Vector3 reflected = Vector3.Reflect(ball.velocity, wallNormal);

        // debug draw
        {
            Vector3 hitPoint = ball.transform.position + (-wallNormal).normalized * ball.radius;

            Debug.DrawRay(ball.transform.position, ball.velocity.normalized, Color.red);
            Debug.DrawRay(hitPoint, wallNormal, Color.white);
            Debug.DrawRay(ball.transform.position, reflected.normalized, Color.green);

            //Debug.Break();
        }

        ball.velocity = reflected.normalized * ball.speed;

        float remainingTime = delta - collisionTime;

        if (remainingTime < float.Epsilon)
        {
            // done
            ball.translationDone = true;
        }
        else
        {
            ball.ComputeTranslation(remainingTime);
        }
    }
    public static void CollideAndCorrect(BounceBall ball1, BounceBall ball2, float delta, float collisionTime)
    {
        ball1.transform.position += ball1.velocity * collisionTime;
        ball2.transform.position += ball2.velocity * collisionTime;

        Vector3 normal = (ball1.transform.position - ball2.transform.position).normalized;

        Vector3 reflected1 = Vector3.Reflect(ball1.velocity, normal);
        Vector3 reflected2 = Vector3.Reflect(ball2.velocity, normal);

        // debug draw
        {
            Vector3 hitPoint = ball2.transform.position + normal * ball2.radius;

            Debug.DrawRay(ball1.transform.position, ball1.velocity.normalized, Color.red);
            Debug.DrawRay(hitPoint, normal, Color.white);
            Debug.DrawRay(ball1.transform.position, reflected1.normalized, Color.green);

            Debug.DrawRay(ball2.transform.position, ball2.velocity.normalized, Color.red);
            Debug.DrawRay(hitPoint, normal, Color.white);
            Debug.DrawRay(ball2.transform.position, reflected2.normalized, Color.green);

            //Debug.Break();
        }

        ball1.velocity = reflected1.normalized * ball1.speed;
        ball2.velocity = reflected2.normalized * ball2.speed;

        float remainingTime = delta - collisionTime;

        if (remainingTime < float.Epsilon)
        {
            // done
            ball1.translationDone = true;
            ball2.translationDone = true;
        }
        else
        {
            ball1.ComputeTranslation(remainingTime);
            ball2.ComputeTranslation(remainingTime);
        }

        ball1.HasCollidedWith(ball2);
        ball2.HasCollidedWith(ball1);
    }