2
votes

I need your advice, I'm new in SpriteKit I need to make animation strips. I have 3 solutions to make it, but I need advice that better and less costly for CPU.

  • 1 solution: each stripe - SKSpriteNode with animation and texture
  • 2 solution: background video
  • 3 solution: each stripe - SKShapeNode with animation

enter image description here

4
The highest performance in terms of CPU usage would be use of a series of PNG images that are decoded before hand and then animate with SKAction. The downside with this approach is lots of memory usage. A background video will likely not be able to handle 60 FPS framerate. The SKShapeNode approach can consume a lot of CPU because each frame needs to be rendered. - MoDJ
simple colored sprites are faster than textured ones and they can be made any dimension. - BadgerBadger
@MoDJ I would agree that in this case, no textures are needed... - Whirlwind
I don't know exactly what the original poster wants to do, if this person goes with approach 3, to render shapes from vector information, then no textures would be needed. But, rendering from a vector may or may not be faster, it all depends on the implementation. I know a background video will not work at that FPS rate. - MoDJ

4 Answers

2
votes

This is a simple task , you don't need to build an atlas animation or use SKShapeNode, you can use SKSpriteNode as this code:

var bar = SKSpriteNode(color: SKColor.greenColor(), size: CGSizeMake(40, 200))
barra.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(barra)

Build n bars with random size, and use SKAction to move them.

Whith this approach your animation will be different everytime you launch it.

Code in details:

class GameScene: SKScene {
    var bars: [SKSpriteNode]!
    var totBars : Int = 50
    override func didMoveToView(view: SKView) {
        self.backgroundColor = SKColor(red: 131/255, green: 190/255, blue: 177/255, alpha: 1)
        let redBarColor = SKColor(red: 204/255, green: 75/255, blue: 75/255, alpha: 1)
        let yellowBar = SKColor(red: 253/255, green: 242/255, blue: 160/255, alpha: 1)
        // add here your colors
        var colorSelected:SKColor = redBarColor
        bars = [SKSpriteNode]()
        for i in 0..<totBars-1 {
            let colorNum = randomNumber(1...2)
            switch (colorNum) {
            case 1:
                colorSelected = redBarColor
            case 2:
                colorSelected = yellowBar
            default:
            break
            }
            let randomWidth = randomCGFloat(5,max:40)
            let randomHeight = randomCGFloat(30,max:400)
            let bar = SKSpriteNode.init(color: colorSelected, size: CGSizeMake(randomWidth, randomHeight))
            bar.zRotation = -45 * CGFloat(M_PI / 180.0)
            bar.name = "bar\(i)"
            self.addChild(bar)
            bars.append(bar)
        }
        animateBars()
    }
    func animateBar(bar:SKSpriteNode) {
        print("- \(bar.name) start!")
        let deltaX = self.randomCGFloat(0,max:self.frame.maxX)
        let deltaY:CGFloat  = self.frame.maxY/2
        let rightPoint = CGPointMake(self.frame.maxX + deltaX,self.frame.maxY + deltaY)
        let leftPoint = CGPointMake(-self.frame.maxX + deltaX,-self.frame.maxY + deltaY)
        bar.position = rightPoint
        let waitBeforeExit = SKAction.waitForDuration(Double(self.randomCGFloat(1.0,max:2.0)))
        let speed = self.randomCGFloat(150,max:300)
        let move = SKAction.moveTo(leftPoint, duration: self.getDuration(rightPoint, pointB: leftPoint, speed: speed))
        bar.runAction(SKAction.sequence([waitBeforeExit,move]), completion: {
           print("\(bar.name) reached position")
           self.animateBar(bar)
        })
    }
    func animateBars() {
        for bar in bars {
            animateBar(bar)
        }
    }
    func getDuration(pointA:CGPoint,pointB:CGPoint,speed:CGFloat)->NSTimeInterval {
        let xDist = (pointB.x - pointA.x)
        let yDist = (pointB.y - pointA.y)
        let distance = sqrt((xDist * xDist) + (yDist * yDist));
        let duration : NSTimeInterval = NSTimeInterval(distance/speed)
        return duration
    }
    func randomCGFloat(min: CGFloat, max: CGFloat) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (max - min) + min
    }
    func randomNumber(range: Range<Int> = 1...6) -> Int {
        let min = range.startIndex
        let max = range.endIndex
        return Int(arc4random_uniform(UInt32(max - min))) + min
    }
}
1
votes

If your stripes are simply plain rectangles, you can use SKSpriteNodes and only give them dimensions and a color, then use actions to animate them. you can rotate the rectangles to give the effect you show in the picture.

You could actually build the whole animation in Xcode using the editor, save it in its own SKS file and load the animation using a SKReferenceNode.

0
votes

To answer your question, Solution 3 is the least costly method for your CPU. Here're several reasons why this is true:

1. The first solution that you're suggesting SKSpriteNode with animation and texture" require the computer to load the texture to the view. If you have multiple .png files, this would mean that the computer would need to load all of these files. But if you were to use SKShapeNode, you would avoid having to do this and you would cheaply create the same looks as the SKShapeNode is not based on an image.

2. Solution 2 is the most costly to your CPU because running a video. This takes a lot of space in your memory which might even create lags if you run it on your phone.

Also, just another thing to note: If you were to extensively use Solution 1 and 2, you would end up using so much memory. But if you use the Solution 3, you will not deal with this.

0
votes

Another option, in addition to the ones put forth already, would be to write a GLSL shader for the background. If you just want a cool backdrop that doesn't interact with the rest of your game, this would probably be the most performant option, since it would all happen on the GPU.

You could even, conceivably, render the rectangles without requiring any images at all, since they are just areas of color.

There's a decent introduction to the topic here: Battle of Brothers GLSL Introduction.