我正在做一个物理游戏,遇到一个奇怪的错误:有时,在发射很多子弹后,碰撞检测开始失败。
在以下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()
是否可以即时更改?
那么在这种情况下如何使碰撞不失败?
答案 0 :(得分:2)
我终于设法修复了它。
我发现的解决方案是遍历每个具有主体的实体并调用refilter()
,这似乎可以解决该问题:
engine.getEntitiesFor(Family.one(BodyComponent::class.java).get()).forEach {
it.body.body.fixtureList.first().refilter()
}
将来,我只能在需要时调用refilter()
(如果我可以确定何时必须调用它),而不是在每一帧都调用它,但现在可以使用。
在refilter()
外部更改实体的filterData
(更改其categoryBits
或maskBits
)之后,您似乎应该呼叫FixtureDef
,但是我似乎并没有这样做(或者可能我缺少了一些东西),所以有点奇怪。