2

I'm making my first game with SpriteKit in which enemies come on screen from one side and pass through- going off screen on the other side. I noticed that later on in the game when different types of enemies are being rendered the FPS drops and the CPU usage approaches 100% (~95-99%). I wanted to know if there was a way to get the exact node count on scene (Not just ones rendered on screen), to tell if I wasn't properly removing them. I already have a global node counter that I update and it seems to work properly-- the total node count is generally consistent. Are there other things that I can do to try and debug this? Thanks!

muZero
  • 948
  • 9
  • 22
  • Write a recursive function, starting at scene, that counts the children. Also override deinit, and add a print statement there. That will tell you if nodes are dieing. – Knight0fDragon Sep 01 '16 at 19:36
  • @Knight0fDragon Do you think the possible failure to remove these nodes would cause such a high CPU usage? As far as the recursive function do you mean something like this? `enumerateChildNodesWithName("//.") { (node, _) -> Void in print("Node: \(node.name)") }` – muZero Sep 01 '16 at 19:41
  • Yes, not removing nodes is a problem – Knight0fDragon Sep 01 '16 at 20:19

3 Answers3

6

You can also create an extension of SKNode to calculate all the nodes in the subtree starting from the current node.

extension SKNode {
    func subtreeCount() -> Int {
        return children.reduce(1) { $0 + $1.subtreeCount() }
    }
}

Now inside your scene simply write

let totalNodes = subtreeCount()
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
2

Something like this:

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
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • self.children.count, where self is a scene, will return the number of all nodes in node tree (if I recall correctly). If this somehow doesn't work(and it returns only immediate children), there is a way to use enumerateChildNodeWithName method and a specific search string to return the number of all nodes in a node tree. So doing this by the hand is not needed ;) – Whirlwind Sep 01 '16 at 20:51
  • @Whirlwind `enumaerateChildNodeWithName` would get you all the nodes, but how would you get a count for it, you would have to go through the entire list and increment I guess – Knight0fDragon Sep 01 '16 at 21:35
  • @Whirlwind `self.children` is an `[SKNode]` so count would only provide immediate children (I use this all the time so I was able to verify) I wonder if `//*` is smart enough to ignore string searches and just grab all nodes, would be interesting to find out which method is faster – Knight0fDragon Sep 01 '16 at 21:42
  • @knight0fDragon I don't believe that it is a build up of nodes thats causing the high CPU usage after counting the nodes. I posted an update with the time profiler if you think that provides any additional insight. – muZero Sep 02 '16 at 16:27
  • This is not about solving your problem, this is about answering your question – Knight0fDragon Sep 02 '16 at 16:30
  • @knight0fDragon I got it, I'll post a separate one. Thanks. – muZero Sep 02 '16 at 16:52
1

Debugging performance issues with games requires a bit of strategy in order to determine where you are bound. Just out of curiosity, are you basing your statements off of the simulator or on a device? If simulator, just be aware that you can actually get some woeful FPS and CPU usage even though your node count isn't particularly high. So when doing looking at performance, you really should be on the device.

You already have some answers regarding getting the node count, so I am not going to answer that part. Depending on how you are managing your nodes, you also may need to factor in hidden nodes. The current approach those that have answers deals with all nodes; visible or not (I am aware part of the q was related to counting all the nodes). If you are utilizing hidden nodes, then you should have at least 2 metrics related to nodes: visible and total. Another breakdown that can be helpful are node "types" as well as what textures nodes are using.

Further looking into performance issues, you would want to then focus on running instruments. In particular Time Profiler and OpenGL ES Analysis. You could also use the GPU Report in Xcode. When running the Time Profiler, I would let the game run for a few seconds on when you think the CPU usage has gone up. This is to allow for more sample points to more easily hone in on the offending areas.

Attacking frame rate can be highly dependent on how you have built and are running the game. For example, using individual textures versus atlases, the size of textures, etc. These types of design decisions do affect performance.

Keep in mind there is no silver bullet for solving these performance issues. Each game is different in how it is implemented, so a solution/approach for you may not be appropriate for another game.

If you're still stuck, it's always helpful to build in some mechanism to disable items or to use a more simplified version of them. This way you can turn items off and see the net effect on frame rate.

Mobile Ben
  • 7,121
  • 1
  • 27
  • 43