I am aiming to have all these waves animate identically, for performance reasons. This will help by reducing the cost of calculating wave paths, and to reduce the draw count.
I have a scene in SpriteKit setup like so:
→ There is a link to an animating version here.
The scene is mainly composed of 2 things:
- Stones (the light and dark grey hexagons)
- Waves (there are 2 per stone - a lighter and a darker blue animating path)
The waves are create like so:
// Wave outline shape node
shapeNode = SKShapeNode(path: self.oldPath)
shapeNode.strokeColor = wave.color
shapeNode.lineWidth = 5
shapeNode.zPosition = waveIndex == 0 ? Layer.farWave : Layer.nearWave
shapeNode.lineJoin = .round
shapeNode.position = stoneCell.node.position.offset(by: stoneCell.offsetVector)
view.scene?.addChild(shapeNode)
// Layer which creates the animation
shapeLayer = CAShapeLayer()
shapeLayer.isHidden = true
view.layer.addSublayer(shapeLayer)
animate()
And the animate() function:
/// Animates the wave's path. This method calls itself forever.
private func animate() {
let newPath = WavePath(wave: wave, direction: currentDirection).createPath()
let anim = CABasicAnimation(keyPath: "path")
anim.duration = 2 // Duration of the wave movements in a direction (in or out)
anim.fromValue = oldPath
anim.toValue = newPath
anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
shapeLayer.path = newPath
shapeLayer.add(anim, forKey: nil)
shapeNode.run(SKAction.customAction(withDuration: anim.duration, actionBlock: { (node, timeDuration) in
(node as? SKShapeNode)?.path = self.shapeLayer.presentation()?.path
}), completion: {
self.oldPath = newPath
self.currentDirection.toggle()
self.animate()
})
}
The problems arise because there are 10 stones on the scene, which increases the performance cost. Is there a way to make this wave animation duplicated under all these stones?
Possible options I can think of:
Convert the paths into a texture, which could be shared between multiple stones? However I think this would be slow to convert to a texture twice (for each wave) per frame, and then copy it over...
Rendering a full animation pass of the wave going in and then out, and then putting that on a loop for every node. But how?
What other solutions may be better?
I do not want to create an atlas and animate it. I cannot do this because these stones and waves change in size, depending on the screen size and level and I want them pixel-perfect. I do not mind however (as mentioned in bullet point two) of storing textures of an animation loop and then repeating that.