5
\$\begingroup\$

I'm trying to sample random positions to find one that is sufficiently far from other bodies.

Hence I'd need to test for bodies within a given circle. So far, I've used b2World::QueryAABB around my circle (which does what I want but for a rectangular area), then manually doing an intersection test with all the fixtures it gives me.

It seems to me like Box2D should already provide such functionality—is there a way that lets me do this without reinventing most of the wheel?

\$\endgroup\$
1

2 Answers 2

6
\$\begingroup\$

I suggest using a sensor.

  1. Create a circular body of the size of you choosing at the location you desire.
  2. Set the Sensor flag to true.
  3. Leave it there for a step. (The delta can be 0 units)
  4. See if the sensors isTouching flag is set to true.

box2d Manual

Sometimes game logic needs to know when two fixtures overlap yet there should be no collision response. This is done by using sensors. A sensor is a fixture that detects collision but does not produce a response.

You can flag any fixture as being a sensor. Sensors may be static or dynamic. Remember that you may have multiple fixtures per body and you can have any mix of sensors and solid fixtures.

Sensors do not generate contact points. There are two ways to get the state of a sensor:

  1. b2Contact::IsTouching
  2. b2ContactListener::BeginContact and EndContact
\$\endgroup\$
4
  • \$\begingroup\$ If you need to leave the sensor for a step, that's a little tough if you're trying to find a location to place your object: "Is here good? nope... What about here? nope.. etc" \$\endgroup\$ Commented Apr 13, 2012 at 16:49
  • \$\begingroup\$ Yea, especially since I might have to sample a lot of points to actually find one that is free. Can't just leave it there for x steps. Other than that, it's a nice suggestion.. \$\endgroup\$
    – ltjax
    Commented Apr 13, 2012 at 17:19
  • \$\begingroup\$ @John McDonald No need to wait a frame if that's what your implying. Just have a time delta of 0 ms when you do the step. It will update collision but not move anything. \$\endgroup\$ Commented Apr 13, 2012 at 18:11
  • \$\begingroup\$ Ahh, that makes more sense. Thanks for updating the answer too btw \$\endgroup\$ Commented Apr 13, 2012 at 18:59
4
\$\begingroup\$

For completeness, I'll document the "reinventing the wheel" approach.

I recently wanted to do this too, but I wanted to do it statically (due to some code-structure decisions made before that I didn't want to break). So I didn't want to create a sensor body and World.Step, as previously suggested.

Instead, I figured that a convex polygon intersects with a circle if

  • some of the polygon's corners are in the circle, or
  • a raycast from the center of the circle toward its center hits in the circle

Both can be determined statically, with some simple math and World.RayCast.

For the corners: Get them by calling fixture.GetShape().GetVertices(). Make sure to transform them from the Body's local coordinate space into world coordinates using body.GetWorldPoint. Then determine intersection by comparing their distances from the circle center to the circle's radius.

For the sides: RayCast a vector from the center of the circle toward the center of the tank with the length of the radius. If you get anything, it's a hit.


Why you need to check both cases:

If you only check the corners, a side between them might still intersect.

collision with side, but not corners

If your raycast toward the middle misses, a corner might still intersect.

collision with corner not caught by raycast

Depending on your objects' relative dimensions and the required precision, doing just one of these could be a good approximation.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .