Обнаружение столкновения Box2D не удается после запуска большого количества пуль - PullRequest
1 голос
/ 29 апреля 2019

Я работаю над игрой в физику и столкнулся со странной ошибкой: иногда, после запуска большого количества пуль, обнаружение столкновений начинает давать сбой.

Как видно в следующем GIF, столкновение работает только на половине платформы, что очень странно. Также включен отладчик Box2D и видно, что платформа представляет собой единое тело.

Bug

Вот как я могу получить эту ошибку, поскольку это происходит только после запуска большого количества пуль (в начале все работает нормально):

Replicate

Примечания:
- для пули в поле bullet установлено значение true
- Я установил в поле bullet игрока значение true, без разницы
- игрок 1 метр на 1 метр
- игрок и патроны DynamicBodies и платформы StaticBodies
- карта близка к (0, 0), хотя она немного отрицательна (-1,5), я сомневаюсь, что это имеет значение
- categoryBits и maskBits являются правильными (столкновение должно произойти, и это происходит, но глюки)
- после исчезновения пуль количество тел будет таким же, как и в начале игры (поэтому они фактически уничтожены)
- сила тяжести World равна (0, -25f)
- игра работает на скорости 60fps

Вот код временного шага Box2D, аналогичный пошаговому коду из 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
    }
}

Я пытался изменить:
- TIME_STEP до более низкого значения, например 1 / 60f
- VELOCITY_ITERATIONS чуть выше, до 8
- POSITION_ITERATIONS чуть выше, до 6
- VELOCITY_ITERATIONS и POSITION_ITERATIONS до 100
и не было (очевидной) разницы.

Концерн
Поврежденная платформа, кажется, начинает вести себя как пуля (она не сталкивается с другими пулями или игроком), по крайней мере, на полпути. Так могут ли categoryBits и maskBits быть изменены на лету, после большого количества world.createBody() и world.destroyBody(), возможно, из-за объединения?

Так, что я должен попытаться, чтобы столкновение не провалилось в этом случае?

1 Ответ

2 голосов
/ 02 мая 2019

Мне наконец-то удалось это исправить.

Решение, которое я нашел, состояло в том, чтобы перебрать каждую сущность, которая имеет тело, и вызвать refilter(), который, кажется, исправляет это:

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

В будущем я мог бы вызывать refilter() только тогда, когда это необходимо (если я могу определить, когда я должен вызывать его), вместо того, чтобы вызывать его каждый кадр, но пока это работает.

Похоже, вам следует позвонить refilter() после того, как вы изменили filterData тела (изменив его categoryBits или maskBits) вне FixtureDef, но я, похоже, этого не делаю ( или, может быть, я что-то упустил), так что это немного странно.

...