2D物理游戏性能问题(在Android中使用libgdx box2d)

4
我正在制作一个2D汽车游戏,就像“赚钱驾到2”一样。我已经快完成了它。唯一的问题是物理引擎的性能。我正在使用box2d,共有10米长的边状形组成一个100公里的地形。有1辆汽车和通常有30-40个方块。活动的动态物体数量大约为60-100,最多为120。游戏在桌面上流畅运行,但在android上,当活跃物体超过60个时,帧速率会下降到30以下。汽车与箱子之间、箱子与箱子之间以及箱子和车与地面之间都会发生碰撞。
我使用的是libgdx框架1.9.4版本,java是1.7,在eclipse neon和windows 7中进行编码。
这是我如何在世界中计算活动物体的方法。
    int num=0;
    Array<Body> bodies=new Array<>();
    world.getBodies(bodies);
    for(Body b:bodies){
        if(b.isActive())num++;
    }

活动的动态物体通常在100个左右。

这不是所有地形和地下网格、汽车和盒子的绘图问题,成本为6-7毫秒,当box2d调试渲染关闭时我测量了它们,而且当有大约30个盒子时,世界步骤方法调用成本约为30毫秒,而汽车正在撞入它们。

我不加载所有游戏对象(现在只有盒子),我将整个地图分成块,地图大小为100公里,块大小为50米,当汽车在下一个50米范围内(在块范围内)时,我从一个准备好的池中加载盒子(这些对象的box2d世界表示也被池化,当盒子在池中时,我使用setActive(false)来停用它们的box2d body,在加载块时再重新激活)。

我也为地形应用了这个块系统。我在游戏加载时加载所有地形,然后通过使用该方法setActive(false)来停用它们,当汽车穿过地图时,如果块范围包括汽车的x轴坐标,则激活下一个块,其中包含静态物体,其大小约为20个装置,使块大小总共为200米。

这里是地图的一部分的截图,以可视化我的性能优化计划:)

绿色线条是活动地形形状,如您所见,在距离左右一段距离后被停用,直到地图结束,这部分来自100公里地形地图中的60公里左右。

当车辆移动更多时,新的盒子将在前方加载,如果它们与汽车相隔20米,则旧的盒子将被池化。

我的问题是

1)这个fps(20 fps)正常并且可以预期吗?(安卓7,这是手机规格http://www.androidpolice.com/2016/02/23/the-general-mobile-gm-5-plus-is-the-most-powerful-android-one-device-yet/

2)如果100公里的地形会有问题,那么我该如何管理它?

->我尝试激活/停用屏幕矩形外的地形物体。

->我尝试在单个物体上使用数百个装置,或者每个地形块都是单独的物体,但最好的性能是将100公里的地形分成200米的块,每个块是一个物体,包含约20个装置。

3)模拟带有巨大边缘形状的100个动态物体完全不可能吗?(但在赚钱之旅中他们做到了)

4)我应该为这种游戏(一个简单的特定游戏)编写自己的简单物理引擎吗?

5) 对于2D目的,我应该使用Bullet Physics而不是Box2d吗?这可行吗?我会遇到性能问题吗?

如果需要任何代码,请在评论中提出,我会添加。

是否有一些真正快速的物理引擎,我在网上找不到,如果有,您建议改用Box2D吗?

值得注意的是:

我正在以恒定时间步长模拟Box2d,我尝试了1/60, 1/45, 1/30和8-3,6-2作为迭代步骤。

我对所有物体使用高阻尼值,如.9的线性和角度阻尼。

我也想将那些盒子分裂成碎片,实际上我正在这样做,但当汽车被压坏时,我经历了这种fps下降,所以现在我将其禁用。

只有关节是车轮关节,仅用于车轮,在地图的任何其他地方都没有关节。

大小比较真实,这些盒子高1.2米。

对于盒子和汽车,使用多边形形状,对于地形,使用边缘形状(链条形状)。

速度阈值在世界设置中默认为1。

如果有我忘记的任何注释,请在评论中提出,我会分享。

谢谢。

1个回答

1

免责声明:我不能回答你所有的问题,以下只是我的猜测。

几年前,我用Java + box2d + plain Opengl (LWJGL)开发了一个游戏原型和游戏库。

我想你正在面临一些我曾经遇到过的问题。

然而,由于我的经验有限,我可能会错。
如果专家(读者)认为我的帖子中有任何错误,请在下面评论,我会修正它。

我的猜测

