Simulating smooth movement along a line after calculating a collision containing a restitution of zero in 2D
- by Casey
[for tl;dr see after listing]
//...Code to determine shapes types involved in collision here...
//...Rectangle-Line collision detected.
if(_rbTest->GetCollisionShape()->Intersects(*_ground->GetCollisionShape())) {
//Convert incoming shape to a line.
a2de::Line l(*dynamic_cast<a2de::Line*>(_ground->GetCollisionShape()));
//Get line's normal.
a2de::Vector2D normal_vector(l.GetSlope().GetY(), -l.GetSlope().GetX());
a2de::Vector2D::Normalize(normal_vector);
//Accumulate forces involved.
a2de::Vector2D intermediate_forces;
a2de::Vector2D normal_force = normal_vector * _rbTest->GetMass() * _world->GetGravityHandler()->GetGravityValue();
intermediate_forces += normal_force;
//Calculate final velocity: See [1]
double Ma = _rbTest->GetMass();
a2de::Vector2D Ua = _rbTest->GetVelocity();
double Mb = _ground->GetMass();
a2de::Vector2D Ub = _ground->GetVelocity();
double mCr = Mb * _ground->GetRestitution();
a2de::Vector2D collision_velocity( ((Ma * Ua) + (Mb * Ub) + ((mCr * Ub) - (mCr * Ua))) / (Ma + Mb));
//Calculate reflection vector: See [2]
a2de::Vector2D reflect_velocity( -collision_velocity + 2 * (a2de::Vector2D::DotProduct(collision_velocity, normal_vector)) * normal_vector );
//Affect velocity to account for restitution of colliding bodies.
reflect_velocity *= (_ground->GetRestitution() * _rbTest->GetRestitution());
_rbTest->SetVelocity(reflect_velocity);
//THE ULTIMATE ISSUE STEMS FROM THE FOLLOWING LINE:
//Move object away from collision one pixel to prevent constant collision.
_rbTest->SetPosition(_rbTest->GetPosition() + normal_vector);
_rbTest->ApplyImpulse(intermediate_forces);
}
Sources:
(1) Wikipedia: Coefficient of Restitution: Speeds after impact
(2) Wikipedia: Specular Reflection: Direction of reflection
First, I have a system in place to account for friction (that is, a coefficient of friction) but is not used right now (in addition, it is zero, which should not affect the math anyway). I'll deal with that after I get this working.
Anyway, when the restitution of either object involved in the collision is zero the object stops as required, but if movement along the same direction (again, irrespective of the friction value that isn't used) as the line is attempted the object moves as if slogging through knee deep snow. If I remove the line of code in question and the object is not push away one pixel the object barely moves at all. All because the object collides, is stopped, is pushed up, collides, is stopped...etc. OR collides, is stopped, collides, is stopped, etc...
TL;DR
How do I only account for a collision ONCE for restitution purposes (BONUS: but CONTINUALLY for frictional purposes, to be implemented later)