Putting two backgrounds one after the other in objective-c iphone game? - iphone

Hi I am creating an iphone game
in my game layer, I have two identical background images but I want them to go one after the other.
Once the game animal (eg a penguin) crosses the first background, I want the first background to go after the second one-- becoming a continuous background until the game is over.
I have tried everything--- for loops, while loops and such but nothing seems to work
Does anyone have an idea for how I could go about doing this?
Thank you for any help you can provide me.
this is all I have so far after many different tries
- (id) init
{
if((self = [super init]))
{
for ( int x = 0; x < 10000000; ++x)
{
CCSprite *bg = [CCSprite spriteWithFile:#"level1.png"];
[bg setPosition:ccp(160,240)];
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[bg.texture setTexParameters:&params];
[self addChild:bg z:0];
CCSprite *bg2 = [CCSprite spriteWithFile:#"level1.png"];
[bg2 setPosition:ccp(320,480)];
ccTexParams param = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[bg2.texture setTexParameters:&param];
[self addChild:bg z:0];
}

If the backgrounds are the identical you don't actually need 2 images, you can just set the texture rect position of the one and it will continuously move. If you call moveBackground on a timer or in the update method it will continually scroll.
-(void)init
{
if((self=[super init]))
{
background = [CCSprite spriteWithFile:#"background.png"];
ccTexParams params = {GL_LINEAR,GL_LINEAR,GL_REPEAT,GL_REPEAT};
[background.texture setTexParameters:&params];
[self addChild:background z:0];
}
}
-(void)moveBackground
{
// Scroll background 5 pixels to the left
int speed = 5;
background.textureRect = CGRectMake(background.textureRect.origin.x-speed,
background.textureRect.origin.y,
background.textureRect.size.width,
background.textureRect.size.height);
}

Related

How to set two different splash screen in cocos2d v3.x in ios

I'm working with the cocos2d 3.x and Xcode 5.1.1.I'm having two images image1.png and image2.png.In my game i already change the default image (splash screen) to my image(image1.png).Here i need to display image1.png for 2 seconds and the image2.png to display for next 3 seconds as a splash screen of my game...Thanks in advance..
This is how i do this (to fade in and out a logo, after the default image has been served by iOS. I have a SplashLogo class (a scene). It is my startup scene, it puts up the logo, fades it out, then replaces itself as the running scene with my game controller.
- (void)onEnter {
[super onEnter];
self.positionType = CCPositionTypePoints;
// todo : test this background seed, GL side effects, timing, etc ...
// [self performSelectorInBackground:#selector(seedGameSequencer) withObject:nil];
[self seedGameSequencer];
CCColor *color = [CCColor colorWithRed:0 green:0.f blue:0.f alpha:0.f];
CCNodeColor *black = [CCNodeColor nodeWithColor:color];
black.positionType = CCPositionTypePoints;
black.position = ccp(0, 0);
black.anchorPoint = ccp(0, 0); // bottom left
[self addChild:black];
[GESprite mediumPixelFormat];
CCSprite *logo = [CCSprite spriteWithImageNamed:#"maxPowerStudiosLogo.png"];
logo.positionType = CCPositionTypePoints;
logo.anchorPoint = ccp(.5, .5);
logo.opacity = 0;
logo.positionInPoints = ccp(black.contentSizeInPoints.width / 2, black.contentSizeInPoints.height / 2);
[GESprite defaultPixelFormat];
id fadein = [CCActionFadeIn actionWithDuration:3 * K_FADE_TIME];
id taponne = [CCActionDelay actionWithDuration:.95];
id fadeout = [CCActionFadeOut actionWithDuration:2 * K_FADE_TIME];
id swapSceneAction = [CCActionCallFunc actionWithTarget:self selector:#selector(swapScene)];
id seq = [CCActionSequence actions:fadein, taponne, fadeout, swapSceneAction, nil];
// add the label as a child to this Layer
[self addChild:logo];
[logo runAction:seq];
}
- (void)seedGameSequencer {
mainScene = [MPGameSequencer scene];
}
- (void)swapScene {
[[CCDirector sharedDirector] replaceScene:mainScene];
}
and in AppDelegate :
- (CCScene *)startScene {
// This method should return the very first scene to be run when your app starts.
return [SplashLogo scene];
}

Sprite Kit loop multi node background

I am trying to loop my background image in SK, the problem is the background is long so I split the image up into tiles that I paste together with code. I want to loop this huge background but I don't know how, the regular methods of looping backgrounds haven't worked because my background is made up of multiple nodes.
This is my method I use to render the nodes together.
- (SKNode *) createBackgroundNode
{
// 1
// Create the node
SKNode *backgroundNode = [SKNode node];
// 2
// Go through images until the entire background is built
for (int nodeCount = 0; nodeCount < 20; nodeCount++) {
// 3
NSString *backgroundImageName = [NSString stringWithFormat:#"Background%02d", nodeCount+1];
SKSpriteNode *node = [SKSpriteNode spriteNodeWithImageNamed:backgroundImageName];
// 4
node.anchorPoint = CGPointMake(0.5f, 0.0f);
node.position = CGPointMake(160.0f, nodeCount*64.0f);
// 5
backgroundNode.name =#"background";
[backgroundNode addChild:node];
}
// 6
// Return the completed background node
return backgroundNode;
}
Then Inside my update method, I use this code to move all the tiles at once by moving the background layers position in my desired direction.
[self enumerateChildNodesWithName:#"background" usingBlock: ^(SKNode *node, BOOL *stop) {
SKSpriteNode *bg = (SKSpriteNode *) node;
bg.position = CGPointMake(0.0f, -((_player.position.y - 200.0f)/10));
}];
The problem is, I can't get the size of the background layer only the position (at least I think I can't) So I have no idea how I can loop all these tiles seamlessly ?
I preferably want to do it all in one class but any helpful suggestions would be greatly appreciated!

Adding a Hud Layer to Scene Cocos2d-3

To keep it simple, what is the easiest way to make the default [ Menu ] in default HelloWorld Scene (for example) as it's own layer. Issue I'm having now is that the scene is completely black, with nothing showing up!
GameLayer node:
- (id)init
{
// Enable touch handling on scene node
self.userInteractionEnabled = YES;
self.theMap = [CCTiledMap tiledMapWithFile:#"AftermathRpg.tmx"];
self.contentSize = theMap.contentSize;
self.metaLayer = [theMap layerNamed:#"Meta"];
metaLayer.visible = NO;
CCTiledMapObjectGroup *objects = [theMap objectGroupNamed:#"mainChar"];
NSMutableDictionary *startPoint = [objects objectNamed:#"startPosition"];
int x = [[startPoint valueForKey:#"x"] intValue];
int y = [[startPoint valueForKey:#"y"] intValue];
self.mainChar = [CCSprite spriteWithImageNamed:#"mainChar.png"];
mainChar.position = ccp(x,y);
[self addChild:mainChar];
[self addChild:theMap z:-1];
[self setCenterOfScreen: mainChar.position];
return self;
}
HudLayer node
-(id)init
{
CGSize winSize = [[CCDirector sharedDirector] viewSize];
CCButton *backButton = [CCButton buttonWithTitle:#"[ Menu ]" fontName:#"Verdana-Bold" fontSize:18.0f];
backButton.position = ccp(0.85f * winSize.width, 0.95f * winSize.height);
[backButton setTarget:self selector:#selector(onBackClicked:)];
[self addChild:backButton];
return self;
}
Scene
+ (GameScene *)scene
{
return [[self alloc] init];
}
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
CGSize winSize = [CCDirector sharedDirector].viewSize;
self.gameLayer = [GameLayer node];
[self addChild:gameLayer z:-1];
//self.contentSize = self.gameLayer.contentSize;
hudLayer = [HudLayer node];
hudLayer.position = ccp(winSize.width * 0.9, winSize.height * 0.9);
[self addChild:hudLayer z:1];
return self;
}
From the OP I take that you have two issues with one being that the HUD is not static (i.e. it is moving as your map moves which you don't want) and that it is not positioning at the top of the screen.
Looking at the position issue first, your position is set to normalized. Since the scene's content size has been made to be the size of your map, which I take is larger than your screen, then this is why it is showing up at the top right of the map and not the screen. To fix this don't do normalized positioning. If you want to be able to still express the position in the 0 to 1 range, use (remove the line that sets the position type to normalized also):
CGSize winSize = [[CCDirector sharedDirector] viewSize];
backButton.position = ccp(0.85f * winSize.width, 0.95f * winSize.height);
If your map is 10,000 x 10,000 then using the normalized positioning like you are will set the button to (8,500, 9,500) rather than the top of the screen.
Looking at the static issue next, from the looks of it you have the Hello World scene that you are adding everything to right? It also looks like you are moving the Hello World scene with a call to:
[self setCenterOfScreen: player.position];
What you want to do instead is this, you first have a scene:
HelloWorldScene* scene;
And to this scene you are adding two "main" layers with one being your gameplay layers as children of a main gameplay layer and the other being your HUD layer, which for example could look something like:
GameplayLayer* gameLayer;
HudLayer* hudLayer;
[scene addChild:gameLayer];
[scene addChild:hudLayer];
When the player moves (or camera or whatever), what should be moving is the game's layer, not the root Hello World scene. Moving the root scene will move all of its children, which includes the hud. That is not what you want.
When I worked on, for example, the Goldfish Mysteries app (https://itunes.apple.com/us/app/finn-friends-mysteries/id740040227?mt=8) I had essentially layers for:
Story (comprised of multiple sub-layers like bg, characters, etc)
Text (highlighted text that plays along with the narration audio)
HUD (comprised of multiple sub-layers)
Whenever there is movement on the story level it occurs on the story layer. When the HUD appears then the text and story layers are paused recursively (i.e. them and all of their children) along with the narration audio if any is playing but the HUD layer remains untouched. Resuming consists of resuming story, text, and any playing narration. I don't remember off the top if dropping the hud moved down the story and text layers in this specific app since I don't have my iPad in front of me, but i have done apps in the past where dropping the hud shifted all other layers. In that situation and for a simple app it would be fine to move the scene since the scene would only be shifted enough to show the TOC (in this type of app for example). What you look to be doing is moving the entire scene with the player's movement, which is not what you really wanted to do by the looks of it.
Either way you want a clear separation between layers and operations that are meant to only happen on specific layers should be directed only towards those layers.
Hope this helped.
UPDATE (Edited):
Based on your new edited OP, you have a new problem that you've introduced. For the hud you shouldn't have to set the layer's position since inside the hud layer everything is already being laid out relative to the screen anyways. So what you should have instead is:
hudLayer = [HudLayer node];
[self addChild:hudLayer z:1];
The second issue is that you are not properly writing your init methods for the game and hud layer classes. The init should look like:
- (instanceType)init
{
self = [super init];
if (self)
{
// Do your init stuff...
}
return self;
}
You are never calling:
self = [super init];

Multiple sprites with same SKPhysics body object

I am building an airport simulation game using sprite kit. My layout for the game states intact before adding SKPhysics body and once SKPhysicsbody is set for nodes, my sprite nodes goes wary.
This is what I am adding to scene without SKPhysicsBody. Imagine a airport with many gates and flights standing next to the gates. That is what I am trying to achieve with below code.
#implementation MyScene
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
allPlanes = [[NSMutableArray alloc]init];
// setting gravity to 0
[[self physicsWorld] setGravity:CGVectorMake(0, 0)];
[[self physicsWorld] setContactDelegate:self];
[self setBackgroundColor:[UIColor whiteColor]];
// Below method will provide runway and other static objects that can be seen in an airport
[self setupAirport];
/* This is where I am setting up by plane sprites.This method will provide a node which is added to the scene. As you can notice, the sprites are added at specific coordinates until they fill the screen. Imagine three or four gates with flights standing by those gates. That is what I am trying to achieve with below while loop */
int xval = 20;
while (xval < kScreenWidth)
{
[self setupFlightAtPoint:xval];
xval = xval + 60;
}
}
return self;
}
Now code for methods [self setupFlightAtPoint:xPos]
-(void) setupFlightAtPoint:(CGFloat ) xPos
{
// Below code will provide a static gate like object.gateNode is of type Gate class which is a subclass of SKNode
gateNode = [[Gate node] newGate];
[gateNode setPosition:CGPointMake(xPos, kScreenHeight * 0.37)];
[self addChild:gateNode];
// Below code provide plane node and positions it near the gate object.Plane is subclass of SKNode
Plane *plane = [[Plane alloc]init];
imageNode = [plane newPlane];
imageNode.planeIdentifier = xPos;
[imageNode setPosition:CGPointMake(gateNode.frame.origin.x + 12, gateNode.frame.origin.y+15)];
[allPlanes addObject:imageNode];
[self addChild:imageNode];
}
Plane object method
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
[self addChild:spriteNode];
return self;
}
Till now everything looks fine.Please see attached image called scene1 to see what I see with above code.
Now my problem begins here when I am trying to set physics body to my plane sprites. In my "newPlane" method, I am adding below code
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
[self addChild:spriteNode];
SKPhysicsBody *planePhysics = [SKPhysicsBody bodyWithRectangleOfSize:spriteNode.frame.size];
[spriteNode setPhysicsBody:planePhysics];
[[spriteNode physicsBody] setAffectedByGravity:NO];
return self;
}
After setting Physicsbodies, my scene looks like this
only one plane sprite is seen in my scene now and I am not able to figure out why?
Try initializing and assigning the physics body before adding the sprite as child:
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
spriteNode.position = CGPointMake(100, 200);
SKPhysicsBody *planePhysics = [SKPhysicsBody bodyWithRectangleOfSize:spriteNode.frame.size];
spriteNode.physicsBody = planePhysics;
spriteNode.physicsBody.affectedByGravity = NO;
[self addChild:spriteNode];
return self;
}
I also converted the code to use dot notation, I find this easier to type and read.

Parallax Scrolling for the Endless Game background using cocos2D

I am newbie programmer in cocos2D.... I wanted to create the Endless Background using the Parallax Scrolling.. I am trying to learn the Parallax but it doesn't update with the time and sprites doesn't keep on rotating from top to bottom! The snippet i tried is as below
-(id) init
{
if((self = [super init]))
{
CGSize wSize = [CCDirector sharedDirector].winSize;
self.isTouchEnabled = YES;
CGPoint topOffset = CGPointMake(wSize.width, 0);
CGPoint midOffset = CGPointMake(wSize.width/2,0);
CGPoint downOffset = CGPointZero;
CCSprite *para1 = [CCSprite spriteWithFile:#"Default.png"];
CCSprite *para2 = [CCSprite spriteWithFile:#"Icon.png"];
CCSprite *para3 = [CCSprite spriteWithFile:#"Default.png"];
CCSprite *para4 = [CCSprite spriteWithFile:#"Icon.png"];
paraNode = [CCParallaxNode node];
[paraNode addChild:para1 z:1 parallaxRatio:CGPointMake(0.5f, 0)
positionOffset:topOffset];
[paraNode addChild:para2 z:2 parallaxRatio:CGPointMake(1, 0) positionOffset:topOffset];
[paraNode addChild:para3 z:4 parallaxRatio:CGPointMake(2, 0) positionOffset:midOffset];
[paraNode addChild:para4 z:3 parallaxRatio:CGPointMake(3, 0) positionOffset:downOffset];
[self addChild:paraNode z:0 ];
[self scheduleUpdate];
}
return self;
}
-(void) update : (ccTime) dt
{
//Need to move the Parallax Node with the repetition of the background
}
This is the Implementation file... I am stuck here for moving the contiunous moving of the background in the Horizontal or Portrait mode.
Thanks for the Help in Advance
CCParallaxNode doesn't support endless scrolling, unless you modify its code. I have an example for endless parallax scrolling in my Learn Cocos2D book. From that link you can also download the book's source code where you'll find the parallax class in chapters 6 to 8.
I have created a simple class named ParallaxManager which is capable for creating infinite parallax effect for both small sprite like small cloud
as well large layer sprite like grass.
You can find out the complete project from GitHub.