3

I am creating a 2D physics engine, and I am having trouble with a certain type of collision between movable and immovable objects. What I mean by movable is that the (x,y) values can change, not that the frame of reference can or can't change.

For example, a ball hitting a wall would be something that is movable colliding with something immovable.

ball and wall collision

I believe that I need to use something like Normal Force in this situation, but I am no sure how that would be used for finding the outcome of the collision.

Here is the code that I have so far. This code is for collision between two moving entities, but I need to add a case for when one is not moving:

private static void UpdateEntities(PhysicsEntity a, PhysicsEntity b)
    {
        var collisionAngle = Math.Atan2(a.Position.Y - b.Position.Y, a.Position.X - b.Position.X);
        var angleA = a.Velocity.Direction - collisionAngle;
        var angleB = b.Velocity.Direction - collisionAngle;

        var vAx = a.Velocity.Magnitude * Math.Cos(angleA);
        var vAy = a.Velocity.Magnitude * Math.Sin(angleA);
        var vBx = b.Velocity.Magnitude * Math.Cos(angleB);
        var vBy = b.Velocity.Magnitude * Math.Sin(angleB);

        var vfAx = ((vAx * (a.Mass - b.Mass) + 2 * b.Mass * vBx) / (a.Mass + b.Mass)) * a.Material.Elasticity;
        var vfBx = ((vBx * (b.Mass - a.Mass) + 2 * a.Mass * vAx) / (a.Mass + b.Mass)) * b.Material.Elasticity;
        var vfAy = vAy * a.Material.Elasticity;
        var vfBy = vBy * b.Material.Elasticity;

        var magA = Math.Sqrt(Math.Pow(vfAx, 2) + Math.Pow(vfAy, 2));
        var magB = Math.Sqrt(Math.Pow(vfBx, 2) + Math.Pow(vfBy, 2));
        var dirA = Math.Atan2(vfAy, vfAx) + collisionAngle;
        var dirB = Math.Atan2(vfBy, vfBx) + collisionAngle;

        a.Velocity.X = magA * Math.Cos(dirA);
        a.Velocity.Y = magA * Math.Sin(dirA);
        b.Velocity.X = magB * Math.Cos(dirB);
        b.Velocity.Y = magB * Math.Sin(dirB);

    }

I tried setting the velocity of the immovable object to the opposite of the movable object's velocity, but that caused things to phase into each other.

