Side Scrolling Best Approach (moving the layer?)

Forums Programming cocos2d support (graphics engine) Side Scrolling Best Approach (moving the layer?)

This topic contains 13 replies, has 6 voices, and was last updated by  jordo 4 years ago.

Viewing 14 posts - 1 through 14 (of 14 total)
Author Posts
Author Posts
March 29, 2010 at 5:58 pm #220730

meladori
@meladori

I am new to Cocos2d and am trying to scroll the background horizontally based on pressing a button (menu item). In my game the character stays in the center of the screen and does not move, but the background does.

I cannot seem to reference the x position of my background Sprite. Am I using getChildByTag properly? Is this the proper approach to side scrolling backgrounds (just move the layer?) Have looked over the documentation and sample code extensively and any help that you can provide would be very much appreciated.

in my init() file:

// add arrow menus
CCMenuItemImage *item1 = [CCMenuItemImage itemFromNormalImage:@"b1.png" selectedImage:@"b2.png" target:self selector:@selector(moveBgBack:)];
CCMenuItemImage *item2 = [CCMenuItemImage itemFromNormalImage:@"f1.png" selectedImage:@"f2.png" target:self selector:@selector(moveBgForward:)];
// set up the arrows etc...
// add background
CCSprite *background = [CCSprite spriteWithFile:bgFileName];
[self addChild:background z:-1 tag:kBackground];

move background forward when arrow button is pressed:

-(void)moveBgForward:(id)sender {
CCSprite bgTemp = [layer getChildByTag:KBackground]
CGPoint currentPos = [bgTemp position];
bgTemp.position.x += 10; // ??
// set x position bounds so you don't over-scroll and get a blank screen
}

March 29, 2010 at 7:34 pm #278325

meladori
@meladori

To answer my own question, I found a tutorial here:

http://johnehartzog.com/2009/10/2d-scrolling-game-with-cocos2d-tilemap-with-zoom/

April 6, 2010 at 7:33 am #278326

donbhar
Participant
@donbhar

How did you do it? I would really be grateful if you could show me some source

April 6, 2010 at 4:40 pm #278327

meladori
@meladori

I didn’t subclass CCMenuItemImage at all. I ended up using a CCSprite and just testing to see if that was pressed, then moving the background based on that.

April 7, 2010 at 6:45 am #278328

ejfarraro
Participant
@ejfarraro

Before driving yourself insane moving the background layer around, consider looking at CCCamera samples. I found it much more intuitive. If you take the ‘move the background’ approach (at least in my experience) it has made collision detection and other things really confusing. By moving the camera around, it’s a lot easier.

Take a look at CCCamera at the setCenter/setEye methods. What you do to keep your character static is whenever your character moves, move the camera (both center and eye) by the same amount. If you move the background instead, you will constantly need to track what the player’s screen position is vs. his actual ‘in game’ position. By moving the camera, the player’s coordinate is always accurate, and you can use it for collision detection.

Hope that makes sense.

April 7, 2010 at 7:21 am #278329

donbhar
Participant
@donbhar

This is really confusing! All the tutorials out there are saying that the camera makes it hard to keep track of object coordinants but your saying that the camera makes it easier to keep track of coordinants -either those tutorials or you are wrong

April 7, 2010 at 8:16 am #278330

ejfarraro
Participant
@ejfarraro

Well, imagine you have a player sprite. It’s always in the middle of the screen. It’s position is (240, 160).

Now imagine that the player sprite “walks” 100 pixels to the right. His position on the screen is still (240, 160) but his ‘game position’ is actually 340, 160. You can no longer use the player’s sprite to perform collision detection. If you were to test CCSprite.position, it would return (240, 160). Instead of moving the player, you’ve moved the background behind him.

Instead, imagine you have a camera that tracks the player’s movement EXACTLY, such that the player always APPEARS to be in the middle of the screen. When the player walks 100 pixels right, his new position is (340, 160), and if you were to test CCSprite.position, position.x would in fact be 100 pixels greater than it used to be. Unlike the above example, you can actually use the character’s sprite to perform collision detection, because it actually is moving.

In the second example, the player APPEARS to be in the same place in the screen, because you move the camera to follow the player exactly.

Hopefully that makes some sense. I was ripping my hair out trying to do the first approach and guaranteed, you will make mistakes. It’s relatively impossible to screw it up if you’re using the camera.

