SpriteKit:使用SKShapeNode UIBezierPath圆角的正方形到圆形动画

时间:2019-03-30 00:08:18

标签: ios swift sprite-kit

我正在尝试将SpriteKit中的正方形平滑地动画成圆形。

我正在使用带有圆角的SKShape创建UIBezierPath。然后,我改变角半径进行动画处理。

我的问题是动画中似乎有一个 jump ,请参见下面的gif。最好使用圆角技术,如何使其变得光滑?

“跳跃”问题

Bug with animating circle to square

    let shape = SKShapeNode()
    let l: CGFloat = 100.0
    shape.path = UIBezierPath(roundedRect: CGRect(x: -l/2, y: -l/2, width: l, height: l), byRoundingCorners: [.topLeft, .bottomLeft, .topRight, .bottomRight], cornerRadii: CGSize(width: 0, height: 0)).cgPath
    shape.position = CGPoint(x: frame.midX, y: frame.midY)
    shape.fillColor = .white
    addChild(shape)

    let action = SKAction.customAction(withDuration: 1) { (node, t) in
    let shapeNode = node as! SKShapeNode
    shapeNode.path = UIBezierPath(roundedRect: CGRect(x: -l/2, y: -l/2, width: l, height: l), byRoundingCorners: [.topLeft, .bottomLeft, .topRight, .bottomRight], cornerRadii: CGSize(width: t * l / 2, height: 0)).cgPath
    }
    shape.run(SKAction.repeatForever(action))

动画调试

要进行调试,我创建了一些形状,它们的拐角半径逐渐增大,如下所示。数字代表角半径与正方形长度的比率。如您所见,在0.30.35之间有一个跳跃。我看不到我想念的东西。

Progressive incrementation

    let cols = 10
    let rows = 1

    let l: Double = 30.0
    let max: Double = l / 2
    let delta: Double = l * 2

    for i in 0..<rows * cols {
        let s = SKShapeNode()
        let c: Double = Double(i % cols)
        let r: Double = floor(Double(i) / Double(cols))
        let pct: Double = Double(i) / (Double(rows) * Double(cols))
        let rad = pct * max
        s.path = UIBezierPath(roundedRect: CGRect(x: -l/2, y: -l/2, width: l, height: l), byRoundingCorners: [.topRight, .bottomRight, .topLeft, .bottomLeft], cornerRadii: CGSize(width: pct * max, height: pct * max)).cgPath
        s.position = CGPoint(x: c * delta - Double(cols) / 2.0 * delta, y: r * delta - Double(rows) / 2.0 * delta)
        s.lineWidth = 1.5
        s.strokeColor = .white
        addChild(s)

        let t = SKLabelNode(text: String(format:"%0.2f", rad / l))
        t.verticalAlignmentMode = .center
        t.horizontalAlignmentMode = .center
        t.fontName = "SanFrancisco-Bold"
        t.fontSize = 15

        t.position = CGPoint(x: 0, y: -delta * 0.66)
        s.addChild(t)
    }

2 个答案:

答案 0 :(得分:1)

您可能无法使用当前的api找到答案。但是您可以自己绘制。

  let duration = 10.0
    let action = SKAction.customAction(withDuration: duration) { (node, t) in
      let shapeNode = node as! SKShapeNode
        let path = CGMutablePath()
        let borderRadius = l/2 * t  / CGFloat(duration);
      path.move(to: CGPoint.init(x: -l/2, y:  -l/2 + borderRadius));
      path.addLine(to: CGPoint.init(x:  -l/2, y: l/2 - borderRadius));
      path.addArc(tangent1End: CGPoint(x: -l/2, y: l/2), tangent2End: CGPoint(x: -l/2 + borderRadius, y: l/2), radius: borderRadius)
      path.addLine(to: CGPoint.init(x:  l/2 - borderRadius, y: l/2 ));
      path.addArc(tangent1End: CGPoint(x: l/2, y: l/2), tangent2End: CGPoint(x: l/2, y: l/2 - borderRadius), radius: borderRadius)
      path.addLine(to: CGPoint.init(x:  l/2, y: -l/2 + borderRadius));
      path.addArc(tangent1End: CGPoint(x: l/2, y: -l/2), tangent2End: CGPoint(x: l/2 - borderRadius, y: -l/2), radius: borderRadius)
      path.addLine(to: CGPoint.init(x:  -l/2 + borderRadius, y: -l/2));
      path.addArc(tangent1End: CGPoint(x: -l/2, y: -l/2), tangent2End: CGPoint(x: -l/2, y: -l/2 + borderRadius), radius: borderRadius)
      path.closeSubpath()
      shapeNode.path = path
    }

Working solution

答案 1 :(得分:0)

UIBezierPath.init(roundedRect:cornerRadius:)的文档指出:

每个角椭圆的半径。值为0会导致没有圆角的矩形。将大于矩形宽度或高度一半的值适当地钳制为宽度或高度的一半。

但是我对此进行了测试,实际上它确实是精确地发生的,其值大于宽度/高度的 1/3 ,而不是一半它的。我正在填写错误报告,希望它能尽快解决。

错误报告链接:https://bugs.swift.org/browse/SR-10496