创建无限的 CGPath 路径而不掉帧

8
我需要不断地创建一个cgpath对象。目前我是这样做的:
 func createLine(){
        var rand = randomBetweenNumbers(1, 2)
        currentY--
        if rand < 1.5{
            currentX--
            CGPathAddLineToPoint(leftPath, nil, currentX, currentY)
        }else{
            currentX++
            CGPathAddLineToPoint(leftPath, nil, currentX, currentY)
        }
        CGPathAddLineToPoint(rightPath, nil, currentX+tileSize, currentY)
        lineNode.path = leftPath
        rightNode.path = rightPath

}

然后像这样调用它:

NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: Selector("startTile"), userInfo: nil, repeats: true)

但问题是,随着时间的推移,帧速率逐渐降低。我需要做出哪些改变才能使帧速率不再下降?
我的目标是创建一个无限随机路径。

我猜你需要删除路径中的旧部分。否则,你最终会拥有越来越多的路径段。或者,为什么不在到达当前路径的末尾时每次创建一个新路径呢? - sangony
我实际上无法创建一个新路径,因为我需要它是无尽的,或者至少对玩家来说看不到新路径。 - Christian
2
这应该有助于行缓存 - 0x141E
你可以将路径点放入一个数组中,只绘制实际可见的屏幕内容。顺便提一下,你可能更喜欢使用CADisplayLink而不是NSTimer,因为它与显示刷新同步触发。 - Matteo Piombo
1个回答

4
保持高FPS数的关键是,在不断增加线条数量时迅速达到状态,使向场景中添加更多线条对帧率几乎没有影响。至少有两种方法可以实现这一点。
其中最简单的方法是定期将先前绘制的线条转换为SKTexture,并将结果显示为SKSpriteNode的纹理。具体步骤如下:
  1. 创建一个用作线条容器的SKNode
  2. 创建一个用作线条画布的SKSpriteNode
  3. 创建一个用于绘制新线条的SKShapeNode
  4. 将容器添加到场景中,并将画布和形状节点添加到容器中
  5. 使用形状节点的path属性绘制一组连接的线段
  6. 当线条计数达到预定值时,将容器的内容转换为'SKTexture'
  7. 将画布的纹理属性设置为SKTexture。请注意,由于画布也是容器的子项,因此它的内容也将添加到纹理中
  8. 重复执行5-7步
以下是在Swift中实现的示例,它可以在iPhone 6设备上以60 FPS无限绘制线条(您应该在设备上而不是模拟器上测试性能):
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()
    }
}

如果您想让该行“淡出”,使得每个部分片段的 alpha 值比前一个略高,那该怎么办呢?这个答案在这种情况下是否仍然适用?那么你提到的神秘替代技术呢? - Andrew
@Andrew,这种方法适用于绘制大量持久线条的游戏。我建议你创建一个可变数组,其中包含SKShapeNode线条,随着时间的推移会逐渐消失(通过更改strokeColor属性)。 - 0x141E

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接