在Swift/SpriteKit中获取准确的节点数和性能问题

在Swift/SpriteKit中获取准确的节点数和性能问题,swift,sprite-kit,frame-rate,Swift,Sprite Kit,Frame Rate,我正在用SpriteKit制作我的第一个游戏,游戏中敌人从一边出现在屏幕上,从另一边穿过屏幕。我注意到在游戏后期,当不同类型的敌人被渲染时,FPS会下降,CPU使用率接近100%(95-99%)。我想知道是否有办法获得场景中的确切节点数(不仅仅是屏幕上渲染的节点数),以判断我是否没有正确删除它们。我已经有了一个更新的全局节点计数器,它似乎工作正常——总节点数通常是一致的。我还可以做其他事情来尝试和调试它吗?谢谢 类似这样: func childrenCount(node : SKNode) -&

我正在用SpriteKit制作我的第一个游戏,游戏中敌人从一边出现在屏幕上,从另一边穿过屏幕。我注意到在游戏后期,当不同类型的敌人被渲染时,FPS会下降,CPU使用率接近100%(95-99%)。我想知道是否有办法获得场景中的确切节点数(不仅仅是屏幕上渲染的节点数),以判断我是否没有正确删除它们。我已经有了一个更新的全局节点计数器,它似乎工作正常——总节点数通常是一致的。我还可以做其他事情来尝试和调试它吗?谢谢

类似这样:

func childrenCount(node : SKNode) -> Int
{
    var count = 0
    for child in node.children
    {
        count += childrenCount(child)
    }
    count += node.children.count
    return count
}

print("Nodes: \(childrenCount(scene) + 1)")  //+ 1 to count scene

您还可以创建
SKNode
的扩展,以计算子树中从当前节点开始的所有节点

extension SKNode {
    func subtreeCount() -> Int {
        return children.reduce(1) { $0 + $1.subtreeCount() }
    }
}
现在在你的场景中简单地写下

let totalNodes = subtreeCount()

调试游戏的性能问题需要一点策略来确定您的目标。出于好奇,你是基于模拟器还是基于设备?如果使用模拟器,请注意,即使您的节点数不是特别高,您实际上也会得到一些糟糕的FPS和CPU使用率。因此,在查看性能时,您确实应该在设备上

关于获取节点计数,您已经有了一些答案,因此我不打算回答这一部分。根据管理节点的方式,可能还需要考虑隐藏节点。当前的方法是那些有答案的方法处理所有节点;是否可见(我知道q的一部分与计算所有节点有关)。如果您使用的是隐藏节点,那么您应该至少有两个与节点相关的指标:可见和总计。另一个有用的细分是节点“类型”以及节点使用的纹理

进一步研究性能问题,您可能希望将重点放在运行仪器上。特别是时间分析器和OpenGL ES分析。您还可以在Xcode中使用GPU报告。当运行时间分析器时,我会让游戏在你认为CPU使用率上升时运行几秒钟。这是为了让更多的样本点更容易磨练出问题区域

攻击帧速率在很大程度上取决于你如何构建和运行游戏。例如,使用单个纹理与地图集、纹理大小等。这些类型的设计决策确实会影响性能

请记住,解决这些性能问题没有灵丹妙药。每个游戏的实现方式不同,因此您的解决方案/方法可能不适合另一个游戏


如果您仍然处于困境,那么构建一些机制来禁用项目或使用更简化的项目版本总是很有帮助的。通过这种方式,您可以关闭项目并查看对帧速率的净影响。

从场景开始编写一个递归函数,对子项进行计数。还要重写deinit,并在那里添加一个print语句。这将告诉您节点是否正在消亡。@Knight0fDragon您认为删除这些节点的可能失败会导致CPU使用率如此高吗?至于递归函数,你的意思是这样的吗
enumerateChildNodesWithName(“//”){(节点,\)->打印时无效(“节点:\(node.name)”)}
Yes,不删除节点是一个问题self.children.count,其中self是一个场景,将返回节点树中所有节点的数量(如果我调用正确)。如果这不起作用(并且只返回直接子节点),可以使用enumerateChildNodeWithName方法和特定的搜索字符串返回节点树中所有节点的数量。因此,不需要手动操作;)@Whirlwind
EnumBaverageChildNodeWithName
将获取所有节点,但如何获取其计数,您必须遍历整个列表并递增Iguess@Whirlwind
self.children
是一个
[SKNode]
所以count只提供直接的子项(我一直使用它,以便能够验证)我想知道
/*
是否足够聪明,可以忽略字符串搜索而只抓取所有节点,如果能找出哪个方法是正确的,我会很感兴趣faster@knight0fDragon我不认为是节点的累积导致了计算节点后CPU的高使用率。我发布了一个时间档案器的更新,如果你认为它提供了任何额外的见解。这不是关于解决你的问题,而是关于回答你的问题question@Knight0fDragon:谢谢,这基本上与你用函数式编程风格写的答案的逻辑相同。我喜欢这种方法,非常优雅。