# Cocos2d: Moving background on update: offsett issue

working with Objective C, iOS and Cocos2d I am developing a vertical scrolling shooter game for iPhone (retina display models with 640 width x 960 height pixel resolution).

My basic algorithm works as following:

• I create two instances of an image that has exactly 640 width x 960 height pixel of resolution, which we will call imageA and imageB
• I then set the two imags with exactly 480.0f of offset from each other, as the screenSize of a CCScene is set by default to 480.0f.
• At each update method call I move the two images by the same value. I make sure that their offsett stays to 480.0f

However when running the game I see a 1 pixel height line between the two images. This literally bugs me and would like to adjust this.

What am I doing wrong?

This is a zoom in on the background when the "offsett line" is visible. The white line you can see divides the two background images and is not meant to exist as both images are completely black :):

If I change the yPositionOfSecondElement value to 479.0f until the first loop the two images overlap correctly, but as soon as the loop starts the two images starts having an offsett of -1.0f.

Here is the initialization code:

-(void) init
{

//...

screenHeight = 480.0f;
yPositionOfSecondElement= screenHeight;//I tried subtracting an offsett of -1 but eventually the image would go wrong again
yPositionOfFirstElement = 0.0f;

loopedBackgroundImageInstanceA = [BackgroundLoopedImage loopImageForLevel:levelName];
loopedBackgroundImageInstanceA.anchorPoint = CGPointMake(0.5f, 0.0f);
loopedBackgroundImageInstanceA.position = CGPointMake(160.0f, yPositionOfFirstElement);

//loopedBackgroundImageInstanceA.color= ccRED;

loopedBackgroundImageInstanceB = [BackgroundLoopedImage loopImageForLevel:levelName];
loopedBackgroundImageInstanceB.anchorPoint = CGPointMake(0.5f, 0.0f);
loopedBackgroundImageInstanceB.position = CGPointMake(160.0f, yPositionOfSecondElement);

//....
}


And here is the move code called at each update:

-(void) moveBackgroundSprites:(BackgroundLoopedImage*)imageA  :(BackgroundLoopedImage*)imageB :(ccTime)delta
{
isEligibleToMove=false;

//This is done to avoid rounding errors
float yStep = delta * [GameController sharedGameController].currentBackgroundSpeed;

NSString* formattedNumber = [NSString stringWithFormat:@"%.02f", yStep];
yStep = atof([formattedNumber UTF8String]);

//First should adjust position of images

//The can get the actual image position

CGPoint posA = imageA.position;
CGPoint posB = imageB.position;

//Here could verify if the checksum is equal to the required difference (should be 479.0f)
if (![self verifyCheckSum:posA :posB]) {
CCLOG(@"does not comply A");
}

//At this stage can compute the hypotetical new position
CGPoint newPosA = CGPointMake(posA.x, posA.y - yStep);
CGPoint newPosB = CGPointMake(posB.x, posB.y - yStep);

// Reposition stripes when they're out of bounds
if (newPosA.y <= -yPositionOfSecondElement)
{
newPosA.y = yPositionOfSecondElement;
[imageA shuffle];
if (timeElapsed>=endTime && hasReachedEndLevel==FALSE) {
hasReachedEndLevel=TRUE;
shouldMoveImageEnd=TRUE;
}
}
else if (newPosB.y <= -yPositionOfSecondElement)
{
newPosB.y = yPositionOfSecondElement;
[imageB shuffle];
if (timeElapsed>=endTime && hasReachedEndLevel==FALSE) {
hasReachedEndLevel=TRUE;
shouldMoveImageEnd=TRUE;
}
}

//Here should verify that the check sum is equal to 479.0f
if (![self verifyCheckSum:posA :posB]) {
CCLOG(@"does not comply B");
}

imageA.position = newPosA;
imageB.position = newPosB;

//Here could verify that the check sum is equal to 479.0f
if (![self verifyCheckSum:posA :posB]) {
CCLOG(@"does not comply C");
}

isEligibleToMove=true;
}

-(BOOL) verifyCheckSum:(CGPoint)posA :(CGPoint)posB
{
BOOL comply = false;
float sum = 0.0f;

if (posA.y > posB.y) {
sum = posA.y - posB.y;
}
else if (posB.y > posA.y){
sum = posB.y - posA.y;
}
else{
return false;
}

if (sum!=yPositionOfSecondElement) {
comply= false;
}
else{
comply=true;
}
return comply;
}


And here is what happens on the update:

if(shouldMoveImageA && shouldMoveImageB)
{
if (isEligibleToMove) {
[self moveBackgroundSprites:loopedBackgroundImageInstanceA :loopedBackgroundImageInstanceB :delta];
}


Forget about shouldMoveImageA and shouldMoveImageB, this is just for when the background reaches the end of level, this works.

• base on my experience image positions should not have a fractional part, otherwise you'll see those artifact Nov 14, 2013 at 15:20
• so for fractional part you refer as the position in float? Should I use int instead?
– mm24
Nov 14, 2013 at 15:28
• not int, but for moving objects, that should always be aligned like the background you are working on, it's much nicer if you round the position just before drawing, always working with integers is not really nice since objects won't move smooth enough Nov 14, 2013 at 15:33
• I do something similar with an horizontal scrolling game, but using actions. If you want this approach I can share the code. Nov 29, 2013 at 13:48
– mm24
Nov 29, 2013 at 18:34

Don't know if this will help but here is the code for a game where we have moving clouds in the background. Is very old but will get you an idea.

-(id) init{
if( (self=[super init] )) {
first = [CCSprite spriteWithFile:@"clouds_1.png"];
firstWidth = first.contentSize.width;
height = first.contentSize.height;
second = [CCSprite spriteWithFile:@"clouds_2.png"];
secondWidth = second.contentSize.width;
Yvalue = GO_CLOUDS_YVALUE;
duration = GO_CLOUDS_DURATION;
CGSize size = [[CCDirector sharedDirector] winSize];
firstXf = -1 * (secondWidth - size.width + firstWidth/2);
secondXf = -1 * (firstWidth + secondWidth/2);
firstX0 = size.width + firstWidth/2;
secondX0 = size.width + secondWidth/2;

moveFirstDone = [CCCallFuncN actionWithTarget:self selector:@selector(callFirstDone:)];
moveSecondDone = [CCCallFuncN actionWithTarget:self selector:@selector(callSecondDone:)];

first.position = ccp(firstX0 + -1*firstX0,Yvalue);
second.position = ccp(secondX0,Yvalue);
[first runAction:[CCSequence actions:[CCMoveTo actionWithDuration:duration position:ccp(firstXf,Yvalue)],moveFirstDone,nil]];
[second runAction:[CCSequence actions:[CCMoveTo actionWithDuration:duration*2 position:ccp(secondXf,Yvalue)],moveSecondDone,nil]];
}
return self;
}

-(void)callSecondDone:(id)sender{
second.position = ccp(secondX0,Yvalue);
[second runAction:[CCSequence actions:[CCMoveTo actionWithDuration:duration*2 position:ccp(secondXf,Yvalue)],moveSecondDone,nil]];
}

-(void)callFirstDone:(id)sender{
first.position = ccp(firstX0,Yvalue);
[first runAction:[CCSequence actions:[CCMoveTo actionWithDuration:duration*2 position:ccp(firstXf,Yvalue)],moveFirstDone,nil]];
}


It looks like your image has an anti aliasing at it's border. You can either fix this in photoshop or you could use a program like texturepacker that will extend your picture a pixel and remove this border.