开发者

Area constraint blows up my physics simulation if a body slams into it too fast

I have a physics simulation and it allows you to place area constraints, so that the bodies within will no开发者_开发技巧t 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;
    }
}


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.


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!


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);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