How to create progress bar in sprite kit?

that is my ProgressBar in swift :

import Foundation

import SpriteKit


class IMProgressBar : SKNode{

var emptySprite : SKSpriteNode? = nil
var progressBar : SKCropNode
init(emptyImageName: String!,filledImageName : String)
{
    progressBar = SKCropNode()
    super.init()
    let filledImage  = SKSpriteNode(imageNamed: filledImageName)
    progressBar.addChild(filledImage)
    progressBar.maskNode = SKSpriteNode(color: UIColor.whiteColor(),
        size: CGSize(width: filledImage.size.width * 2, height: filledImage.size.height * 2))

    progressBar.maskNode?.position = CGPoint(x: -filledImage.size.width / 2,y: -filledImage.size.height / 2)
    progressBar.zPosition = 0.1
    self.addChild(progressBar)

    if emptyImageName != nil{
        emptySprite = SKSpriteNode.init(imageNamed: emptyImageName)
        self.addChild(emptySprite!)
    }
}
func setXProgress(xProgress : CGFloat){
    var value = xProgress
    if xProgress < 0{
        value = 0
    }
    if xProgress > 1 {
        value = 1
    }
    progressBar.maskNode?.xScale = value
}

func setYProgress(yProgress : CGFloat){
    var value = yProgress
    if yProgress < 0{
        value = 0
    }
    if yProgress > 1 {
        value = 1
    }
    progressBar.maskNode?.yScale = value
}
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}

//How to use :

let progressBar = IMProgressBar(emptyImageName: "emptyImage",filledImageName: "filledImage")

or

let progressBar = IMProgressBar(emptyImageName: nil,filledImageName: "filledImage")

and add this progressBar to any SKNode :

self.addChild(progressBar)

//That's all.


Quite simply: you need a frame image (optional) and a "bar" image. The bar image out to be a single, solid color and as high as you need it and 1 or 2 pixels wide. A SKShapeNode as bar will do as well.

Just making the bar and animating is simply a matter of changing the SKSpriteNode's size property. For example to make the bar represent progress between 0 and 100 just do:

sprite.size = CGSizeMake(progressValue, sprite.size.height);

Update the size whenever progressValue changes.

You'll notice the image will increase in width to both left and right, to make it stretch only to the right change the anchorPoint to left-align the image:

sprite.anchorPoint = CGPointMake(0.0, 0.5);

That is all. Draw a frame sprite around it to make it look nicer.


I would recommend looking into SKCropNode. For a visual aid how SKCropNode works, look it up in the Apple Programming Guide. I have read through the entire document multiple times and it is a particularly good read.

SKCropNode is basically an SKNode which you add to your scene, but its children can be cropped by a mask. This mask is set in the maskNode property of the SKCropNode. In this way, you only need one texture image. I would subclass SKCropNode to implement functionality to move or resize the mask, so you can easily update its appearance.

@interface CustomProgressBar : SKCropNode

/// Set to a value between 0.0 and 1.0.
- (void) setProgress:(CGFloat) progress;

@end

@implementation CustomProgressBar

- (id)init {
  if (self = [super init]) {
    self.maskNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(300,20)];
    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"progressBarImage"];
    [self addChild:sprite];
  }
  return self;
}

- (void) setProgress:(CGFloat) progress {
  self.maskNode.xScale = progress;
}

@end

In your scene:

#import "CustomProgressBar.h"

// ...

CustomProgressBar * progressBar = [CustomProgressBar new];
[self addChild:progressBar];

// ...

[progressBar setProgress:0.3];

// ...

[progressBar setProgress:0.7];

Note: this code doesn't move the mask (so the sprite will be cropped on either side) but I'm sure you get the idea.