I need to create a cgpath continuously. At the moment I do it like that:
func createLine(){
var rand = randomBetweenNumbers(1, 2)
currentY--
The key to maintaining a high FPS count while drawing a progressively increasing number of lines is to quickly reach a state where adding more lines to the scene has little or no effect on frame rate. There are at least two ways to accomplish this.
The most straightforward of the two is to periodically convert the previously drawn lines to an SKTexture
and display the results as texture of an SKSpriteNode
. Here are the steps:
SKNode
to be used as a line containerSKSpriteNode
that will be used as a line canvasSKShapeNode
to be used to draw new linespath
property of the shape nodeSKTexture
. Note that since the canvas is also a child of the container, its contents will also be added to the textureHere's an example implementation in Swift that draws an endless set of lines at 60 FPS on an iPhone 6 device (you should test performance on a device not with the simulator):
class GameScene: SKScene {
// 1. Create container to hold new and old lines
var lineContainer = SKNode()
// 2. Create canvas
var lineCanvas:SKSpriteNode?
// 3. Create shape to draw new lines
var lineNode = SKShapeNode()
var lastDrawTime:Int64 = 0
var lineCount = 0
var timeScan:Int64 = 0
var path = CGPathCreateMutable()
var lastPoint = CGPointZero
override func didMoveToView(view:SKView) {
scaleMode = .ResizeFill
// 4. Add the container to the scene and the canvas to the container
addChild(lineContainer)
lineCanvas = SKSpriteNode(color:SKColor.clearColor(),size:view.frame.size)
lineCanvas!.anchorPoint = CGPointZero
lineCanvas!.position = CGPointZero
lineContainer.addChild(lineCanvas!)
lastPoint = CGPointMake(view.frame.size.width/2.0, view.frame.size.height/2.0)
}
// Returns a random value in the specified range
func randomInRange(minValue:CGFloat, maxValue:CGFloat) -> CGFloat {
let r = CGFloat(Double(arc4random_uniform(UInt32.max))/Double(UInt32.max))
return (maxValue-minValue) * r + minValue
}
func drawLine() {
if (CGPathIsEmpty(path)) {
// Create a new line that starts where the previous line ended
CGPathMoveToPoint(path, nil, lastPoint.x, lastPoint.y)
lineNode.path = nil
lineNode.lineWidth = 1.0
lineNode.strokeColor = SKColor.blueColor()
lineNode.zPosition = 100
lineContainer.addChild(lineNode)
}
// Add a random line segment
let x = randomInRange(size.width*0.1, maxValue: size.width*0.9)
let y = randomInRange(size.height*0.1, maxValue: size.height*0.9)
CGPathAddLineToPoint(path, nil, x, y)
lineNode.path = path
// Save the current point so we can connect the next line to the end of the last line
lastPoint = CGPointMake(x, y)
}
override func update(currentTime: CFTimeInterval) {
let lineDrawTime = timeScan / 10
// 5. Draw a new line every 10 updates. Increment line count
if (lineDrawTime != lastDrawTime) {
drawLine()
++lineCount
}
// 6. and 7. Add all newly and previously drawn lines to the canvas
if (lineCount == 8) {
addLinesToTexture()
lineCount = 0
}
lastDrawTime = lineDrawTime
++timeScan
}
func addLinesToTexture () {
// Convert the contents of the line container to an SKTexture
let texture = self.view!.textureFromNode(lineContainer)
// Display the texture
lineCanvas!.texture = texture
// Start a new line
lineNode.removeFromParent()
path = CGPathCreateMutable()
}
}