Jedi_Maseter_Sam
  • 753
  • 4
  • 24
  • Your "immovable" object has a `Velocity`, which can change. Is that anything like the velocity which involves moving? – Beta May 31 '16 at 23:32
  • I don't believe so. Shouldn't the immovable object exert the same amount of force in the opposite direction? (I am not entirely sure if your question was for clarification or if you want to lead me to the answer) – Jedi_Maseter_Sam May 31 '16 at 23:37
  • *"Shouldn't?* You have two entities, `a` and `b`. Which of them is immovable, and why are you setting its velocity? – Beta May 31 '16 at 23:39
  • The code for `a` and `b` is for all collisions. Neither of them have to be immovable, but I need to add a case for when one is immovable. Updated the question to be more specific. – Jedi_Maseter_Sam May 31 '16 at 23:41
  • 1
    Does this code work, in general? If so, then you can make an object immovable (or unimpellable) by setting its mass extremely high. – Beta May 31 '16 at 23:47
  • The code does work. Will setting mass to very high number cause any anomalies like very wrong reflection angle or the velocity of the moving object to be wrong – Jedi_Maseter_Sam May 31 '16 at 23:54
  • Not if your code is correct. **Try it.** – Beta May 31 '16 at 23:57
  • Did you take a look to [this SO post](http://stackoverflow.com/questions/573084/how-to-calculate-bounce-angle) ? – cromod Jun 01 '16 at 22:40

1 Answers1

0

I was able to get help from a friend and we worked out this algorithm to have objects reflect off of immovable objects during a collision.

Modified Original Function:

private static void UpdateEntities(PhysicsEntity a, PhysicsEntity b)
    {
        var collisionAngle = Math.Atan2(a.Position.Y - b.Position.Y, a.Position.X - b.Position.X);

        if (a.IsMoveable && b.IsMoveable)
        {
            var angleA = a.Velocity.Direction - collisionAngle;
            var angleB = b.Velocity.Direction - collisionAngle;

            var vAx = a.Velocity.Magnitude * Math.Cos(angleA);
            var vAy = a.Velocity.Magnitude * Math.Sin(angleA);
            var vBx = b.Velocity.Magnitude * Math.Cos(angleB);
            var vBy = b.Velocity.Magnitude * Math.Sin(angleB);

            var vfAx = ((vAx * (a.Mass - b.Mass) + 2 * b.Mass * vBx) / (a.Mass + b.Mass)) * a.Material.Elasticity;
            var vfBx = ((vBx * (b.Mass - a.Mass) + 2 * a.Mass * vAx) / (a.Mass + b.Mass)) * b.Material.Elasticity;
            var vfAy = vAy * a.Material.Elasticity;
            var vfBy = vBy * b.Material.Elasticity;

            var magA = Math.Sqrt(Math.Pow(vfAx, 2) + Math.Pow(vfAy, 2));
            var magB = Math.Sqrt(Math.Pow(vfBx, 2) + Math.Pow(vfBy, 2));
            var dirA = Math.Atan2(vfAy, vfAx) + collisionAngle;
            var dirB = Math.Atan2(vfBy, vfBx) + collisionAngle;

            a.Velocity.X = magA * Math.Cos(dirA);
            a.Velocity.Y = magA * Math.Sin(dirA);
            b.Velocity.X = magB * Math.Cos(dirB);
            b.Velocity.Y = magB * Math.Sin(dirB);
        }
        else
        {
            var sign = Math.Sign(collisionAngle);
            collisionAngle *= sign;
            while (collisionAngle > Math.PI/2)
            {
                collisionAngle -= Math.PI / 2;
            }
            collisionAngle *= sign;
            if (a.IsMoveable)
            {
                Reflection(ref a, b, collisionAngle);
            }
            else
            {
                Reflection(ref b, a, collisionAngle);
            }
        }
    }

Reflection Function:

        private static void Reflection(ref PhysicsEntity movable, PhysicsEntity immovable, double collisionAngle)
    {
        if (Math.Abs(collisionAngle - Math.PI / 2) < Universe.Epsilon)
        {
            // take the velocity vector, rotate it 180 degrees, scale it
            movable.Velocity.X *= -1;
            movable.Velocity.Y *= -1;
        }
        else if (Math.Abs(movable.Position.Y - immovable.Position.Y) < Universe.Epsilon ||
                 (movable.Position.X > movable.CollisionPoint.X ^ movable.Position.Y < movable.CollisionPoint.Y))
        {
            //take velocity vector, rotate CCW by 2*collisionAngle, scale it
            var rotateAngle = 2 * collisionAngle;
            var xPrime = movable.Velocity.X * Math.Cos(rotateAngle) - movable.Velocity.Y * Math.Sin(rotateAngle);
            var yPrime = movable.Velocity.Y * Math.Cos(rotateAngle) - movable.Velocity.X * Math.Sin(rotateAngle);
            movable.Velocity.X = xPrime;
            movable.Velocity.Y = yPrime;
        }
        else
        {
            //take the vector, rotate it CCW by 360-2*collisionAngle, scale it
            var rotateAngle = 2 * (Math.PI - collisionAngle);
            var xPrime = movable.Velocity.X * Math.Cos(rotateAngle) - movable.Velocity.Y * Math.Sin(rotateAngle);
            var yPrime = movable.Velocity.Y * Math.Cos(rotateAngle) - movable.Velocity.X * Math.Sin(rotateAngle);
            movable.Velocity.X = xPrime;
            movable.Velocity.Y = yPrime;
        }

        movable.Velocity.X *= movable.Material.Elasticity;
        movable.Velocity.Y *= movable.Material.Elasticity;
    }
Jedi_Maseter_Sam
  • 753
  • 4
  • 24