// Update the particle
debug_Particle.Integrate(dt_Seconds);
// Set the rectangle's centre to the particle position
debug_Rectangle[0].Centre = debug_Particle.Position;
if (Detection2D.TestRectangleRectangle(debug_Rectangle[0], debug_Rectangle[1], ref contact))
{
// Correct the intersection
debug_Rectangle[0].Centre += contact.normal * contact.penetration;
// Correct the velocity
// Sliding response (remove all components of velocity along the normal of collision)
float vDotN = Vector2.Dot(debug_Particle.Velocity, contact.normal);
debug_Particle.Velocity -= contact.normal * vDotN;
}
Collision response with velocity not correct with rectangle corners?
Hi folks,
If I have two rectangles, one static and the other controllable, I can resolve an intersection between the two using:
rectangle_Moving.Centre += contact.normal * contact.penetration;
If I decide to create a particle that lies at the centre of the moving rectangle and update the position of the rectangle based on the particle's position, then the collision resolution steps I take are as follows:
- Integrate particle
- Set moving rectangle centre to particle's current position
- Test for intersection
[If intersecting]:
- Adjust rectangle position (as shown above)
- Adjust particle velocity
Unfortunately the collision resolution doesn't work as planned and the moving rectangle will stick to the static rectangles corners.
Can anyone please tell me what I may have done wrong here please?
Thank you.
Have you made sure that the contact.normal is always perpendicular to only one of the static rectangle's sides? (And that the contact.penetration is along that vector)
- Because if the normal would be diagonal (e.g. on a corner) it could cause getting stuck, when both the horizontal and vertical velocity may be canceled by the corresponding diagonal correction.
- Because if the normal would be diagonal (e.g. on a corner) it could cause getting stuck, when both the horizontal and vertical velocity may be canceled by the corresponding diagonal correction.
The rectangles never get stuck when just adjusting position, only when adjusting velocity.
The collision normals are only ever perpendicular to the rectangle sides and are never diagonal for the corners.
I am integrating my particle as follows:
Maybe that is where I am going wrong?
The collision normals are only ever perpendicular to the rectangle sides and are never diagonal for the corners.
I am integrating my particle as follows:
public void Integrate(float duration) { // We don't integrate things with zero mass // <= ??!??!?! 0 = infinite mass?!?!?!?!?!?!?!?! if (mass_Inverse <= 0.0f) { return; } // ========================================================================================================== // • Work out the acceleration from all the forces acting on the particle // • Forces are stored in force_Accumulated for (int i = 0; i < force_Generators.Count; i++) { force_Generators.UpdateForce(this, duration); } // ========================================================================================================== // Update acceleration from accumulated forces Vector2 acceleration_Resulting = acceleration; acceleration_Resulting += force_Accumulated; // Update linear velocity from the acceleration velocity += acceleration_Resulting * duration; // Update linear position position += velocity * duration; // Clear the accumulated forces ClearAccumulatedForce(); }
Maybe that is where I am going wrong?
I don't see anything causing sticking there, the velocity is accumulated and should keep any sliding. Especially if you have 0 force.
I presume the particle is completely still when you describe it as stuck, and that there is nothing that keeps driving/accelerating the particle after a first collision-correction.
If you can make a debugger breakpoint when getting stuck on a corner try to confirm that the velocity really gets parallel to the static rect-side (to see whether first code snippet works), then step until next loop update and ensure that the same velocity remains "sliding" the same way - if it does not that indicates the velocity has been lost somewhere else, which it shouldn't.
Such a loss can possibly be caused by copying only part of the particle data, or modifying a temporary instance instead of the real one, or another code part interrupting (the debugger can help find that). Personally I use to find "data breakpoint" useful when a variable is correct at one point but gets wrong at an unknown point.
I presume the particle is completely still when you describe it as stuck, and that there is nothing that keeps driving/accelerating the particle after a first collision-correction.
If you can make a debugger breakpoint when getting stuck on a corner try to confirm that the velocity really gets parallel to the static rect-side (to see whether first code snippet works), then step until next loop update and ensure that the same velocity remains "sliding" the same way - if it does not that indicates the velocity has been lost somewhere else, which it shouldn't.
Such a loss can possibly be caused by copying only part of the particle data, or modifying a temporary instance instead of the real one, or another code part interrupting (the debugger can help find that). Personally I use to find "data breakpoint" useful when a variable is correct at one point but gets wrong at an unknown point.
Quote:
I presume the particle is completely still when you describe it as stuck, and that there is nothing that keeps driving/accelerating the particle after a first collision-correction.
The particle velocity is (0,0) when it is "stuck" at the corner. If the particle is traveling in the +ve y direction the y velocity remains at 0 when sliding and never changes.
Maybe the problem might be that the collision detection is returning the wrong axis when the rectangles are parallel?
Can anyone please confirm/deny that this might be the case?
public static bool TestRectangleRectangle(Collidable2D col_A, Collidable2D col_B, ref Contact2D contact) { CD_Rectangle a = (CD_Rectangle)col_A; CD_Rectangle b = (CD_Rectangle)col_B; // [Separating Axis Theorem] // • Two convex shapes only overlap if they overlap on all axes of separation // • In order to create accurate responses we need to find the collision vector (Minimum Translation Vector) // • Find if the two boxes intersect along a single axis // • Compute the intersection interval for that axis // • Keep the smallest intersection/penetration value // Minimum Translation Vector parameters float mtv_Distance = float.MaxValue; // Set current minimum distance (max float value so next value is always less) int mtv_Axis = 0; // Axis along which to travel with the minimum distance // For each separating axis for (int i = 0; i < 2; i++) { // Find distance intervals for current two slabs // Distance is between slab min/max values float d_S0 = a.MinPoint.Index(i) - b.MaxPoint.Index(i); float d_S1 = b.MinPoint.Index(i) - a.MaxPoint.Index(i); // The distance is positive if the intervals do not overlap if (d_S0 > 0f || d_S1 > 0f) { return false; } // Current distance interval for slabs float d = (d_S0 > d_S1) ? -d_S0 : d_S1; // If d is the smallest distance so far if (Math.Abs(d) < Math.Abs(mtv_Distance)) { // Store the distance and the current axis mtv_Distance = d; mtv_Axis = i; } } // Minimum Translation Vector Vector2 mtv = Vector2.Zero; switch (mtv_Axis) { case 0: mtv.X = mtv_Distance; break; case 1: mtv.Y = mtv_Distance; break; } contact.normal = Vector2.Normalize(mtv); contact.penetration = Math.Abs(mtv_Distance) + Constants.EPSILON; return true; }
Do I need to change the above method to avoid incorrect collision detection when the rectangles are parallel?
Thank you.
I have discovered what I think is now the true source of the problem.
When I push the particle in a +y direction using the following:
The particle's velocity will be 0 in the push direction upon collision, which is correct. However, the particle's position will slowly push into the +y direction even when a collision is detected.
This can be resolved using:
debug_Particle.Position -= contact.normal * contact.penetration;
but this is not a good way of applying physics, correct? I should be applying velocities to the particle!
Can anyone explain why the particle position keeps moving in +y direction, even when the velocity in that direction is 0, and how can I stop it?
The current method for collision resolution is as follows:
Thank you for your help.
When I push the particle in a +y direction using the following:
class Particle2D_UserInput : IParticle2D_ForceGenerator { public Particle2D_UserInput() { } public override void UpdateForce(Particle2D particle, float duration) { Vector2 force = Vector2.Zero; // Get user input state if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Up)) { force += Vector2.UnitY; } if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Down)) { force += -Vector2.UnitY; } if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Left)) { force += -Vector2.UnitX; } if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Right)) { force += Vector2.UnitX; } particle.AddForce(force); } }
The particle's velocity will be 0 in the push direction upon collision, which is correct. However, the particle's position will slowly push into the +y direction even when a collision is detected.
This can be resolved using:
debug_Particle.Position -= contact.normal * contact.penetration;
but this is not a good way of applying physics, correct? I should be applying velocities to the particle!
Can anyone explain why the particle position keeps moving in +y direction, even when the velocity in that direction is 0, and how can I stop it?
The current method for collision resolution is as follows:
// Update the particle debug_Particle.Integrate(dt_Seconds); // Set the polygon centre to the particle position debug_Polygon2D[1].Centre = debug_Particle.Position; // Test for 2D Swept SAT if (Detection2D.TestMovingPolygonPolygon(debug_Polygon2D[0], debug_Polygon2D[1], ref contact)) { T0 = contact.t0; T1 = contact.t1; // Adjust position debug_Polygon2D[1].Centre -= contact.normal * contact.penetration; // IF I ADJUST PARTICLE POSITION - No more sticking debug_Particle.Position -= contact.normal * contact.penetration; // Adjust velocity float vDotN = Vector2.Dot(debug_Particle.Velocity, contact.normal); debug_Particle.Velocity -= contact.normal * vDotN; } // Set polygon's centre/velocity to associated particle's position/velocity debug_Polygon2D[1].velocity = debug_Particle.Velocity;
Thank you for your help.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement