Sign in to follow this  

Bounding Box - Push away objects

This topic is 4841 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A quick way is to take the minimum overlap between the boxes, and use that to push the objects around. Not very accurate, but it's a start.



bool Collide(Box A, Box B, Vector& PushVector)
{
Vector ABpush(A.Max - B.Min);
Vector BApush(B.Max - A.Min);

if (ABpush.x < 0.0f || ABpush.y < 0.0f || ABpush.z < 0.0f ||
BApush.x < 0.0f || BApush.y < 0.0f || BApush.z < 0.0f)
return false;

PushVector = Vector((ABpush.x < BApush.x)? -ABpush.x : BApush.x,
(ABpush.y < BApush.y)? -ABpush.y : BApush.y,
(ABpush.z < BApush.z)? -ABpush.z : BApush.z);

float min;
if (fabs(PushVector.y) < fabs(PushVector.x))
{
PushVector.x = 0.0f;
min = PushVector.y;
}
else
{
PushVector.y = 0.0f;
min = PushVector.x;
}

if (fabs(PushVector.z) < min)
{
PushVector.x = PushVector.y = 0.0f;
}
else
{
PushVector.z = 0.0f;
}

return true;
}

// if boxA intersects boxB, push boxA away
Vector PushVector;
if (Collide(BoxA, BoxB, PushVector))
{
BoxA.Min += PushVector;
BoxA.Max += PushVector;
}

Share this post


Link to post
Share on other sites
Sure, circle to box is a little more difficult than bounding box. Linear algebra is a plus. This in fact requires 8 tests. The first four are against the lines, and the other four are against the points. Of course, some of these can be eliminated with some clever coding. I'm feeling generous, so I'll post how I do sphere against box:


public static bool ballAgainstRectangleMove(Sprite ball, Sprite rectangle)
{
Point ballPoint = new Point(ball.x, ball.y);

Segment topEdge = new Segment(new Point(-rectangle.sclX, rectangle.sclY), new Point(rectangle.sclX, rectangle.sclY));
CommonFunctions.RotateLineAroundPoint(new Point(0, 0), ref topEdge, rectangle.rotZ);
topEdge.MoveBy(rectangle.x, rectangle.y);

float smallestDistance;
string edgeClosestTo;

Math2D.Segment collisionPointToBall = new Segment();


smallestDistance = ballPoint.DistanceTo(topEdge,ref collisionPointToBall);
edgeClosestTo = "top";

Segment bottomEdge = new Segment(new Point(-rectangle.sclX, -rectangle.sclY), new Point(rectangle.sclX, -rectangle.sclY));
CommonFunctions.RotateLineAroundPoint(new Point(0, 0), ref bottomEdge, rectangle.rotZ);
bottomEdge.MoveBy(rectangle.x, rectangle.y);
if(ballPoint.DistanceTo(bottomEdge) < smallestDistance)
{
smallestDistance = ballPoint.DistanceTo(bottomEdge,ref collisionPointToBall);
edgeClosestTo = "bottom";
}

Segment leftEdge = new Segment(new Point(-rectangle.sclX, rectangle.sclY), new Point(-rectangle.sclX, -rectangle.sclY));
CommonFunctions.RotateLineAroundPoint(new Point(0, 0), ref leftEdge, rectangle.rotZ);
leftEdge.MoveBy(rectangle.x, rectangle.y);
if(ballPoint.DistanceTo(leftEdge) < smallestDistance)
{
smallestDistance = ballPoint.DistanceTo(leftEdge,ref collisionPointToBall);
edgeClosestTo = "left";
}
Segment rightEdge = new Segment(new Point(rectangle.sclX, rectangle.sclY), new Point(rectangle.sclX, -rectangle.sclY));
CommonFunctions.RotateLineAroundPoint(new Point(0, 0), ref rightEdge, rectangle.rotZ);
rightEdge.MoveBy(rectangle.x, rectangle.y);
if(ballPoint.DistanceTo(rightEdge) < smallestDistance)
{
smallestDistance = ballPoint.DistanceTo(rightEdge,ref collisionPointToBall);
edgeClosestTo = "right";
}

if(smallestDistance < ball.sclX)
{
float remainingDistance = ball.sclX - smallestDistance;
Vector2 amountToMove = new Vector2(ballPoint.x - collisionPointToBall.p1.x, ballPoint.y - collisionPointToBall.p1.y);
amountToMove.Normalize();
amountToMove = amountToMove * remainingDistance;
ball.x += amountToMove.X;
ball.y += amountToMove.Y;
return true;
}
else
return false;
}



Wow, that's a lot of code. But it's a start. If you're interested in discussing it, you can send me a message on AOL Instant Messenger: ArmySarj.

Good luck.

--vic--

Share this post


Link to post
Share on other sites
for sphere box, it's actually quite similar. You need to find the closest point on the box to the sphere centre, which is similar to the code I posted, but even simpler in the case of the centre being outside the box. Then it's a matter of testing if that point is inside the sphere, if it is, calculate the point on the sphere that is the closest to that point (again, take the opposite point of the sphere centre is inside the box), and push the sphere so that the two contact points meet.


// returns if point is inside the box already
bool ClosestPointOnBox(Vector P, Box B, Vectop& Q)
{
Vector D = (P - Box.Centre);

// Vector::Abs() takes abosilute values of x, y, z, store it
// in vector form
Vector F = Box.Extent - D.Abs();

if (inx && iny && inz)
{
float min;
if (F.x < F.y)
{
D.y = 0.0f;
min = F.x;
}
else
{
D.x = 0.0f;
min = F.y;
}
if (F.z < min)
{
D.x = D.y = 0.0f;
}
else
{
D.z = 0.0f;
}

// Vector::Sign() calcualtes the sign of x, y , z and
// store it as vector
D = D.Sign();
D.ScaleBy(Box.Extent);

Q = B.Centre + D;
}
else
{
if (inxx) D.x = sgn(D.x) * Box.Extent.x;
if (inxy) D.y = sgn(D.y) * Box.Extent.y;
if (inxz) D.z = sgn(D.z) * Box.Extent.z;

Pbox = Box.Centre + D;
return false;
}
}

bool PointInsideSphere(SphereS, Vector P)
{
Vector D = P - S.Centre;
float d2 = D.LengthSquared();
return (d2 < Sphere.Radius2);
}

Vector ClosestPointOnSphere(Vector P, Sphere S)
{
Vector D = P - S.Centre;
D /= D.Length();
return S.Centre + D * Sphere.Radius;
}


Vector FurthestPointOnSphere(Vector P, Sphere S)
{
Vector D = P - S.Centre;
D /= D.Length();
return S.Centre - D * Sphere.Radius;
}


bool ContactPoints(Sphere S, Box B, Vector& Pbox, Vector& Psphere)
{
bool inside = ClosestPointOnBox(S.Centre, B, Pbox);

if (!PointInsideSphere(S, Pbox))
return false;

if (inside)
{
FurthestPointOnSphere(Pbox, S, Psphere);
}
else
{
ClosestPointOnSphere(Pbox, S, Psphere);
}
return true;
}

bool Collide(Sphere S, Box B, Vector& Push)
{
Vector Psphere;
Vector Pbox;

if (!ContactPoints(S, B, Psphere, Pbox))
return false;

Push = Pbox - Psphere;
return true;
}




that's what I use. And the method can be generalised to any kind of convex shapes, like triangles, segments and polygons.

Share this post


Link to post
Share on other sites

This topic is 4841 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this