发射大量子弹后 Box2D 碰撞检测失败
Box2D collision detection fails after firing a lot of bullets
我正在做一个物理游戏,遇到了一个奇怪的错误:有时,在发射大量子弹后,碰撞检测开始失败。
从下面的GIF可以看出,碰撞只在一半的平台上起作用,这很奇怪。另外,启用了Box2D调试渲染器,也可以看出平台是单体
这是我如何让这个错误发生的,因为它只在发射大量子弹后才会发生(一开始一切正常):
备注:
- 项目符号的 bullet
字段设置为 true
- 我将玩家的 bullet
字段设置为 true
,没有任何区别
- 玩家是 1 米 x 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()
之后,可能是由于池化?
那么在这种情况下我应该尝试什么才能使碰撞不失败?
我终于修好了。
我找到的解决方案是遍历每个具有 body 的实体并调用 refilter()
,这似乎可以解决问题:
engine.getEntitiesFor(Family.one(BodyComponent::class.java).get()).forEach {
it.body.body.fixtureList.first().refilter()
}
将来,我可以只在需要时调用 refilter()
(如果我能确定何时必须调用它),而不是每帧都调用它,但现在可以使用。
看起来你应该在 body(改变它的 categoryBits
或 maskBits
)之外的 filterData
之后调用 refilter()
=17=],但我似乎没有这样做(或者我可能遗漏了什么),所以有点奇怪。
我正在做一个物理游戏,遇到了一个奇怪的错误:有时,在发射大量子弹后,碰撞检测开始失败。
从下面的GIF可以看出,碰撞只在一半的平台上起作用,这很奇怪。另外,启用了Box2D调试渲染器,也可以看出平台是单体
这是我如何让这个错误发生的,因为它只在发射大量子弹后才会发生(一开始一切正常):
备注:
- 项目符号的 bullet
字段设置为 true
- 我将玩家的 bullet
字段设置为 true
,没有任何区别
- 玩家是 1 米 x 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()
之后,可能是由于池化?
那么在这种情况下我应该尝试什么才能使碰撞不失败?
我终于修好了。
我找到的解决方案是遍历每个具有 body 的实体并调用 refilter()
,这似乎可以解决问题:
engine.getEntitiesFor(Family.one(BodyComponent::class.java).get()).forEach {
it.body.body.fixtureList.first().refilter()
}
将来,我可以只在需要时调用 refilter()
(如果我能确定何时必须调用它),而不是每帧都调用它,但现在可以使用。
看起来你应该在 body(改变它的 categoryBits
或 maskBits
)之外的 filterData
之后调用 refilter()
=17=],但我似乎没有这样做(或者我可能遗漏了什么),所以有点奇怪。