FP3 -- OnCollision events for bullets

Topics: User Forum
Apr 27, 2010 at 10:59 PM

I've got a small, fast-moving object with Bullet = true, and it's colliding with a thin, static object (which it could easily tunnel through if it weren't using CCD).

The bullet never tunnels through the wall, but about half the time, the OnCollision event handler doesn't get called. Which is kind of a problem, since I need to destroy the bullet and add damage to the target when the bullet hits something.

Did I miss something?

Developer
Apr 28, 2010 at 12:43 AM

Can you provide a sample that demonstrates this problem? Once we verify there is a problem I will write similar test code for the C++ version and see if it has the same problem. If so I will file an issue here and with Erin over at Box2D.

 

Apr 28, 2010 at 1:47 AM

Initialisation:

world = new World(Vector2.Zero, true);

Body staticBody = BodyFactory.CreateBody(world);
world.Add(staticBody);

Vertices staticVerts = new Vertices();
staticVerts.Add(new Vector2(-8, -8.4f));
staticVerts.Add(new Vector2(-8, 8));
staticVerts.Add(new Vector2(8, 8));
staticVerts.Add(new Vector2(8, -8.4f));
staticVerts.Add(new Vector2(8.4f, -8.4f));
staticVerts.Add(new Vector2(8.4f, 8.4f));
staticVerts.Add(new Vector2(-8.4f, 8.4f));
staticVerts.Add(new Vector2(-8.4f, -8.4f));

foreach (Vertices poly in FarseerPhysics.Common.Decomposition.BayazitDecomposer.ConvexPartition(staticVerts)) {
	staticBody.CreateFixture(new FarseerPhysics.Collision.Shapes.PolygonShape(poly));
}

Update step:

float fireCooldown = 0.0f;

List toRemove = new List();

public void Update() {
	foreach (Body b in toRemove) {
		world.Remove(b);
	}
	toRemove.Clear();

	if (fireCooldown > 0.0f) {
		fireCooldown -= TimeStep * 0.001f;
	}

	IGraphicsDeviceService graphics = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));

	MouseState mouse = Mouse.GetState();

	if (fireCooldown <= 0 && mouse.LeftButton == ButtonState.Pressed) {
		float target_angle = (float)Math.Atan2(graphics.GraphicsDevice.Viewport.Height / 2 - mouse.Y, mouse.X - graphics.GraphicsDevice.Viewport.Width / 2);
		if (target_angle < 0) {
			target_angle += (float)(2 * Math.PI);
		}

		Fixture f = FixtureFactory.CreateCircle(world, 0.1f, 1f);
		f.Body.Rotation = target_angle;
		f.Body.BodyType = BodyType.Dynamic;
		f.Body.Bullet = true;
		f.OnCollision += OnBulletCollision;

		f.Body.ApplyLinearImpulse(new Vector2((float)Math.Cos(target_angle), (float)Math.Sin(target_angle)) * 4);

		fireCooldown = 0.3f;
	}

	world.Step(0.0018f, 7, 2);
}

private bool OnBulletCollision(Fixture fix1, Fixture fix2, Manifold manif) {
	if (!toRemove.Contains(fix1.Body))
		toRemove.Add(fix1.Body);
	return true;
}

I can provide a complete project if you need, but I would have to extract it all from my game.

 

Half the time, the bullets hit the wall and disappear as they should, and the rest of the time they stop and roll along the wall.

Apr 30, 2010 at 8:03 AM
Edited Apr 30, 2010 at 8:31 AM

For the record, I've also managed to get a small, fast-moving circle object with Bullet = true to completely tunnel through another dynamic, non-Bullet shape (frame n, it's just in front of the obstacle, frame n+1 it's just behind it).

Something seems wrong...

 

EDIT: also, I've been going through the source code trying to work out where the actual CCD happens... SolveToi seems to only pick things up if there's already a contact between two bodies, but if body A passed entirely through body B in one step, surely no contact is generated...?

Apr 30, 2010 at 3:49 PM
Edited Apr 30, 2010 at 3:50 PM
I found another issue related to the oncollision event (so I'll use this same thread). When I try to add a new joint to the world (World.Add(joint) ) during the oncollision event, I get a really ugly exception, in the World.cs line that says Debug.Assert(!Locked); If I add this same joint at another time, it works well :/
Apr 30, 2010 at 10:24 PM

That's not a bug. Because of the way collisions are calculated, you can't add or remove joints (or anything) to the world while it's running the step.

I think that happens in box2d as well.

Developer
May 1, 2010 at 1:12 AM

Nornagon is correct. You must move your joint creation code to after the end of the Step.

There has been a lot of changes to the TOI and CCD code so we may have to do some additional testing.

May 3, 2010 at 6:54 AM

Thanks Nornagon and Matt. I'll move all the creation code outside the event, I'll keep testing now :)