views:

115

answers:

3

I have a physics simulation and it allows you to place area constraints, so that the bodies within will not exit that area. However if an atom goes past one of the "walls" of the area constraint it blows up the physics simulation. Why does it do this? Update method:

if (!atom.IsStatic)
{
    Vector2 force = Vector2.Zero;
    bool x = false, y = false;
    if (atom.Position.X - atom.Radius < _min.X)
    {
        force = new Vector2(-(_min.X - atom.Position.X), 0);
        if (atom.Velocity.X < 0)
            x = true;
    }
    if (atom.Position.X + atom.Radius > _max.X)
    {
        force = new Vector2(atom.Position.X - _max.X, 0);
        if (atom.Velocity.X > 0)
            x = true;
    }
    if (atom.Position.Y - atom.Radius < _min.Y)
    {
        force = new Vector2(0, -(_min.Y - atom.Position.Y));
        if (atom.Velocity.Y < 0)
            y = true;
    }
    if (atom.Position.Y + atom.Radius > _max.Y)
    {
        force = new Vector2(0, atom.Position.Y - _max.Y);
        if (atom.Velocity.Y > 0)
            y = true;
    }
    atom.ReverseVelocityDirection(x, y);
    if (!atom.IsStatic)
    {
        atom.Position += force;
    }
}
+3  A: 

I see you're doing calculation with a constant time step T. When modeling collisions though on every step you should use time step equal to minimal time before any of atoms reach any obstacle.

Make time step variable, and atoms will never "tunnel" obstacles.

P.S. There are a lot of optimizations in collision detection, please read gamedev papers for information on those.

P.S. A bug?

force = new Vector2(-(_min.X - atom.Position.X), 0);

Force is created separately for X and Y reflection. What happens when the atom gets into a corner? Only second force will be applied.

P.P.S: Use epsilon

One more important note: if you use floating point, the error is accumulated, and you should use eps:

abs(atom.Position.Y + atom.Radium - _max.Y) < eps

where eps is a number much smaller than normal sizes in your task, e.g. 0.000001.

Vladimir Dyuzhev
I use a verlet integration with a constant timestep, plus i was advised to not use a timestep when calculating constraint satisfaction.
RCIX
Good point though i don't think that's the root cause of my problem.
RCIX
A: 

Wouldn't you know, after about half an hour of mindless hacking at it, i thought of simply not applying the position correction. That fixed it like a charm. For any interested, here's the updated code:

if (!atom.IsStatic)
{
    if (atom.Position.X - atom.Radius < _min.X && atom.Velocity.X < 0)
    {
        atom.ReverseVelocityDirection(true, false);
    }
    if (atom.Position.X + atom.Radius > _max.X && atom.Velocity.X > 0)
    {
        atom.ReverseVelocityDirection(true, false);
    }
    if (atom.Position.Y - atom.Radius < _min.Y && atom.Velocity.Y < 0)
    {
        atom.ReverseVelocityDirection(false, true);
    }
    if (atom.Position.Y + atom.Radius > _max.Y && atom.Velocity.Y > 0)
    {
        atom.ReverseVelocityDirection(false, true);
    }
}
RCIX
See my note about epsilon in my message too. May be that's the cause of your original problem.
Vladimir Dyuzhev
Yeah i gotta get around to that. Thanks for reminding me!
RCIX
+1  A: 

You seem to have solved the problem already, but I notice that "force" seems to be wrong. It moves the atom away from the boundary, even if it's on the wrong side. Suppose an atom has shot past _max.X:

if (atom.Position.X + atom.Radius > _max.X) 
    { 
        force = new Vector2(atom.Position.X - _max.X, 0); 
        ...
    } 

Now "force" will be in the +x direction, and the atom's distance from the wall will double with every iteration. Boom!

Beta
oh man it's that simple? Why didn't i see it? Thanks for spotting the error!
RCIX