Game Programming: Creating infinite seamless scrolling backgrounds.

If you are like any of us in here you must have played Halfbrick’s Monster Dash or the more recent, totally amazing ,Jetpack Joyride.

I can’t avoid playing great games and keep wondering “How the %@*$ did they do that?” and that is what inspired this little tutorial.

What we are going to do is to create a basic logic for creating a scrolling background that uses any amount of different images, loaded and unloaded dynamically when needed.

I don’t claim to know how Halfbrick’s guys did the random, scrolling backgrounds for Jetpack Joyride but this is as closest as I could get while spending little time working on it, and of course there is a lot of room for improvement.

I am going to write down the final code, but there was a lot of trying in the middle which ended in failure for me.

In this example we are scrolling 5 images from top to bottom and looping them infinitely.  The example is made for loading fullscreen images and it runs at a perfect 60 fps with no visible glitches or slowdowns in an iPhone 4 with Retina Display graphics. I’ve yet to try it in older devices or with different sized images.

Here is the code:

//
//  HelloWorldLayer.h
//  JumpMan
//
//  Created by Pablo Ruiz on 05/09/11.
//  Copyright InfinixSoft S.R.L. 2011. All rights reserved.
//


// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"

// HelloWorldLayer
@interface HelloWorldLayer : CCLayer
{
	int currentBck;
	CCSprite * cachedNode;
	BOOL alreadyLoadedOneNode;
	float timedScale;
	NSMutableArray * backgroundSprites;
	BOOL cachedInitialImage;
}

// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
-(void)launchImg:(float)offset;
-(void)changeTimeScale;
-(void)loadNode;
-(void)cacheTexture:(CCTexture2D *)texturr;
-(void)removeNode:(CCSprite *)n;

@end

 

The example runs in portrait and it requires for you to have 5 fullscreen (320 x 480) images bck1.png, bck2.png and so on, and their -hd versions too. Just start a new Cocos2d project from the templates and replace the HelloWorldLayer files with the ones provided in here.

Let me explain what the code does:

  1. First, in the init method we initialize the backgroundSprites array which holds our background pieces for updating their positions. Then we set some initial values for the necessary variables we need. After that, we call the loadNode method which we’ll see in a moment. Finally we call the update method which will update the pieces’ positions and manage their unloading.
  2. What the loadNode method does is to tell Cocos2d to load the next texture asynchronously. We do it this way so this new texture is loaded in another thread and we don’t see a hiccup while this is done. Once the texture is loaded, the cacheTexture method will be called.
  3. The cacheTexture method creates the CCsprite from that texture and holds a reference to it so we can add this image right up to the last one when needed.
  4. In the update method we keep moving down the images added to the backgroundSprites array. If one of those images moves past the end of the screen we display the image we had loaded and cached before. Then if that images goes way more past the screen, to the point it is not seen anymore we call the removeNode method.
  5. The removeNode method removes the CCsprite from the layer and removes the texture from the cache to free up memory.

That is all!

Ohh one other thing, the first time this loads, we have the first image right in the place where it should be start SHOWING the next one. That means that we wouldn’t have that second image in the cache loaded, so what we do is to start the scrolling once the second image has been loaded too. This makes the scrolling start half a sec later instead of instantly. This is easily conceivable by adding a “Ready, set, go!” animation or anything that delays the scrolling a little bit!

There is a lot of room for improvement and we are all ears to hearing your suggestions or critics!