Swift, sprite kit game: Have circle disappear in c

2019-01-26 01:04发布

问题:

Alright, so I don't know the name for this but I have a sprite kit game (a runner game) that, when it's game over, is going to have a "save me" button and a timer that runs out accordingly. When the timer runs out, you can no longer click the button and save the character.

I don't want to display this timer in text however- I want a circle that "unwinds itself," if you will, and disappears at the rate that the timer runs out. I.e. when the timer reaches 0, the circle has fully disappeared. The circle disappears degree by degree in a clockwise motion in accordance with the timer.

Here are some pictures to explain what I'm talking about.

How would I do this?

回答1:

By changing the path property of an SKShapeNode at a fixed interval, you can create a frame-by-frame animation sequence. To create the animation, set the path property to a sequence of shapes that starts with a circle and ends with nothing. You can use UIBezierPath, a wrapper for CGPath, to create shapes for the animation using the following steps:

  1. Move path's "pen" to the center of the circle
  2. Add an arc to the path with addArcWithCenter from a startAngle to endAngle
  3. Add a line to the path from the point on the circle corresponding to the ending angle to the center
  4. Change the endAngle by a fixed amount
  5. Repeat steps 1-4

Here's an implementation of the above steps:

override func didMove(to:SKView) {

    let circle = SKShapeNode(circleOfRadius: 50)
    circle.fillColor = SKColor.blue
    circle.strokeColor = SKColor.clear
    circle.zRotation = CGFloat.pi / 2
    addChild(circle)

    countdown(circle: circle, steps: 20, duration: 5) {
        print("done")
    }
}

// Creates an animated countdown timer
func countdown(circle:SKShapeNode, steps:Int, duration:TimeInterval, completion:@escaping ()->Void) {
    guard let path = circle.path else {
        return
    }
    let radius = path.boundingBox.width/2
    let timeInterval = duration/TimeInterval(steps)
    let incr = 1 / CGFloat(steps)
    var percent = CGFloat(1.0)

    let animate = SKAction.run {
        percent -= incr
        circle.path = self.circle(radius: radius, percent:percent)
    }
    let wait = SKAction.wait(forDuration:timeInterval)
    let action = SKAction.sequence([wait, animate])

    run(SKAction.repeat(action,count:steps-1)) {
        self.run(SKAction.wait(forDuration:timeInterval)) {
            circle.path = nil
            completion()
        }
    }
}

// Creates a CGPath in the shape of a pie with slices missing
func circle(radius:CGFloat, percent:CGFloat) -> CGPath {
    let start:CGFloat = 0
    let end = CGFloat.pi * 2 * percent
    let center = CGPoint.zero
    let bezierPath = UIBezierPath()
    bezierPath.move(to:center)
    bezierPath.addArc(withCenter:center, radius: radius, startAngle: start, endAngle: end, clockwise: true)
    bezierPath.addLine(to:center)
    return bezierPath.cgPath
}

and a video clip: