swift - SpriteKit游戏中的高CPU和帧速率下降

标签 swift xcode sprite-kit instruments

我正在制作我的第一个游戏与精灵在其中的敌人从屏幕上的一方,并离开屏幕上的另一方。我注意到在游戏后期,当不同类型的敌人被渲染时,fps下降,cpu使用率接近100%(95-99%)。我使用了两种仪器调试工具,结果如下:
在时间分析器工具中,我发现了main的问题,我认为它是appDelegate的主体。我知道这看起来很明显,但我惊讶地发现update中的GameScene函数几乎不是问题所在。有没有办法深入研究这个问题?如果这是我的一个功能导致的问题,我觉得似乎它会更容易评估我在哪里搞砸了。
enter image description here
我还使用了allocations工具,发现大量使用内存将构建新的外星精灵:
enter image description here
这是我添加普通外星人的代码:

func addNormAlien(){

    let mult = normAlienMultiplers

    let alienInst = normAlien(startPos:CGPoint(x: 10,y: 10), speed: random(UInt32(10),max: UInt32(50))*mult[0])

    let yStart = random(UInt32(alienInst.size.height/2), max: UInt32(size.height-alienInst.size.height))
    alienInst.position = CGPoint(x:size.width+alienInst.size.width/2, y:CGFloat(yStart))

    addChild(alienInst)
    totalNodes+=1
}

这是不是有点期待,因为它是昂贵的不断实例化新的精灵(即使我很少超过20一次)?我这样做只是为了确保它们的随机传播。
我也找不到很多关于纹理大小的东西——有没有一个惯例可以使用?目前,我发现自己制作的sprite纹理相当大,然后使用setScale缩小它们,而不是在图像编辑器中这样做。
这些纹理和动画也正在(预加载?)在我的GameScene文件的开头
let laserTexture = SKTextureAtlas(named:"Sprites").textureNamed("laserTexture")`


let shipFrames = ["ship0","ship1","ship2","ship3","ship4","ship5","ship6","ship7","ship8","ship9","ship9","ship9","ship8","ship7","ship6","ship5","ship4","ship3","ship2","ship1","ship0"].map{textureAtlas.textureNamed($0)}`

之前:class GameScene: SKScene, SKPhysicsContactDelegate {
因此,可以从我的sprite类中使用以下行进行访问:
    super.init(texture: shipStartTexture, color: UIColor.clearColor(), size: shipStartTexture.size())


func animateShip1() {
    let animate = SKAction.animateWithTextures(shipFrames, timePerFrame: 0.1)
    let forever = SKAction.repeatActionForever(animate)
    self.runAction(forever)
}

如果有更好的方法预先分配纹理,我很想知道,任何进一步的见解,我可以如何评估这些其他问题将是可怕的!

最佳答案

一般来说,您会发现main包含最高的cpu使用率,因为通常大多数事情都是从主线程运行的。你需要深入调查才能找到真正的罪犯,你已经做到了。记住,这都是相对于你使用的仪器运行完成的。所以如果你没有足够的数据点,你可以得到红鲱鱼。一个例子就是游戏加载。这可能是一个昂贵的手术。在某些情况下,它看起来比较快(比如加载1-5秒),但是当您查看您的配置文件时,您可能会发现它占用了大量时间。但是,如果在运行时发现fps很高,那么加载的开销是值得的。
在你的场景中,一个问题是你运行了多久?另一个问题是addnormalien的实际调用频率是多少?是每帧吗?你的addnormalien有两个部分正在消耗时间,这是创建和添加到层次结构中的时间。在不知道苹果是如何实现这些项目的情况下,它们实际上有点像黑匣子,但很明显,有些方面的创新是昂贵的。再说一次,不知道你的游戏的时间特性会让你很难完全放下。回到我之前提到的,如果所有这些工作都是在装载过程中完成的,那么这些数字就可能是个危险的数字。因此,您需要确保您的测试运行具有足够的游戏会话代表性。
一个建议是创建已经构建的外星人节点的现有池。然后在需要的时候从池中提取一个对象(顺便说一句,可能还应该包含normalien方法)。顺便问一句,有多少游戏能做到。它们基于使用加载时间来招致对象创建的“惩罚”的前提,创建在运行时将需要的项的预分配版本,从而使运行时相对不受该开销的影响。但请注意,这有一个诀窍。从池中提取空闲对象时,需要进行一些最小的初始化。以前,您可能依赖于构造函数/初始值设定项。但由于这是一个已经创建的对象,您将不会有这种奢侈(请记住,您在运行时试图消除不必要的开销)。这意味着您确实需要对此保持警惕,因为它可能会创建一些难以跟踪的错误。
另一件事,我在另一篇帖子中提到过,你应该禁用一些东西。例如,有一个runaction发生在副本看起来很昂贵的地方。
关于纹理大小。有多大?总的来说,这是个坏主意。你这样做会招致惩罚。但是,根据大小、缩放位置等,开销可以忽略不计。一个简单的测试是运行一个纹理大小与大纹理大小相对应的版本。如果你总是按比例缩小,就没有理由使用大的。
不管怎样,这里有很多事情要研究,这就是为什么游戏性能调整会很棘手,以及为什么一个游戏的方法可能不适用于另一个游戏。只有你知道你是如何建造的。
添加了基于信息的问题更新。
关于你的问题的更新。在我看来,你正在扩大范围,现在无关的项目(预加载纹理),也在寻找一个银弹或一站式的答案,你所有的不幸。没有。如前所述,补救这些类型的事情可能是棘手的和高度依赖游戏。只有你知道你的游戏,只有你能在乐器中运行它。有一种策略可以使用。这主要是因为经验和一些问题(例如,为什么初始化要花这么长时间?)。如果这会引出更多这样的问题,那么就打断这个问题。
关于预加载纹理,您需要为此创建一个新问题。想想你在很多游戏中看到的加载屏幕。为什么你认为它们存在?加载背景中的内容,如纹理和其他数据。是的,它增加了DEV的复杂性,但是需要为用户提供更好的体验。预加载通过preload完成。您在代码片段中引用的只是数据的初始化,稍后可用于引用纹理实例。
我建议您做的是找到隔离代码部分的方法,以确定您的性能影响来自何处。例如,您已经检查了节点计数。20不是很大。pi会很惊讶动态创建它们会有这样的开销,但是您的时间配置确实表明可能有一些显著的开销。如果init开销确实很大,你可以通过简单地让你的游戏在每一帧分配新的外星人来衡量它。您应该能够运行几秒钟而不会耗尽内存。然后,您可以使用它开始删除部分代码,以查看这如何影响性能。你应该在这里看到,很多事情都是反复试验的。没有银弹/设置答案,它需要一定的心态,以善于优化。
我在你的另一个问题中提到过,但是如果你在模拟器上这样做的话,这不是优化性能的正确方法。必须在设备上完成。

关于swift - SpriteKit游戏中的高CPU和帧速率下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39297415/

相关文章:

swift - 如何加载单例类属性?

ios - Swift 中如何计算坐标

iOS FIRAuth : Is there any way to get user email from user uid?

ios - Swift 4 insertTimeRange 添加视频轨道但播放时除了第一个不显示

ios - 你如何在 Swift 中风格化字体?

Swift 嵌套的非可选结构给出了可选的

objective-c - 如何在 x86_64 Swift 项目中使用 i386 框架

ios - 如何获得移动的 SKSpriteNode 的位置?

javascript - 你能告诉我我做错了什么吗?

ios - 如何使用 Swift 的 prepareForSegue 函数指定要准备的 View Controller ?