3

I would like to optimize draw counts, but don't know where to start.

Can someone briefly explain ( or point me in the right direction ) which factors affect draws, is there a way to view/debug them and are there any optimization tips? What is the optimal count for draws?

For example, my game loads one texture atlas for whole ui, and uses children nodes as containers for different game menus ( instead of separate scenes). But draw count is 20+ for one screen, and fps drops by 10-15, which is a problem.

elektricni
  • 319
  • 1
  • 5
  • 12

2 Answers2

3

OK think in the realms of the game scene is made up of layers. Each zPosition gives reference to a node belonging to a layer. (The reason the property is called zPosition is because its the nodes position along the zAxis)

enter image description here

If you had a gameScene with 4 SKSpriteNodes and gave the nodes zPositions as shown above then the system interprets your intent to be like in the diagram above. When rendering the system will have a draw count of 4. In draw count 1, all nodes with zPosition 1 will be rendered. In draw count 2, all nodes with a zPosition of 2 will be rendered and so on. This is know as the Painters Algorithm. It's like a painter paints.

Now say in our game scene we want to add another SKSpriteNode to node 3. If we add it as a child to node 3 then this is where

var ignoresSiblingOrder: Bool { get set }

comes into play. If set to false then our new node would be rendered after the parent node3. so it would have a zPosition of say 3.5. Our draw count has now increased to 5. If set to true the system will ignore the child/parent relationship our draw count will drop to back to 4 again, but there is no guarantee what the system will render first. node 3 or our new Node. This is result is non-deterministic meaning it will not return the same results. Sometimes node3 will be rendered on top of its child node. Other times the child node will be rendered on top of the Parent node.

A final and really important point is that zPosition is only taken into account by the system when overlap occurs between two nodes.

A good way to optimise is to where possible make single textures. If there is no need to have separate nodes then don't! create a single texture and use that.

This is Key and probably the most important point. If possible avoid node overlap. zPosition is only taken into account during node overlay. If you have 1000 nodes all with different zPositions, but none of them overlap guess what.... you have a draw count of 1.

If node overlay can't be avoided and mostly it can't in some instances. Set ignoreSiblingOrder to true. (You don't really need to do this but it makes things simpler and allows you to specify the draw cycles) Ensure you set zPositions for all nodes. But KEY remember each time you create a new zPosition you are increasing you draw count by 1 as long as that node intersects with another.

Hope this helps

hoboBob
  • 832
  • 1
  • 17
  • 37
  • Wait, so if `ignoresSiblingOrder` is `true` and zPositions are set, draw count would be low, but the disadvantage is the order of rendering? If a game has 1 layer and numerous nodes with different zPos, draw count will still be 1? – elektricni Dec 02 '19 at 13:43
  • No ignoreSigblingOrder never overrides a set zPosition. The draw count would just be the number of different zPositions you have. ignoreSigblingOrder only effects the child/parent relationship of rendering – hoboBob Dec 02 '19 at 14:02
  • You mean, if i have 100 nodes, each having it's own zPosition ( 0..<100 ), and add them all to the same scene, there will be 100 draws? – elektricni Dec 02 '19 at 14:25
  • YES !!!!! I can't say it in any other way...... Node zPosition impacts draw call count because, generally, nodes at different zPositions must be rendered on a subsequent pass. For example, nodes that overlap each other must be done in separate draw calls. Overlapping nodes at the same zPosition can be rendered in the same draw call if you enable the SKView ignoresSiblingOrder property. https://developer.apple.com/documentation/spritekit/sknode/about_node_drawing_order – hoboBob Dec 02 '19 at 14:34
  • Great, thanks. But, what if i want to have 1 draw count for all 100 nodes, and at the same time, have a way to differentiate them on z-axis? Is that even possible? – elektricni Dec 02 '19 at 14:51
  • @elektricni I don't see a case where you would need 100 nodes all overlapping each other like that. – George Dec 02 '19 at 17:13
  • @George_E Just an example mate :) . Guess I'll have to reduce number of layers and zPositions as much as possible. – elektricni Dec 02 '19 at 17:30
  • @elektricni Hi bud, I think I get why you asked you last question. I updated the answer and it might explain why if you are testing and only getting low draw count rates. Any way man. If you appreciate the the help add a good answer mark. peace – hoboBob Dec 03 '19 at 00:11
  • 1
    I've already marked Georges answer, because it helped me and it was first. But you also helped me, so i upvoted yours answer. – elektricni Dec 03 '19 at 00:42
2

Draw counts are the result of needing to layer a scene in the right order, and some nodes can be dependent on the content behind it if they have some transparency for example.

1: One of the biggest ways to reduce the draw count is to render multiple nodes at once - this can be achieved by adding child nodes you want in the same layer to a parent node. For example, have a parent node called nodeCollection and use addChild() to add multiple nodes to be rendered together to lower the performance hit.

2: Another thing you can do is set ignoresSiblingOrder to true on SKView, and use zPosition on each node instead - this means that SpriteKit has to do less work as you are more explicit.

3: Don't use SpriteKit for UI! This is what UIKit is for! You have your SKView which holds your SKScene. SKView is a subclass of UIView, which means that you have it placed in one of your view controllers. All you need to do is add move views or buttons or whatever you want in your view controller on top of your SKView, and you're set!

For more optimisations I recommend checking out: Hacking with Swift - 15 tips to optimize your SpriteKit game.

George
  • 25,988
  • 10
  • 79
  • 133
  • Are you sure about point 1? If you add a node which has multiple nodes attached, each with different zPosition values then the draw count would not be reduced. Maybe worse even when considered cost (only marginally...but still) – hoboBob Dec 02 '19 at 00:30
  • Adding on Georges points I'd say the single most important thing is to look at what you are doing and think do I really need to have a different zPosition there. If the answer if yes then so be it. If not get rid of it. The draw count is based on the number of different zPositions you have. The compiler os smart enough not to use unreferenced zPositions so if you have 2 nodes. node 1 at zPosition 1 and node 2 at zPosition 100 you still only have 2 draw counts. – hoboBob Dec 02 '19 at 00:52
  • ignoresSiblingOrder was set to true. But now i'm confused. Does zPosition affects draws, or parent/child relationship, or both? Should i use delegates to pass nodes to 1 node and use addChild() there, or try to reduce zPos if possible, or both? – elektricni Dec 02 '19 at 11:00
  • @elektricni [ignoresSiblingOrder](https://developer.apple.com/documentation/spritekit/skview/1520215-ignoressiblingorder) is when the position and hierarchy of the node determines the rendering order. This can be quite expensive if you have a large node tree. Only use `zPosition` when `ignoresSiblingOrder = true`. `zPosition` only puts a node on the right rendering layer, but does not reduce the draw calls. Draw calls are reduced when you have fewer nodes in the scene (this is why you can add multiple nodes to a parent node, so SpriteKit knows they are all to be rendered together). – George Dec 02 '19 at 11:51
  • @hoboBob I would say just don't set the `zPosition` for nodes to all be a child of a parent node. I'm not sure on the performance about this, but the parent node should represent a whole layer (for example having 64 nodes as parent of a chest board grid does not need a `zPosition`). – George Dec 02 '19 at 11:54