April 9, 2010 at 2:23 pm #278331

donbhar
Participant
@donbhar

Ok, interesting but using the camera screws up rotation I have heard.

This is what i wanna do: Have 4 buttons and when the user presses the buttons it will move in a given direction: Do i move the camera or the layer, currently i am using the layer approach but it is screwing with my touch methods, what should i do?

April 9, 2010 at 2:41 pm #278332

Blue Ether
Participant
@blue-ether

I’ve never used the Cocos camera, and its not necessary. You can make your own “camera” simply by setting the position to -[the player's position] + offset. So, if the player is centered than the offset is always 240 and if the player is actually at 240x, the layer is at 0 (-240 + 240). If the player moves to 340x, the layer is at -100 (-340 + 240). The layer moves in the exact opposite direction of the player, but taking into account the offset.

You can accomplish this in many ways. One way might be to override the player’s setPosition method to call a layer method handling the camera follow. Alternately the layer could have a method running every frame for tracking the player’s position.

The only rotation that would get screwed up is if you’re trying to rotate the background, which you haven’t really mentioned. The rotation of objects within the layer would work as normal.

April 9, 2010 at 2:50 pm #278333

donbhar
Participant
@donbhar

Thanks for the quick reply

Are you saying i should create my own camera and move it but also move the layer?

Right now i got this: ScrollLayer.position = newPosition; //Moves the layer

On another note what if i have more than 1 sprite.

But what if i have more than one sprite?

April 9, 2010 at 2:59 pm #278334

David994A
Participant
@david994a

I don’t use the camera either. For my side scroller, I use a parallax node with three layers. I then apply an action to the parallax node to move it.

As for your code example – make CCSprite *background an instance variable in your @interface section in the class header file then you will not need to use the “getChildByTag” method, instead this will expose the instance variable to all methods in your class.

April 9, 2010 at 2:59 pm #278335

Blue Ether
Participant
@blue-ether

I’m saying that by creating a mechanism for moving the layer in response to the movement of your player, you have created a “camera.” There is no “camera” object in your code, just the effect of a camera.

As long as all of the other sprites are children of the same layer, they will follow the scrolling action when the layer is moved. The best advice I can give is to start experimenting.

Also, I’m not saying that the Cocos camera isn’t a better solution. I just don’t have any experience using it, and I have found this solution to be perfectly adequate in my games.

April 9, 2010 at 3:24 pm #278336

donbhar
Participant
@donbhar

It would help if i could see or a snippet of the exact “camera mechanism code”

like i said before i have 4 menu buttons which are 4 arrows when the user presses one of those arrows the layer will move in its given direction. The code i am using to implement this at the moment is the following:

-(void)rightArrowButton:(id)sender //the right button

{

NSLog(@”right”); //just to make sure that the button tap was detected

currentPosition.x += -50;

newPosition = currentPosition;

scrollLayer.position = newPosition;

//the scroll layer which includes all the main game content

April 9, 2010 at 4:22 pm #278337

jordo
Participant
@jordo

Here’s what I did for a side scroller:

I have a ‘GameView’ singleton, which keeps position of the ‘camera’.

Everyone of my game sprites is scheduled to update it’s position based on the cameras position.

Everyone of my sprites inherits from GameSprite…



GameView.h

/** This class allows sprites to convert their world coordinates to screen coordinates using the current game view. */
@interface GameView : NSObject {

// game view
CGPoint view;

}

@property (readwrite,assign) CGPoint view;

/** returns a shared instance of the game view */
+(GameView *)instance;

@end

GameSprite.mm

@implementation GameSprite

- (id) initWithFile:(NSString*) filename {
self = [super initWithFile:filename];
if( self ) {
[self schedule: @selector(tickSprite:) interval:1.0/60.0];
}

return self;
}

-(void) tickSprite: (ccTime) dt {
if(b2body != nil) {
// set position of sprite based on position of space
// this is for my box2d bodies...
CGPoint worldPosition = cpv(b2body->GetPosition().x * PTM_RATIO, b2body->GetPosition().y * PTM_RATIO);

// find the screen position relative to the camera view.
worldPosition = cpvsub(worldPosition, [[GameView instance] view]);

[self setPosition:worldPosition];
[self setRotation:CC_RADIANS_TO_DEGREES(b2body->GetAngle() * -1)];
}
}

@end

Viewing 14 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic.