Endless Scrolling (Repeating) Background in Spritekit Game - Swift

Vertical endless scrolling background in sprite kit

I will give you an answer conceptually to give you a place to start since you have not provided any code.

You will need multiple images that are the size of the screen and stack them on top of each other vertically.

You then want to move these images down point by point. When the top of one of the images reaches the bottom of the screen, put it back on top of your stack of images. This will cause a never ending scrolling of your background.

Best of luck!

Endless Scrolling Background in SpriteKit

I did a small component called SKScrollingNode for that particular need in my last open source project : SprityBird.

FPS was not an issue even with 3 or 4 layers (for parallax), but you may need to try it yourself.

To use it you just have to add it like any other node and giving it a scrollingSpeed likeso :

back = [SKScrollingNode scrollingNodeWithImageNamed:@"back" inContainerWidth:WIDTH(self)];
[back setScrollingSpeed:BACK_SCROLLING_SPEED];
[self addChild:back];

SKScrollingNode.h

@interface SKScrollingNode : SKSpriteNode

@property (nonatomic) CGFloat scrollingSpeed;

+ (id) scrollingNodeWithImageNamed:(NSString *)name inContainerWidth:(float) width;
- (void) update:(NSTimeInterval)currentTime;

@end

SKScrollingNode.m

@implementation SKScrollingNode

+ (id) scrollingNodeWithImageNamed:(NSString *)name inContainerWidth:(float) width
{
UIImage * image = [UIImage imageNamed:name];

SKScrollingNode * realNode = [SKScrollingNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(width, image.size.height)];
realNode.scrollingSpeed = 1;

float total = 0;
while(total<(width + image.size.width)){
SKSpriteNode * child = [SKSpriteNode spriteNodeWithImageNamed:name ];
[child setAnchorPoint:CGPointZero];
[child setPosition:CGPointMake(total, 0)];
[realNode addChild:child];
total+=child.size.width;
}

return realNode;
}

- (void) update:(NSTimeInterval)currentTime
{
[self.children enumerateObjectsUsingBlock:^(SKSpriteNode * child, NSUInteger idx, BOOL *stop) {
child.position = CGPointMake(child.position.x-self.scrollingSpeed, child.position.y);
if (child.position.x <= -child.size.width){
float delta = child.position.x+child.size.width;
child.position = CGPointMake(child.size.width*(self.children.count-1)+delta, child.position.y);
}
}];
}
@end

Gradually increasing speed of scrolling background in SpriteKit

You could use the gameSpeed variable to set the velocity of the background. For this to work, firstly, you need to have a reference to your two background pieces (or more if you so wanted):

class GameScene: SKScene {
lazy var backgroundPieces: [SKSpriteNode] = [SKSpriteNode(imageNamed: "Background"),
SKSpriteNode(imageNamed: "Background")]

// ...
}

Now you need your gameSpeed variable:

var gameSpeed: CGFloat = 0.0 {
// Using a property observer means you can easily update the speed of the
// background just by setting gameSpeed.
didSet {
for background in backgroundPieces {
// Minus, because the background is moving from left to right.
background.physicsBody!.velocity.dx = -gameSpeed
}
}
}

Then position each piece correctly in didMoveToView. Also, for this method to work each background piece needs a physics body so you can easily change its velocity.

override func didMoveToView(view: SKView) {
for (index, background) in enumerate(backgroundPieces) {
// Setup the position, zPosition, size, etc...

background.physicsBody = SKPhysicsBody(rectangleOfSize: background.size)
background.physicsBody!.affectedByGravity = false
background.physicsBody!.linearDamping = 0
background.physicsBody!.friction = 0

self.addChild(background)
}

// If you wanted to give the background and initial speed,
// here's the place to do it.
gameSpeed = 1.0
}

You could update gameSpeed in update for example with gameSpeed += 0.5.

Finally, in update you need to check if a background piece has gone offscreen (to the left). If it has it needs to be moved to the end of the chain of background pieces:

override func update(currentTime: CFTimeInterval) {
for background in backgroundPieces {
if background.frame.maxX <= 0 {
let maxX = maxElement(backgroundPieces.map { $0.frame.maxX })

// I'm assuming the anchor of the background is (0.5, 0.5)
background.position.x = maxX + background.size.width / 2
}
}
}

How can I create a finite, scrollable background in SpriteKit?

So, taking @KnightOfDragon's comment into account about needing to set maximum and minimum X coordinate values for the background, I was able to solve my own question. I already had swipe left/right recognisers in my code (for another purpose in my game), and I was able to reuse these to fulfil my needs. Code is as follows:

In didMove():

swipeRightRec.addTarget(self, action: #selector(self.swipedRight) )
swipeRightRec.direction = .right
self.view!.addGestureRecognizer(swipeRightRec)

swipeLeftRec.addTarget(self, action: #selector(self.swipedLeft) )
swipeLeftRec.direction = .left
self.view!.addGestureRecognizer(swipeLeftRec)

And then these functions:

@objc func swipedRight() {
if background.position.x + 250 > maxBackgroundX {
let moveAction = SKAction.moveTo(x: maxBackgroundX, duration: 0.3)
background.run(moveAction)
} else {
let moveAction = SKAction.moveTo(x: background.position.x + 250, duration: 0.3)
background.run(moveAction)
}
}

@objc func swipedLeft() {
if background.position.x - 250 < minBackgroundX {
let moveAction = SKAction.moveTo(x: minBackgroundX, duration: 0.3)
background.run(moveAction)
} else {
let moveAction = SKAction.moveTo(x: background.position.x - 250, duration: 0.3)
background.run(moveAction)
}
}

Yes this means that the background moves a set amount each time you swipe, no matter how big the swipe is, but it is exactly what I required for my game. I hope this helps someone else who needs the same thing!

Scrolling background - Sprite Kit

Anyway, I fixed it. Just in case someone else will need it, this is how I did it:

    // Create 2 background sprites
bg1 = [SKSpriteNode spriteNodeWithImageNamed:@"bg1"];
bg1.anchorPoint = CGPointZero;
bg1.position = CGPointMake(0, 0);
[self addChild:bg1];

bg2 = [SKSpriteNode spriteNodeWithImageNamed:@"bg2"];
bg2.anchorPoint = CGPointZero;
bg2.position = CGPointMake(bg1.size.width-1, 0);
[self addChild:bg2];

then in the update method:

    bg1.position = CGPointMake(bg1.position.x-4, bg1.position.y);
bg2.position = CGPointMake(bg2.position.x-4, bg2.position.y);

if (bg1.position.x < -bg1.size.width)
bg1.position = CGPointMake(bg2.position.x + bg2.size.width, bg1.position.y);

if (bg2.position.x < -bg2.size.width)
bg2.position = CGPointMake(bg1.position.x + bg1.size.width, bg2.position.y);

Endless repeating scrolling/animated background in iOS?

Well, in code you could create a new image that is the composite of these two. This composite image is 960 pixels wide, and has the first image copied to the rightmost and leftmost positions. The middle position is the second image.

You start the image left shifted 640 pixels so you can only see the first image. Then you animate 640 pixels. When you restart the animation the image is always left shifted 640 pixels.

This way you have one animation.



Related Topics



Leave a reply



Submit