【问题标题】:SpriteKit physics huge FPS drop on iOS 9iOS 9 上的 SpriteKit 物理 FPS 大幅下降
【发布时间】:2016-10-24 22:14:03
【问题描述】:

我在场景中遇到了巨大的 FPS 下降,其中一些静态 SKSpriteNode 节点的主体用SKPhysicsBody init(polygonFrom: CGPath) 定义,一些简单的动态SKSpriteNode 节点的主体用init(rectangleOf: CGSize) 定义。

动态节点在场景中被触发并最终休息,这取决于物理。每个动态节点都与其他动态节点以及前面提到的静态节点发生冲突。

游戏以 60fps 流畅运行,直到屏幕上的动态节点数量约为 30 或更多。之后,FPS 开始急剧下降到 10fps 左右。

注意 1:该问题在 iOS 10 上不存在,只有 iOS 9(我没有测试过 iOS 8,因为我不支持它)。

注意2:由于动态节点的增加,draw call并没有增加,所以在OpenGL端似乎没有问题。

注意 3:我禁用了 contactTestBitMask 以确保这不是问题的原因。

我用 Time Profiler 运行 Instruments,专注于 FPS 下降的部分,发现以下奇怪的事情:

奇怪的是,有问题的片段中超过 50% 的时间都花在了PhysicsKit。请注意,此时是否正在发生碰撞或动态节点是否只是静止不动并不重要。结果总是一样的。

这一定是它的原因,但由于所有这些都发生在系统库 (PhysicsKit) 中,我真的不知道在我的代码库中哪里寻找问题。

感谢您的帮助!

【问题讨论】:

  • 您尝试清理项目了吗? Shift-CMD-K
  • SpriteKit 版本之间一直存在非常奇怪的不一致。即使在次要版本之间。 Apple 从不发布更改或其他有用的发行说明。他们很少在自己的论坛上回复关于性能问题的长线程。我告诉你这个,所以你不认为这是一个完全的反常现象。有报告称最新的 SpriteKit 中存在内存错误和音频问题,这些问题本应被基本单元测试发现,并且自 iOS 10 早期测试版以来就已成为其一部分。 Sprite Kit 的用户并不多,Apple 也没有给予太多的关心或关注。
  • @Nik 是的,很多次。
  • 如果你想有办法将 Box2D 导入 SpriteKit。
  • @NSDawg 不确定我是否想这样做。

标签: ios sprite-kit game-physics skphysicsbody


【解决方案1】:

没有办法解决你的问题,因为 nateslager 已经提到了明显的问题,我只是告诉你一个解决方案。

您所做的是将场景分成具有某种重叠的象限或更多象限,并为这些象限保留categoryBitMasks,因为物理对象可以有多个 categoryBitMask。现在你需要每帧更新这些类别,所以我喜欢覆盖 position 属性并添加didSet 来告诉节点它们在哪个象限中。

现在这可能会变得非常复杂,具体取决于您使用这些标志的方式,因为您不能执行 quadrant4 和 bad 之类的操作,因为那样它仍然会记录所有好的和坏的。相反,您需要将 quadrant4bad 作为 1 个类别。这样做的目的是减少在所有机构之间进行的检查次数。

例如 我们有一个 (-5,-5) 到 (5,5) 的场景,大小为 (11,11)

象限1是(-5,0),(0,0),(-5,-5),(0,-5)
象限2是(0,0),(5,0),(0,-5),(5,-5)
quadrant3 是 (-5,5),(0,5),(-5,0),(0,0)
quadrant4 是 (5,0),(5,5),(0,0),(5,0)
象限C是(-2.5,2.5),(2.5,2.5),(-2.5,-2.5),(2.5,2.5)

enum PhysicsCategory : UInt
{
   case good = 0b1
   case quadrant1Bad = 0b10
   case quadrant2Bad = 0b100
   case quadrant3Bad = 0b1000
   case quadrant4Bad = 0b10000
   case quadrantCBad = 0b100000
}

//we set up a good player at position 0,0 so he is in the center quadrant
good.contactBitMask = quadrantC


//we set up a enemy  at position -5, -5 so he is in the first quadrant
bad1.contactBitMask = quadrant1

//we set up a enemy  at position 5, -5 so he is in the second quadrant
bad2.contactBitMask = quadrant2

//we set up a enemy  at position -5, 5 so he is in the third quadrant
bad3.contactBitMask = quadrant3

//we set up a enemy  at position 5, 5 so he is in the fourth quadrant
bad4.contactBitMask = quadrant4

//we set up a enemy  at position -2.5, 2.5 so he is in the third quadrant and center quadrant (remember, they have a width and height to them, so they will be in more than 1 quadrant
badC.contactBitMask = quadrant3 | quadrantC

现在当我们的游戏运行时,good 只会在他的象限中检查敌人,所以只会在 quadrantC 上进行检查

如果好的移动到象限3,那么只会进行2次检查,bad3和badC

这将帮助您减少物理后端的调用,从而减少延迟。

如果你碰巧有很多不同的类别正在使用,那么我建议不要使用多个位掩码,而是在敌人不在特定象限时关闭他们的 categoryBitMasks。这也将减少物理引擎完成的检查次数。

【讨论】:

  • 感谢您的回复。绝对是个好主意,但看看我的游戏,我不确定它是否会有所帮助,因为目标是让动态节点堆积在静态节点上的特定热点中。因此,我认为计算不会有太大帮助。作为最后的手段,我会试一试,然后告诉你。顺便说一句,我很快尝试在动态节点“休息”后关闭categoryBitMasks,但这似乎不会影响计算。
  • 如果你有静态节点,然后将你所有的物理体组合成一个体,并将其分配给一个父节点,你可以使用 contactPoint 找出被击中的节点
  • KnightOfDragon,如何将几个静态物理体合并为一个物理体?
  • @classenApps 它是physicsbody inits 之一
【解决方案2】:

即使你只有“几个”多边形物理体,每个额外的矩形物理体,无论它是否在移动,都需要在每一帧中计算出它与每个多边形物理体的距离(因此 b2Distance() 函数) .尝试降低多边形物理实体的复杂性/数量以提高帧速率。

我怀疑性能的突然下降与存储这些距离的缓存 (b2SimplexCache) 达到其最大容量(可能约为 30 个值)有关,此时缓存未命中会降低帧速率。 iOS 10 肯定增加了这个缓存。另一种解决方案是在 iOS 9 中以某种方式增加此功能的缓存,尽管我不确定如何。

【讨论】:

  • 感谢您的回答,但我无法进一步简化正文。无论哪种方式,它们对于静态节点都不是那么复杂。动态节点只有矩形体。
  • 您使用了多少个多边形物理体?它们是什么?
  • 我一次使用大约 4 个多边形物理体。它们应用于代表房屋的SKSpriteNode 节点。
  • 一次只有四个身体,肯定有某种错误影响你的表现。您能否增加 iOS 10 中测试项目中的主体数量,以查看它何时开始表现出相同的行为/问题? @damirstuhec
  • 我在 iOS 10 上使用 4 个多边形主体进行了测试,我需要至少 80 个带有简单矩形主体的节点才能开始看到帧下降。下降只是几帧,不像 iOS 9 那样大。
猜你喜欢
  • 1970-01-01
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
相关资源
最近更新 更多