1
votes

I am working on a physics game and encountered a strange bug: sometimes, after firing a lot of bullets, collision detection starts to fail.

As can be seen in the following GIF, the collision works only on half the platform, which is very strange. Also, the Box2D debug renderer is enabled and it can also be seen that the platform is a single body.

Bug

Here is how I get this bug to happen, as it only happens only after firing lots of bullets (in the beginning everything works fine):

Replicate

Notes:
- the bullet has the bullet field set to true
- I set the player's bullet field to true, did not make a difference
- the player is 1 meter by 1 meter
- the player and the bullets are DynamicBodies and the platforms are StaticBodies
- the map is near to (0, 0), though it goes a bit in the negatives (-1.5), I doubt it matters
- the categoryBits and maskBits are correct (the collision should happen, and it does happen, but glitches)
- after the bullets disappear, the number of bodies is the same as when the game starts (so they are actually destroyed)
- the World's gravity is (0, -25f)
- the game runs at 60fps

Here is the Box2D timestep code, similar to the stepping code from the libGDX wiki:

companion object {
    private const val TIME_STEP = 1f / 300f
    private const val VELOCITY_ITERATIONS = 6
    private const val POSITION_ITERATIONS = 2
}

private var accumulator = 0f

override fun update(deltaTime: Float) {
    accumulator += Math.min(deltaTime, 0.25f)
    while (accumulator >= TIME_STEP) {
        world.step(TIME_STEP, VELOCITY_ITERATIONS, POSITION_ITERATIONS)
        accumulator -= TIME_STEP
    }
}

I tried changing:
- TIME_STEP to a lower value, like 1/60f
- VELOCITY_ITERATIONS a bit higher, to 8
- POSITION_ITERATIONS a bit higher, to 6
- VELOCITY_ITERATIONS and POSITION_ITERATIONS to 100
and there was no (obvious) difference.

Concern:
The bugged platform seems to start behaving like a bullet (it doesn't collide with other bullets or with the player), at least halfway. So could its categoryBits and maskBits be changed on-the-fly, after a lot of world.createBody() and world.destroyBody(), maybe due to pooling?

So what should I try for the collision not to fail in this case?

1
You are not doing anything with bullet position other than applying a force to the bullets when you fire them?Laurence
Also, are you using a contact listener, or are you iterating and checking contacts?Laurence
It looks like it is some section of the wall that remains "broken". In your collision listener, your bullet and wall fixtures will not always be the same arguments. You are definitely destroying or manipulating the bullet in your collisions?Laurence
Cool ya just ruling things out. Just to let you know I have built games which shoot constant streams of bullets that bounced, so this is not a box2d issue.Laurence
Can you turn your own rendering off, just the box2d debug?Laurence

1 Answers

2
votes

I finally managed to fix it.

The solution I found was to loop through every entity that has a body and call refilter(), which seems to fix it:

engine.getEntitiesFor(Family.one(BodyComponent::class.java).get()).forEach {
    it.body.body.fixtureList.first().refilter()
}

In the future, I could call refilter() only when needed (if I can determine when I have to call it) instead of calling it every frame, but it works for now.

It looks like you should call refilter() after you change the filterData of a body (changing its categoryBits or maskBits) outside the FixtureDef, but I don't seem to be doing that (or maybe I am missing something), so it is a bit weird.