-1

I am trying to create a repeating background from top to bottom. I have got the background to actually scroll however there's a black area that appears with each repetition. I'm not entirely sure why this is happening... Below is my code:

- (void)onEnter
{
    [super onEnter];
    [self initBackground];
}

-(void)initBackground
{
    NSString *backgroundImage = @"Stars.png";//[self getThemeBG];

    background1 = [CCSprite spriteWithImageNamed:backgroundImage];
    background1.position = ccp(self.contentSize.width*0.5f,self.contentSize.height*0.5f);
    [self addChild:background1 z:-123];

    background2 = [CCSprite spriteWithImageNamed:backgroundImage];
    background2.position = ccp(self.contentSize.width*0.5f,self.contentSize.height*0.5f+background1.contentSize.height);

    background2.flipY = true;
    [self addChild:background2 z:-456];

}

-(void)scrollBackground:(CCTime)dt
{
    CGSize s = [[CCDirector sharedDirector] viewSize];

    CGPoint pos1 = background1.position;
    CGPoint pos2 = background2.position;

    pos1.y -= kScrollSpeed;
    pos2.y -= kScrollSpeed;


    if(pos1.y <=-(s.height*0.5f) )
    {
        pos1.y = pos2.y + background2.contentSize.height;
    }

    if(pos2.y <=-(s.height*0.5f) )
    {
        pos2.y = pos1.y + background1.contentSize.height;
    }

    background1.position = pos1;
    background2.position = pos2;

}

-(void)update:(CCTime)delta
{
    [self scrollBackground:delta];
}

I have defined kScrollSpeed as 3 and both backgroundImage1 and 2 are CCSprites. I'm not entirely sure why a black area is appearing with each cycle.

The dimensions of the background image is 640 x 1136px.

James Webster
  • 31,873
  • 11
  • 70
  • 114

1 Answers1

1

The trick to solve the "black lines" issue with tiling graphics, specifically for cocos2d but also applicable to Sprite Kit and other render engines is to ensure that content is drawn on exact pixel boundaries.

The only way to ensure that is to cast positions to integers, or on Retina round to the next nearest "half point" (ie on Retina 123.5 is a valid exact pixel coordinate, but not on non-Retina devices).

Where exactly to perform the rounding depends on your code, but in general instead of doing this:

background1.position = pos1;

You need to do:

pos1.x = round(pos1.x * 2.0) / 2.0;
pos1.y = round(pos1.y * 2.0) / 2.0;
background1.position = pos1;

Casting to int is often recommended but it means that on Retina devices your content will only move on a 2-pixel boundary. The above solution doesn't use int casting but relies on rounding to allow .5 coordinates. It works equally well on both standard and Retina resolution devices.

PS: I strongly advice to create a helper function or overriding the setPosition: method for the above rounding code. You don't want to spread these calculations all over your code.

More points to consider:

  • only round once, at the very end of your position calculations, before applying the new position to the node's position property
  • you may need to apply the same round procedure to parent's position, for example if you change position of both tile sprites and their parent (ie a layer or container node)
CodeSmile
  • 64,284
  • 20
  • 132
  • 217