cocos2d problem - layer not updating quick enough - iphone

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.

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];
}

iPhone: Application crashes when I add a layer

My applications crashes when I try to add a layer in it with CCSprite.
Here is some code I use:
CCLayer *layerPause = [CCLayer node];
CCSprite *spriteBackgroundPause = [[CCSprite alloc] initWithFile:#"BackgroundMenu.jpg"];
[layerPause addChild:spriteBackgroundPause];
[self addChild:layerPause z:27];
Here is picture also:
You have to retain the layerPause variable because it seems an autoreleased object, try in this way :
CCLayer *layerPause = [[CCLayer node] retain];
CCSprite *spriteBackgroundPause = [[CCSprite alloc] initWithFile:#"BackgroundMenu.jpg"];
[layerPause addChild:spriteBackgroundPause];
[self addChild:layerPause z:27];
Why not do it simple .. ? Like this:
CCLayer * layer = [CCLayer alloc]init];
[self addchild: layer];
CCSPrite * sprite = [CCSPrite spriteWithFile:#"ImageName.png"];
[layer addChild:sprite];

Game play at multiple layers simultaneously in cocos2d

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.

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;
}