I'm building an app that provides an editable canvas similarly to photoshop or illustrator (currently using SpriteKit
). I'm encountering some performance issues when displaying a large number of nodes (1000+) as you might imagine.
Currently, I've got an SKScene
with SKShapeNodes
on it. They presently do not have any images and are simply filled with a color. Their shape paths (CGPath
s) vary from circles, to bezier paths. Each shape currently has an SKPhysicsBody
with the same path as the rendered shape that is used to detect taps.
The performance issues can be described by:
Disabling PhysicsBodies doesn't substantially improve performance, but does improve CPU load (jumps from constant 60% to 1% or so)
Most users will not be working with 1000 nodes, but I'd like to implement the optimal solution.
What I'd like is two have two layers:
CGPath
s with strokes and fills (preferably choosing the stroke end cap style among other little things) CGPath
s and stroke CGPath's with a color to indicate highlighting.How can I accomplish this or a similar solution that will improve the speed at which I can render 1000 circles?
Don't use SKShapeNode, it needs 1 draw call per shapenode. You can create a shape, then "cast" it to a SpriteNode before adding it to the scene:
func shapeToSprite(_ shape: SKShapeNode) -> SKSpriteNode {
let sprite = SKSpriteNode(texture: SKView().texture(from: shape))
sprite.physicsBody = shape.physicsBody // Or create a new PB from alpha mask (may be slower, IDK)
shape.physicsBody = nil
return sprite
}
override func didMove(to view: SKView) {
let shape = SKShapeNode(circleOfRadius: 60)
addChild(shapeToSprite(shape))
}
This would suck though if you needed to constantly edit the size / shape of your shape in a way that isn't doable via scaling or SKWarpGeometry
To detect taps like this, you just need to either 1, Set a name for the SpriteNode then look for it in touchesBegan, or 2, subclass a SpriteNode and override it's touchesBegan.
Also, if you need to just have a static image, you can bit-blit thousands of nodes onto 1 texture. Sprite Kit: A Lot of sprites (1000+) with Bit Blitting
So if you don't need every node to be touchable at all times, you can alternate between having physicsBodys and not, or switch layers from bitblitted to active.