Java速度慢/不太适合游戏。

免责声明:这方面存在很多争议。
我没有足够的专业知识来做出坚定的陈述,但我看到我的许多游戏原型在C++中运行3倍到10倍的速度比Java快。(使用差异不大的算法)

内存碎片化

你可能已经知道,即使使用池,与C ++相比仍然非常差劲。
你可以池化盒子,但不能池化所有东西,例如游戏逻辑数据结构、vector2D、普通数组(经常是new[]),以及你使用的某些库中的一些恐怖算法。

停用的物体仍然会消耗内存(间接增加内存碎片化)。

你有大量静态物体/静态物体复杂度很高。

你没有提到你有多少静态物体,以及它们是什么。
你是否为地形使用了高数量的顶点形状?
像Box2D和Bullet这样的流行物理引擎在凸形状方面表现出色,并且在原始形状方面专业,但在凹形状方面(例如你的地形)往往表现不佳。

你的形状正在持续相互碰撞。

例如,100个盒子的堆栈比场景中散落的100个盒子需要更多的计算。

世界太大了

据我所知,box2d将场景(世界)划分为网格。如果你的世界非常大,但许多物体聚集在网格的同一单元格中,Box2D的效果会相对较差。这不仅限于Box2D。Bullet和Ogre3D在某些配置下也会遇到这个问题。
答案(再猜一次)
1) 这个fps(20 fps)正常并符合预期吗?
我不知道移动端的情况,但你的代码仍然可以通过某些方式进行优化。(见下文)
2) 如果100公里的地形成为问题,我该如何处理?
不专注的区块 -> 删除身体(不仅仅是停用它)。
是的,这比做起来难,你可能只是停用附近的区块,但删除(删除)所有远离的区块中的身体(> 3个区块距离,可能是)。如果已删除的区块可以回到场景中,您可能需要找到一种保存它的方法。 (例如,仅保存身体位置、大小、重量)

3) 模拟100个动态物体和巨大的边缘形状地形是完全不可能的吗?(但在“赚钱之旅”中他们做到了)

他们做到了,还是你只是认为他们做到了?
在某些方面,编程是一门艺术。
你看到的东西可能与实际实现方式非常不同。
你的瓶颈可能只是地形-减少其细节级别也可能有所帮助。

4) 对于这种简单特定类型的游戏,我应该自己编写简单的物理引擎吗?

不需要,除非你想学习并且有很多时间并且真的喜欢数学。

5) 对于2D目的,我应该使用bullet物理引擎而不是box2d吗?这是可能的吗?我会遇到性能问题吗?

我认为你仍然会在某种程度上面临问题。
约束对于Box2D和Bullet都很昂贵。
你确定你真的需要约束吗?
在某些情况下,可以通过复合形状/修改游戏设计来避免它。

我认为如果你改用C++和Bullet,性能至少会提高3倍,但我并不确定


很晚的反馈 :( 我有其他项目要处理...现在它的性能好多了,在移动设备上稳定达到60帧。它从20-30提高到60,经历了两个重大步骤。一个与主题无关,我的字体与按钮纹理分开存储,所以纹理切换会影响性能。此外,删除和重新创建物体而不是激活/停用它们也产生了重要的影响。另一个重要的提示:不要经常调用Java本地接口,这也会影响性能。(在我的情况下,box2d是本地的,我通过jni访问它)我接受了答案。谢谢你的帮助。 - ömer.bozkurt
你可以编辑你的回答,更清楚地说明解决巨大地形问题如何提高性能。还有一点需要注意的是:我认为问题的根本原因是box2d数据结构。它无法快速处理10万个元素。当你保持世界狭窄时,它的管理速度会快得多。因此,在需要时创建和删除物体可以作为box2d手册的一个必须使用的亮点句子添加进去。现在这个游戏比它的C++版本性能更好,所以Java仍然适合游戏开发...继续爱着Java... - ömer.bozkurt
1
@mücahid 感谢你的反馈和宝贵意见。你发现 Java 比 C++ 更快是一个非常有趣的结果。你对此有多大的把握?这与我的经验相矛盾。在使用 C++ 时,你是否启用了优化(例如 -O2)?当进行基准测试时,你使用了多少个物体?你的游戏最多可以支持多少个物体(60fps)?我以前从未使用过“Java Native Interface”。你可以分享很多东西。你甚至可以将其作为另一个答案发布。这将对读者(至少对我来说,我会点赞)非常有用。XD - javaLover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接