Circular Pulse Animation with Sprite Kit

I'm trying to make circular pulse animation. I used the following code with single view application and it works great, but now I want to assign physics to the circle so I put the same code in sprite kit and its not working. Then I modified the code with SKShapeNode which you can find below. Its not working in sprite kit. Can someone please please help me out with this.


override func drawRect(rect: CGRect) {

let shapeLayer = CAShapeLayer()

let circlePath = UIBezierPath(arcCenter: CGPoint(x: self.bounds.size.width/2, y: self.bounds.size.height/2), radius: CGFloat(10), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)

shapeLayer.path = circlePath.CGPath

shapeLayer.lineWidth = 1

shapeLayer.strokeColor = UIColor.redColor().CGColor

shapeLayer.fillColor = UIColor.init(red: 247/255, green: 78/255, blue: 0/255, alpha: 0.09).CGColor

layer.addSublayer(shapeLayer)

let animation = CABasicAnimation(keyPath: "path")

animation.duration = 2

animation.repeatCount = 30

animation.toValue = UIBezierPath(arcCenter: CGPoint(x: self.bounds.size.width/2, y: self.bounds.size.height/2), radius: CGFloat(1000), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true).CGPath

animation.removedOnCompletion = true

shapeLayer.addAnimation(animation, forKey: nil)

}



Modified Code for SpriteKit


class GameScene: SKScene {



let shapeLayer = CAShapeLayer()

let circlePath = SKShapeNode ()

var path = UIBezierPath ()



override func didMoveToView(view: SKView)

{

/ Setup your scene here */

self.scene!.backgroundColor = UIColor(red: 122/255, green: 167/255, blue: 155/255, alpha: 1)

/

circlePath.path = UIBezierPath(ovalInRect: CGRectMake(0, 0, 20, 20)).CGPath

circlePath.position = CGPoint(x: size.width/2, y: size.height/2)

circlePath.fillColor = UIColor.init(red: 247/255, green: 78/255, blue: 0/255, alpha: 0.09)

circlePath.strokeColor = UIColor.redColor()

circlePath.lineWidth = 1

addChild(circlePath)


shapeLayer.path = circlePath.path

let animation = CABasicAnimation(keyPath: "path")

animation.duration = 2

animation.repeatCount = 30

/

animation.toValue = UIBezierPath(ovalInRect: CGRectMake(0, 0, 1000, 1000)).CGPath

animation.removedOnCompletion = true

shapeLayer.addAnimation(animation, forKey: nil)


}

Accepted Reply

SpriteKit is a complete animation environment, so I think it's a bad idea to try to mix-and-match CA animations into that. It's either not going to work at all, or it's likely going to kill performance (fps).


Instead, use a SKAction to animate your sprite. I'm not sure I'm reading your code correctly, but it looks like you're basically just scaling your shape. You can use a 'scaleBy' or 'scaleTo' SKAction for that.


Also, at least in the past, SKShapeNode was fairly unsatisfactory in terms of performance and appearance. You'd be better off using SKSpriteNodes instead.

Replies

SpriteKit is a complete animation environment, so I think it's a bad idea to try to mix-and-match CA animations into that. It's either not going to work at all, or it's likely going to kill performance (fps).


Instead, use a SKAction to animate your sprite. I'm not sure I'm reading your code correctly, but it looks like you're basically just scaling your shape. You can use a 'scaleBy' or 'scaleTo' SKAction for that.


Also, at least in the past, SKShapeNode was fairly unsatisfactory in terms of performance and appearance. You'd be better off using SKSpriteNodes instead.

For example :


//
// Extension.swift
// PulseAnimation
//
// Created by Onur Işık on 17.09.2018.
// Copyright © 2018 Onur Işık. All rights reserved.
//
import SpriteKit
extension SKSpriteNode {

private static let fillColor = UIColor(red: 0, green: 0.455, blue: 0.756, alpha: 0.45)

func addPulseEffect(circleOfRadius: CGFloat, backgroundColor: UIColor = fillColor) {

let circle = SKShapeNode(circleOfRadius: circleOfRadius)
circle.fillColor = backgroundColor
circle.lineWidth = 0.0
circle.position = CGPoint(x: 0, y: 0)
self.addChild(circle)
let scale = SKAction.scale(to: 3.0, duration: 1.0)
let fadeOut = SKAction.fadeOut(withDuration: 1.0)
let pulseGroup = SKAction.sequence([scale, fadeOut])
let repeatSequence = SKAction.repeatForever(pulseGroup)
circle.run(repeatSequence)

}

func repeatPulseEffectForEver(circleOfRadius: CGFloat) {
let _ = Timer.scheduledTimer(withTimeInterval: 0.8, repeats: true) { (timer) in
self.addPulseEffect(circleOfRadius: circleOfRadius)
}

}

}

Sure, but why is there a Timer involved? The Sprite Kit action repeats every 2 seconds for ever. If you add a new pulse "effect" ever 0.8 seconds, all you're going to see is a mess of ever more random flashing. Or is there a point to "repeatPulseEffectForEver" that I'm missing?