How to create progress bar in sprite kit?

7 Solutions Collect From Internet About “How to create progress bar in sprite kit?”

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;


@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;


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.

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.

Assuming HealthBarNode is a subclass of SKSpriteNode with a public property health that varies between 0.0 and 1.0 and whose parental property texture is generated from the entire color bar image of width _textureWidth (a private property), you could do something like this:

- (void)setHealth:(CGFloat)fraction
{ = MIN(MAX(0.0, fraction), 1.0); // clamp health between 0.0 and 1.0
    SKTexture *textureFrac = [SKTexture textureWithRect:CGRectMake(0, 0, fraction, 1.0) inTexture:self.texture]; 
// check docs to understand why you can pass in self.texture as the last parameter every time

    self.size = CGSizeMake(fraction * _textureWidth, self.size.height);
    self.texture = textureFrac;

Setting the health to a new value will cause the health bar (added as a child to the main scene, say) to get cropped properly.

I built a small library to deal with this exact scenario! Here is SpriteBar:

There is no “cutting” an image/texture.

An alternative to what Cocos offered is to make a couple of textures and interchange them into your node depending on health. I did a game where the health bar changed texture every 10 points (range was 0-100). After some trial and error though, I just ended up doing what Cocos already suggested.

enter image description here

I did it like this, and it works perfectly.

So first, I declared a SKSpriteNode:

baseBar = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(CGRectGetMidX(self.frame)-40, self.frame.size.height/10)];
//The following will make the health bar to reduce from right to left
//Change it to (1,0.5) if you want to have it the other way
//But you'd have to play with the positioning as well
[baseBar setAnchorPoint:CGPointMake(0, 0.5)];
CGFloat goodWidth, goodHeight;
goodHeight =self.frame.size.height-(baseBar.frame.size.height*2/3);
goodWidth =self.frame.size.width-(10 +baseBar.frame.size.width);
[baseBar setPosition:CGPointMake(goodWidth, goodHeight)];
[self addChild:baseBar];

I then added a ‘Frame’ for the bar, with an SKShapeNode, without fill colour (clearcolour), and a stroke colour:

//The following was so useful
SKShapeNode *edges = [SKShapeNode shapeNodeWithRect:baseBar.frame];
edges.fillColor = [UIColor clearColor];
edges.strokeColor = [UIColor blackColor];
[self addChild:edges];

When I wanted to reduce the health, I did the following:

    if (playerHealthRatio>0) {
        playerHealthRatio -= 1;
        CGFloat ratio = playerHealthRatio / OriginalPlayerHealth;
        CGFloat newWidth =baseBar.frame.size.width*ratio;
        NSLog(@"Ratio: %f newwidth: %f",ratio,newWidth);
        [baseBar runAction:[SKAction resizeToWidth:newWidth duration:0.5]];
//        NSLog(@"Game over");

Simple, clean and not complicated at all.

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()
    let filledImage  = SKSpriteNode(imageNamed: filledImageName)
    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

    if emptyImageName != nil{
        emptySprite = SKSpriteNode.init(imageNamed: emptyImageName)
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")


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

and add this progressBar to any SKNode :


//That’s all.