SpriteKit: квадратная круговая анимация с использованием SKShapeNode UIBezierPath, закругленные углы - PullRequest
0 голосов
/ 30 марта 2019

Я пытаюсь плавно анимировать квадрат в круг в SpriteKit.

Я создаю SKShape с UIBezierPath, используя закругленные углы. Затем я изменяю угловой радиус для анимации.

Моя проблема в том, что у меня, похоже, в анимации прыжок , см. Рисунок ниже. Предпочтительно, используя технику закругленных углов, как сделать так, чтобы она была гладкой?

проблема "Jumpy"

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.3 и 0.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 ]

1 голос
/ 30 марта 2019

Вы не можете найти ответ, используя текущий 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

0 голосов
/ 17 апреля 2019

Документация UIBezierPath.init(roundedRect:cornerRadius:) гласит:

Радиус каждого угла овал. Значение 0 приводит к прямоугольнику без закругленных углов. Значения, превышающие половину ширины или высоты прямоугольника, зажимаются соответственно половине ширины или высоты.

Но я проверил это, и это на самом деле происходит точно для значений, превышающих третью ширины / высоты, а не на половине . Я заполняю отчет об ошибке и будем надеяться, что он быстро решен.

Ссылка на сообщение об ошибке: https://bugs.swift.org/browse/SR-10496

...