libGDX – Box2D 世界步进中出现无限循环

huangapple go评论79阅读模式
英文:

libGDX - endless loop in Box2D world step

问题

我正在使用libGDX开发一个小游戏,使用Box2D进行碰撞检测。一切正常,直到我在游戏中添加了一个箭头,以便玩家可以射击。自从我添加了这个功能以后,我遇到了一个问题,游戏时不时地会卡住,不再响应。

我认为这种行为的原因是在Box2D世界步进的某个地方有一个无限循环。当我使用调试器停止执行时,停止点总是在World.step(float, int, int)方法中。不幸的是,这是一个本地方法,所以我无法确切找到问题所在:

// 来自 com.badlogic.gdx.physics.box2d.World

public void step (float timeStep, int velocityIterations, int positionIterations) {
	jniStep(addr, timeStep, velocityIterations, positionIterations);
}

private native void jniStep (long addr, float timeStep, int velocityIterations, int positionIterations);

问题:

有时在使用新的“射箭”功能时,执行似乎会停止,游戏会冻结。很难复现,因此我无法确定真正的根本原因。它只在向Box2D世界添加新的箭头时才会出现,但问题并不总是出现。

我迄今为止尝试过的:

  • 为了验证问题是否在Box2D代码内部,我尝试将箭头的夹具的掩码更改为0x0000,以便它不与任何其他对象发生碰撞。这实际上修复了问题(或者至少我无法再复现问题)。但这并没有太大帮助,因为不击中任何东西的箭对游戏来说没有多大用处...
  • 更改夹具的掩码,使其不与特定类别(称为CATEGORY_OBSTACLE)发生碰撞,似乎也修复了问题,但我不知道原因,而且这仍然不是一个真正的解决方案...

代码:

由于我甚至似乎无法可靠地复现问题,我也无法创建一个最小可重现示例。我只能指向游戏的GitHub存储库。对此感到抱歉 libGDX – Box2D 世界步进中出现无限循环 当前的代码位于projectile_bug分支中。

为了解释一下代码:

  • GameScreen有一个render方法,在其中调用了World.step方法(导致无限循环)。
  • Dwarf有一个executeSpecialAction方法,通过一些工厂方法开始创建箭头
  • 最后,类ProjectileFactory有一个createProjectile方法,用于创建箭头并将其添加到世界中。
  • Box2D夹具使用PhysicsBodyCategories类中的掩码 MASK_PLAYER_ATTACK

复现步骤:

由于我真的不知道问题的根本原因,所以只能通过在地图上射击一些箭来复现这个错误:

  • 使用desktop子项目中DesktopLauncher类中的main方法启动游戏。
  • 在世界上移动并使用空格键发射一些箭头
  • 希望错误会出现...通常需要在世界上射出很多箭头才会出现错误(我在projectile_bug分支中增加了射击速率以加快速度)

问题:

我不确定是什么原因导致了这个错误,而且我对Box2D还相当陌生。如果有人知道如何修复这个问题或者对这个问题有任何解决方法,那将对我帮助很大。如果您还了解一些相关的已报告错误或类似的内容,也会有所帮助。

提前谢谢您的帮助。

英文:

I'm working on a little game with libGDX, that uses Box2D for collision detection. This was working fine, till I added an arrow to the game, so the player can shoot. Since I added this feature I'm facing the problem that the game gets stuck from time to time, and doesn't react anymore.

I think the reason for this behaviour is an endless loop somewhere in the Box2D world step. When I stop the execution using the debugger the stopping point is always in the World.step(float, int, int) method. Unfortunately this is a native method so I can't find where the problem is exactly:

// from com.badlogic.gdx.physics.box2d.World

public void step (float timeStep, int velocityIterations, int positionIterations) {
	jniStep(addr, timeStep, velocityIterations, positionIterations);
}

private native void jniStep (long addr, float timeStep, int velocityIterations, int positionIterations);

<hr>

The problem:

Sometimes when using the new "shoot arrow" feature the execution seems to stop and the game just freezes. It is realy hard to reproduce, therefore I can't realy tell what the real root cause is. It only appears when adding a new arrow to the Box2D world, but the problem does not appear all the time.

<hr>

What I've tried so far:

  • To validate that the problem is within the Box2D code, I've tried to change the mask of the arrow's fixture to 0x0000, so it doesn't collide with any other object. This actually fixed the problem (or at least I couldn't reproduce it anymore). But this doesn't help very much, because an arrow that doesn't hit anything isn't very usefull in the game...
  • Changing the mask of the fixture, so it doesn't collide with a specific category (called CATEGORY_OBSTACLE) also seemed to fix the problem, but I have no idea why, and still this isn't realy a solution...

<hr>

The code:

Since I couldn't seem to even reliably reproduce the problem, I also wasn't able to create a minimal reproducable example. I can only point to the GitHub repo of the game. Sorry for this libGDX – Box2D 世界步进中出现无限循环 The current code is placed in the branch projectile_bug.

To explain the code a bit:

  • The class GameScreen has a render method, from which the World.step method is called (the one that causes the endless loop).
  • The class Dwarf has an executeSpecialAction method, which starts the creation of the arrow through some factory methods.
  • In the end, the class ProjectileFactory has a createProjectile method, that creates the arrow and adds it to the world.
  • The categories and masks that are used by the Box2D fixtures are placed in the PhysicsBodyCategories class. The arrow's fixture uses the mask MASK_PLAYER_ATTACK

<hr>

Steps to reproduce:

Since I don't realy know the root cause of the problem, the bug can only be reproduced by shooting some arrows over the map:

  • Start the game using the main method in the class DesktopLauncher in the desktop-subproject.
  • Move over the world and fire some arrows using the space key
  • Hope for the bug to appear... It usually takes quite some arrows on the world for the bug to appear (I increased the fire rate in the projectile_bug branch to speed things up a bit)

<hr>

The Question:

I'm not sure what causes this bug and I'm still quite new to Box2D. If anyone has an idea on how to fix this or knows a workarround for this problem, it would realy help me a lot. Also if you know about some related, reported bugs or anything like this, it could also help.

Thanks in advance.

答案1

得分: 1

好的,我咬了这个问题。根据我的经验,当刚体或夹具没有被正确销毁,或者存在一些指向已销毁刚体的悬空引用时,box2d 在大多数情况下会崩溃或卡住。所以我刚试了一下,在你的代码中,在 step 函数之后移除这条语句 PhysicsWorld.getInstance().removeBodiesAndFixtures();,然后,哇,它奏效了。顺便说一句,游戏做得很棒。当然,这不是解决方案,但可能会给你一个线索,让你知道从何处着手查找根本原因。

英文:

Okay, I bite for it. In my experience box2d crashes or hangs most of the time when bodies or fixtures are not correctly destroyed, or when there are some dangling references to destroyed bodies. So I just tried to remove this statement form your code PhysicsWorld.getInstance().removeBodiesAndFixtures(); right after the step function, and voila, it works. Nice game btw. This is of course not the solution, but it might give you a hint where to search for the root cause.

huangapple
  • 本文由 发表于 2020年9月10日 23:08:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63832601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定