Game play at multiple layers simultaneously in cocos2d - iphone

I am using 3 CCLayers in one Scene and I want simultaneous game play on all three layers, while user will play the game by switching between these layers. I can switch between these layers easily but my scheduled methods are not being called at all
Thats how I am doing it in the init() method of my scene and the line [self schedule:#selector(gameLogic:) interval:1.0]; is not working for me
Please help me where I am getting it wrong.
layer1 = [CCLayer node];
layer2 = [CCLayer node];
layer3 = [CCLayer node];
// add layer as a child to scene
[self addChild:layer1];
[self addChild:layer2];
[layer2 setVisible:NO];
[self addChild:layer3];
[layer3 setVisible:NO];
CCLabelTTF *layer1Label = [CCLabelTTF labelWithString:#"Layer1" fontName:#"Marker Felt" fontSize:64];
CGSize size = [[CCDirector sharedDirector] winSize];
layer1Label.position = ccp( size.width /2 , size.height/2 );
[layer1 addChild: layer1Label];
CCLabelTTF *layer2Label = [CCLabelTTF labelWithString:#"Layer2" fontName:#"Marker Felt" fontSize:64];
layer2Label.position = ccp( size.width /2 , size.height/2 );
[layer2 addChild: layer2Label];
CCLabelTTF *layer3Label = [CCLabelTTF labelWithString:#"Layer3" fontName:#"Marker Felt" fontSize:64];
layer3Label.position = ccp( size.width /2 , size.height/2 );
[layer3 addChild: layer3Label];
[self schedule:#selector(gameLogic:) interval:1.0];
}
return self;
}

Ohh dear I got it set myself. The problem was nowhere in init(). [super onEnter] was missing in -(void)onEnter method. Now all my scheduled methods are doing fine.

Related

Cocos2D - Layer background color not changing

I want to integrate cocos2d in one of my view. So, I have a normal view controller(MapEditorViewController) and a view, in my view controller, (I created a IBOutlet UIView *openGLView) in which I want cocos2d to be in. In my view controller, I have a method setupCocos2D :
- (void)setupCocos2D {
CCGLView *glView = [CCGLView viewWithFrame:self.openGLView.bounds
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.openGLView insertSubview:glView atIndex:0];
[[CCDirector sharedDirector] setOpenGLView:glView];
CCScene *scene = [HelloWorldLayer scene];
[[CCDirector sharedDirector] runWithScene:scene];
}
setupCocos2D is called in viewDidLoad of the class MapEditorViewController.
I have a layer (HelloWorldLayer), which is basically the code in the tutorial of http://www.raywenderlich.com/25736/how-to-make-a-simple-iphone-game-with-cocos2d-2-x-tutorial
// Helper class method that creates a Scene with the HelloWorldLayer as the only child.
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
- (void) addMonster {
CCSprite * monster = [CCSprite spriteWithFile:#"backbutton.png"];
// Determine where to spawn the monster along the Y axis
CGSize winSize = [CCDirector sharedDirector].winSize;
int minY = monster.contentSize.height / 2;
int maxY = winSize.height - monster.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = ccp(winSize.width + monster.contentSize.width/2, actualY);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(-monster.contentSize.width/2, actualY)];
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}];
[monster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super initWithColor:ccc4(255,0,255,255)]) ) {
CGSize winSize = [CCDirector sharedDirector].winSize;
CCSprite *player = [CCSprite spriteWithFile:#"carteIntrouvable.png"];
player.position = ccp(player.contentSize.width/2, winSize.height/2);
[self addChild:player];
[self setIsTouchEnabled:YES];
[self schedule:#selector(gameLogic:) interval:1.0];
}
return self;
}
-(void)gameLogic:(ccTime)dt {
[self addMonster];
}
Now, I don't know what I'm doing wrong, the layer appears but it is black, even though I change the line initWithColor in -(id) init.
How can I change the layer's background color, because the code works if I don't integrate cocos2d with UIKit... ?
Alternative Solution: Add CCLayerColor to base layer.
-(void) onEnter
{
[super onEnter];
ccColor4B color = {255,255,0,255};
CCLayerColor *colorLayer = [CCLayerColor layerWithColor:color];
[self addChild:colorLayer z:LAST_LAYER_PLUS_1];
}

How to display the score in the game over layer in cocos2d

I've a problem when I try to show the final score in the Game Over Layer in a game in cocos2d. There's an algorithm that modify the value of my variable increment, that contains the points of the user and then the game shows them.
increment = increment + 50;
[pointLabel setString: [NSString stringWithFormat: #"Points: %i", increment]];
and then a function controls if the user has or not lives in his play
-(void)gameOver:(int)value punteggio:(id)punti{
if (value == 1) {
//WIN
}else if(value == 2){
if (life > 1) { // 1
life = life - 1;
for (CCSprite *spr in spriteLifeArray) {
if (life == spr.tag) {
[self removeChild:spr cleanup:YES];
}}}
else {
// LOSE
[...]
[[CCDirector sharedDirector] replaceScene:[GameOver node]];
}
}}
Then the GameOverLayer is called. This is the .h file
#interface GameOver : CCNode {
CGSize size;
CCLabelTTF *label1;
CCLabelTTF *label2;
CCLabelTTF *labelpnt;
CCLabelTTF *labelscore;
}
-(void)restart;
Here the .m file
#implementation GameOver
+(id) scene {
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
GameOver *layer = [GameOver node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init{
if( (self=[super init] )) {
size = [[CCDirector sharedDirector] winSize];
label1 = [CCLabelTTF labelWithString:#"Game Over" fontName:#"Marker Felt" fontSize:40];
label1.position = ccp(size.width/2 , size.height/2+20+50 );
labelpnt = [CCLabelTTF labelWithString:#"Punteggio" fontName:#"Marker Felt" fontSize:20];
labelpnt.position = ccp(size.width/2 , size.height/2+50-100 );
labelscore = [CCLabelTTF labelWithString:#"100" fontName:#"Marker Felt" fontSize:20];
[labelscore setString: [NSString stringWithFormat: #" 0 "]];
[labelscore setColor:ccc3(255, 1, 1)];
labelscore.position = ccp(size.width / 2, size.height/2+50-130);
label2 = [CCLabelTTF labelWithString:#"Ricomincia" fontName:#"Marker Felt" fontSize:25];
CCMenuItemLabel *back = [CCMenuItemLabel itemWithLabel:label2 target:self selector:#selector(restart)];
CCMenu *menu= [CCMenu menuWithItems:back, nil];
menu.position = ccp(size.width/2 , size.height/2-50+50);
[self addChild: label1];
[self addChild: labelpnt];
[self addChild: labelscore];
[self addChild: menu];
}
return self;
}
-(void) restart {
[[CCDirector sharedDirector] replaceScene:[HelloWorldLayer node]];
}
How can I show the final value of my int increment in the game over layer? How can I pass it throught the classes?
Use UserDefault. Here is code
//Save score in game screen
int highScore = 234;
[[NSUserDefaults standardUserDefaults] setInteger:12 forKey:#"HighScore"];
[[NSUserDefaults standardUserDefaults] synchronize];
//get score in game over
int highScore = [[NSUserDefaults standardUserDefaults] integerForKey:#"HighScore"];
NSString *score = [NSString stringWithFormat: #"%d", highScore];
CCLabelTTF *scoreLabel = [CCLabelTTF labelWithString:score fontName:#"Marker Felt" fontSize:40];
Hey in that Case You should take a separate layer for displaying the Score lives or whatever you want to display simultaneously.
In HUD Layer i.e Heads-Up Display class You should write some basic code to display a CCLabelBMFont to the screen that says "Your Score", “You Win” or “You Lose” and a button underneath that says “Restart”.
When the restart button is tapped, it creates a new instance of the ActionLayer switches to it.
Write a Score method scoreUpdate, this method will have the logic for the score calculation like whenever a bullet hit to monster and update it to the CCLabelBMFont label.
And then All you need to do just call that method.
Here is the one of the best tutorial for such requirement.
See

Cocos2d CCMenuItemSprite in stacked menus not working

I am trying to simulate a modal view in cocos2d by displaying a few sprites over my scene and showing a menuitemsprite as a continue button. In the code below, i show my game over modal and have the menu set up with a CCMenuItemSprite; which does not respond to touches, and a CCMenuItemImage; which does work.
-(void) gameOver {
CGSize size = [[CCDirector sharedDirector] winSize];
self.menu.isTouchEnabled = NO;
CCLayer *modalLayer = [[CCLayer alloc] init];
[self addChild:modalLayer z:20];
CCSprite *spriteGameOver = [CCSprite spriteWithFile:#"game_over.png"];
spriteGameOver.position = ccp( size.width/2,size.height/2);
CCLabelTTF *lblGameOver = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"Game Over!\nScore %d/%d",numCorrect,questionIdx] dimensions:CGSizeMake(380, 300) alignment:CCTextAlignmentCenter fontName:#"Trebuchet MS" fontSize:50.0f];
// position the label on the center of the screen
lblGameOver.position = ccp(size.width/2-200, size.height/2-100);
lblGameOver.color = ccc3(20, 20, 20);
lblGameOver.opacity = 0;
// add the label as a child to this Layer
[spriteGameOver addChild: lblGameOver];
spriteGameOver.opacity = 0;
[modalLayer addChild:spriteGameOver];
CCSprite *spriteGameOverBtn = [CCSprite spriteWithFile:#"mainButton.png" rect:CGRectMake(0,0,300,60)];
spriteGameOverBtn.position = ccp( size.width/2,size.height/2-100);
CCLabelTTF *lblGameOverBtn = [CCLabelTTF labelWithString:#"Continue" dimensions:CGSizeMake(300, 60) alignment:CCTextAlignmentCenter fontName:#"Trebuchet MS" fontSize:40.0f];
//lblGameOverBtn.position = ccp(size.width/2-200, size.height/2-300);
[lblGameOverBtn setAnchorPoint:ccp(0.0f,0.1f)];
lblGameOverBtn.color = ccc3(20, 20, 20);
lblGameOverBtn.opacity = 0;
// add the label as a child to this Layer
[spriteGameOverBtn addChild: lblGameOverBtn];
spriteGameOverBtn.opacity = 0;
CCMenuItemImage *itemH = [CCMenuItemImage itemFromNormalImage:#"backArrow.png" selectedImage:#"backArrowS.png" target:self selector:#selector(goToMain:)];
itemH.position = ccp( size.width/2,size.height/2-100);
CCMenuItemSprite *mGameOverBtn = [CCMenuItemSprite itemFromNormalSprite:spriteGameOverBtn selectedSprite:nil disabledSprite:nil target:self selector:#selector(goToMain:)];
CCMenu *menuGO = [CCMenu menuWithItems: itemH,mGameOverBtn, nil];
menuGO.position = ccp( 0, 0);
[modalLayer addChild:menuGO z:21];
[lblGameOverBtn runAction:[CCSequence actions:[CCDelayTime actionWithDuration: 1.75f],[CCFadeIn actionWithDuration: 1.75f],nil]];
[spriteGameOverBtn runAction:[CCSequence actions:[CCDelayTime actionWithDuration: 1.75f],[CCFadeIn actionWithDuration: 1.75f],[CCDelayTime actionWithDuration: 3.75f],nil]];
[lblGameOver runAction:[CCSequence actions:[CCDelayTime actionWithDuration: 1.75f],[CCFadeIn actionWithDuration: 1.75f],[CCDelayTime actionWithDuration: 3.75f],nil]];
[spriteGameOver runAction:[CCSequence actions:[CCDelayTime actionWithDuration: 1.75f],[CCFadeIn actionWithDuration: 1.75f],[CCDelayTime actionWithDuration: 3.75f],nil]];
//[self runAction:[CCSequence actions:[CCDelayTime actionWithDuration: 2.75f],[CCCallFunc actionWithTarget:self selector:#selector(goToMain:)], nil]];
}
I'm having the same problem with CCMenuItemSprite too. It looks like the CCMenuItemSprite-class is a bit buggy. In my case it doesn't respond to touches. But I found out it has something to do with multi-layered Sprites inside the CCMenuItemSprite. So when I use a single-layered Sprite it works, but when I use a Sprite which contains multiple embedded sprites it doesn't.
My 'not-ready-yet' solution right now is setting the contentSize to the appropriate size of the CCMenuItemSprite right after it has been initialized:
CCMenuItemSprite * menuItem = [CCMenuItemSprite itemWithNormalSprite:multiLayeredSprite selectedSprite:nil target:self selector:#selector(clickHandler:)];
[s setContentSize:backgroundSprite.contentSize];
CCMenu * menu = [CCMenu menuWithItems:
menuItem,
nil];
It's receiving touch-events now. The only problem I now have is the positioning of the Rectangle... it's still in the upper-right corner. I'll try to found out how to fix this now.
Hopefully this is clarifying a bit of the problem.
Have you have registered your scene with the touch dispatcher and your selectors actually do something?
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO]

Constrain CCRenderTexture to top of screen when using CCCamera - Cocos2d

i have a "mini map" that I am using to show a portion of the background.
How can I constrain the CCRenderTexure to the top right corner of the screen? I am also using CCCamera to follow a sprite.
in init()
CGSize s = [[CCDirector sharedDirector] winSize];
minimap = [[CCRenderTexture renderTextureWithWidth:s.width * 1.5 height:s.height * 1.5] retain];
[minimap setPosition:ccp( s.width - ( s.width * kMinimapScaleFactor ) - 5, s.height - ( s.height * kMinimapScaleFactor ) - 5)];
[minimap begin];
[self visit];
[minimap end];
CCSprite *mms = [minimap sprite];
[mms setScale:kMinimapScaleFactor];
mms.scaleY *= -1;
mms.anchorPoint = ccp(0, 0);
[self addChild:minimap z:1 tag:1];
[self schedule:#selector(updateMinimap:) interval:1.0f];
Above init()
#define kMinimapScaleFactor 0.2
-(void) updateMinimap: (ccTime) dt
{
[minimap begin];
[self visit];
[minimap end];
}
in .h
CCRenderTexture *minimap;
#property(nonatomic, retain) CCRenderTexture *minimap;
Here is how I use CCCamera
id cameraMove = [CCFollow actionWithTarget:_ball];
[self runAction:cameraMove];
Anyone know?
Thanks
All you have to do is add it to the scene id
+ (id)scene
{
CCScene *scene = [CCScene node];
GameScene *layer = [GameScene node];
[scene addChild:layer];
CGSize s = [[CCDirector sharedDirector] winSize];
layer.player = [CCRenderTexture renderTextureWithWidth:s.width height:s.height];
CCSprite *mms = [layer.player sprite];
[mms setScale:kMinimapScaleFactor];
mms.scaleY *= -1;
mms.position = ccp(300, 400);
[scene addChild:layer.player z:2 tag:1];
[layer schedule:#selector(updateMinimap:) interval:1/30.0f];
layer._mini = [CCSprite spriteWithFile:#"minimap.png"];
layer._mini.position = ccp(405, 255);
layer._mini.opacity = 150;
[scene addChild:layer._mini];
return scene;
}

cocos2d problem - layer not updating quick enough

i am adding overlays to a cocos2d layer in preparation for a screenshot...
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCScene* currentScene = [[CCDirector sharedDirector] runningScene];
GameLayer* topLayer = (GameLayer *)[currentScene.children objectAtIndex:0];
CCSprite *middleBackground = [CCSprite spriteWithFile:#"mid_bg.png"];
middleBackground.position = ccp(winSize.width * 0.5,winSize.height * 0.55);
[topLayer addChild:middleBackground z:3 tag:111];
CCSprite *bottomBackground = [CCSprite spriteWithFile:#"bot_bg.png"];
bottomBackground.position = ccp(winSize.width * 0.5,winSize.height * 0.1);
[topLayer addChild:bottomBackground z:3 tag:112];
CCSprite *topBackground = [CCSprite spriteWithFile:#"top_bg.png"];
topBackground.position = ccp(winSize.width * 0.5,winSize.height * 0.94);
[topLayer addChild:topBackground z:3 tag:113];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
CCSprite *topBackground2 = [CCSprite spriteWithFile:#"statusCover2.png"];
topBackground2.position = ccp(winSize.width * 0.5,winSize.height * 0.992);
[topLayer addChild:topBackground2 z:3 tag:114];
[[topLayer popoverController] dismissPopoverAnimated:YES];
then
[UIImage imageWithCGImage:UIGetScreenImage()];
However the later is not taking the overlays into account. It is taking a screenshot of the layer before the overlays are added.
Is there anyway I can tell the cocos2d scene/layer to update the frame NOW?
Because cocos2d is asynchronous you can't tell it to do something like that. However, you can schedule a callback to happen in two seconds and have that callback do the screen capture.
[self schedule: #selector(screenshot:) interval:2.0];
then define the selector like this:
-(void) screenshot:(id)sender {
[UIImage imageWithCGImage:UIGetScreenImage()];
[self unschedule:#selector(screenshot:)];
}
don't forgot to unschedule it.