iAd reducing FPS? - cocos2d-iphone

Does iAd banner reduces FPS?
Indeed, since I added iAd my FSP is shit. I was 59 all game and now it's variable from 35-50 FPS.
Any ideas please because my game is almost not playable with this banner.
Thank for help.

You should implement the iAd logic in your UINavigationController subclass that was set in the appDelegate. At mine code it look like:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the main window
window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds]
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
// Enable multiple touches
[glView setMultipleTouchEnabled:YES];
director_ = (CCDirectorIOS*) [CCDirector sharedDirector];
director_.wantsFullScreenLayout = YES;
// Display FSP and SPF
[director_ setDisplayStats:YES];
// set FPS at 60
[director_ setAnimationInterval:1.0/60];
//FEW LINES LATER
// Create a Navigation Controller with the Director
navController_ = [[MyNavigationController alloc] initWithRootViewController:director_];
navController_.navigationBarHidden = YES;
[self checkDeviceType];
// setup iAds bannerView
[self setupIADs];
// for rotation and other messages
[director_ setDelegate:navController_];
// set the Navigation Controller as the root view controller
[window_ setRootViewController:navController_];
// make main window visible
[window_ makeKeyAndVisible];
return YES;
}
- (void)setupIADs {
CGSize size = [[CCDirector sharedDirector] winSize];
float bannerHeight = _isiPadRunning ? 66.0f : 50.0f;
ADAdType bannerType = _isiPadRunning ? ADAdTypeMediumRectangle : ADAdTypeBanner;
_bannerView = [[ADBannerView alloc] initWithAdType:bannerType];
_bannerView.frame = CGRectMake(0, navController_.view.frame.size.height, size.width, bannerHeight);
CGSize newBannerSize = [_bannerView sizeThatFits:CGSizeMake(size.width, bannerHeight)];
_bannerView.frame = CGRectMake(0, navController_.view.frame.size.height,
newBannerSize.width, newBannerSize.height);
_bannerView.delegate = self;
//get view
UIView *mainView = [navController_ view];
[mainView addSubview:_bannerView];
[mainView setNeedsLayout];
}
As you can see I use navController_ to place an iAd banner view. No FPS drops! :)
Please, try it out. For me it helped and I have no FPS drops or delay. Everything works great.

Related

How to take screenshot of a user defined rectangular area in cocos2d

I need to take the screenshot in my cocos2d application. I've searched a lot, even in stack overflow. Then I found the following code:
+(UIImage*) screenshotWithStartNode:(CCNode*)stNode
{
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture* renTxture =
[CCRenderTexture renderTextureWithWidth:winSize.width
height:winSize.height];
[renTxture begin];
[stNode visit];
[renTxture end];
return [renTxture getUIImage];
}
Now,
Problem: The above code gives me the entire screenshot. But I am in need of the screenshot of a custom are, such as, within a CGRect(50,50,100,200).
Can anyone please help me..? Thanks...
Wow... found out what I need. I've changed the above method like:
-(UIImage*) screenshotWithStartNode:(CCNode*)startNode
{
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [CCDirector sharedDirector].winSize;
CCRenderTexture* rtx =
[CCRenderTexture renderTextureWithWidth:winSize.width
height:winSize.height];
[rtx begin];
[startNode visit];
[rtx end];
UIImage *tempImage = [rtx getUIImage];
CGRect imageBoundary = CGRectMake(100, 100, 300, 300);
UIGraphicsBeginImageContext(imageBoundary.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-imageBoundary.origin.x, -imageBoundary.origin.y, tempImage.size.width, tempImage.size.height);
// clip to the bounds of the image context
CGContextClipToRect(context, CGRectMake(0, 0, imageBoundary.size.width, imageBoundary.size.height));
// draw image
[tempImage drawInRect:drawRect];
// grab image
UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return subImage;
}

CCRepeatForever action stops automatically while switching scenes

I am developing a simple game app.
I am required to have two screens one on left & other on right, just like on scroll view with pagination having 2 screens to toggle between. I am detecting swipes with the help of RootViewController class and successfully swiping left and right screens.
But the problem is I have to have infinitely running rotateBy action on both screens each running this action on single sprite placed on center of screen.
I am using a main scene called SelectWorld & two are it's sub scenes.
First screen is called factory & other is called stack.
Following is my code:
Select World Screen:
#implementation SelectWorld
+(CCScene*)scene
{
CCScene* scene = [CCScene node];
SelectWorld* layer = [SelectWorld node];
[scene addChild:layer];
return scene;
}
-(id)init
{
if((self = [super init]))
{
[RootViewController singleton].swipeCallBackHandler = self;
[[RootViewController singleton] enableSwipeDetection];
factory = [[ColorfulFactory scene] retain];
stack = [[CoinsStack scene] retain];
[self addChild:factory];
isOnFactory = YES;
}
return self;
}
-(void)swipedLeft
{
if(isOnFactory)
{
[self removeAllChildrenWithCleanup:YES];
isOnFactory = NO;
CCTransitionScene* transitionalScene = [CCTransitionSlideInR transitionWithDuration:0.3 scene:stack];
[[CCDirector sharedDirector] replaceScene:transitionalScene];
}
}
-(void)swipedRight
{
if(!isOnFactory)
{
[self removeAllChildrenWithCleanup:YES];
isOnFactory = YES;
CCTransitionScene* transitionalScene = [CCTransitionSlideInL transitionWithDuration:0.3 scene:factory];
[[CCDirector sharedDirector] replaceScene:transitionalScene];
}
}
Here's the code for factory only, same goes for stack-
#implementation ColorfulFactory
+(CCScene*)scene
{
CCScene* scene = [CCScene node];
ColorfulFactory* layer = [ColorfulFactory node];
[scene addChild:layer];
return scene;
}
-(id)init
{
if((self = [super init]))
{
CGSize size = [CCDirector sharedDirector].winSize;
CCLabelTTF* info = [CCLabelTTF labelWithString:#"Colorful Factory" fontName:#"Helvetica" fontSize:35.0];
info.position = ccp(size.width/2, size.height-50);
[self addChild:info];
CCSprite* sprite = [CCSprite spriteWithFile:#"Icon.png"];
sprite.position = ccp(size.width/2, size.height/2);
[self addChild:sprite];
sprite.tag = 123;
CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:60 angle:360.0];
CCRepeatForever* repeatForever = [CCRepeatForever actionWithAction:rotateBy];
[sprite runAction:repeatForever];
repeatForever.tag = 456;
}
return self;
}
Now the problem is, in first two swipes actions are running fine, but as soon as I try to swipe more than two or three times, actions got stopped. I haven't written a single line to stop this in both the classes. I require it there running forever.
Your mistake is that you're re-using the same scene object for every scene change. You can't do that in cocos2d, you have to create a new instance of the scene object.
You should never retain a scene object, since there ought to be only one active scene at any one time (with the exception of the duration of a scene transitioning to another scene - but that's handled by cocos2d internally).
For example:
CCScene* factory = [ColorfulFactory scene];
CCTransitionScene* transitionalScene = [CCTransitionSlideInR transitionWithDuration:0.3 scene:factory];
[[CCDirector sharedDirector] replaceScene:transitionalScene];
If you need both objects in memory, make them layers (or nodes), not scenes. Don't use replaceScene but instead animate the layers with regular moveTo actions in and out of the screen.

- (BOOL)ccTouchBegan responds on simulator but not on device

I am working on a Pause screen menu for a game. After displaying the pause screen, I have the user touch the screen to hide the pause screen and resume the game. This works perfect on the simulator but doesn't work when I test on an actual device. It seems that the device doesn't respond to touches specifically for the pause menu. Every other part of the game works fine on both the simulator and device. It's weird how it does work on the simulator but not on the device. This is the code I have for the pause screen:
- (id)init {
if ((self = [super init])) {
CGSize windowSize = [[CCDirector sharedDirector] winSize];
//windowSize.height = 768.0;
//windowSize.width = 1024.0;
CCSprite *whiteScreen = [CCSprite spriteWithFile:#"OutOfTime.png"];
whiteScreen.position = ccp(windowSize.width / 2, windowSize.height / 2);
[self addChild:whiteScreen];
CCLabelTTF *touchToDismiss = [CCLabelTTF labelWithString:#"Touch screen to continue" fontName:#"Marker Felt" fontSize:30];
touchToDismiss.color = ccBLACK;
touchToDismiss.position = ccp(windowSize.width / 2, 20);
[self addChild:touchToDismiss];
}
return self;
}
- (void)onEnter {
[super onEnter];
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
}
- (void)gameOverWithScore:(NSInteger)score {
CGSize windowSize = [[CCDirector sharedDirector] winSize];
//windowSize.height = 768.0;
//windowSize.width = 1024.0;
CCLabelTTF *touchToDismiss = [CCLabelTTF labelWithString:#"Game Over" fontName:#"Marker Felt" fontSize:75];
touchToDismiss.color = ccBLACK;
touchToDismiss.position = ccp(windowSize.width / 2, windowSize.height / 2 + 40);
[self addChild:touchToDismiss];
NSString *scoreString = [NSString stringWithFormat:#"Final Score: %d", score];
CCLabelTTF *scoreLabel = [CCLabelTTF labelWithString:scoreString fontName:#"Marker Felt" fontSize:60];
scoreLabel.color = ccBLACK;
scoreLabel.position = ccp(windowSize.width / 2, (windowSize.height / 2) - 40);
[self addChild:scoreLabel];
}
- (void)setMessage:(NSString *)message {
}
- (void)dealloc {
[super dealloc];
}
- (BOOL)ccTouchBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"haha");
return YES;
}
You probably should add the following line on your init
self.isTouchEnabled = YES;
You have to do this for every CCLayer you have that has touch events.
EDIT: just noticed that your ccTouchBegan only prints a Log.
This log is easily viewed in the debug window of XCode, but in the device it is hidden from the user.
Try doing something else.

Using glScissor on a modal layer in cocos2d

I am coding a modal layer in cocos2d and I would like to use the OpenGL glScissor API call to crop the inside of a CCScrollLayer that I am using,
Basically,
Present some kind of Modal sprite
Put CCScrollLayer with assets on the modal sprite
I want to crop the CCScrollLayer so that it does not overflow the sprite.
Seems pretty simple.
The problem I'm having is that the visit function never seems to be get hit and thus glScissor never gets implemented.
I'm not sure what I'm doing wrong.
The way I do modals is I use blocks to handle a Yes and No condition/state.
// This appears in my "Pick City scene"
-(id) init
{
if ((self = [super init]))
{
NSLog(#"City list");
for (City *cityObj in listOfCities)
{
citySpriteOff = [CCSprite spriteWithSpriteFrameName:#"city.png"];
citySpriteOn = [CCSprite spriteWithSpriteFrameName:#"city_on.png"];
int x = [cityObj.x intValue];
int y = [cityObj.y intValue];
CCMenuItemSprite *mapMenuItem = [CCMenuItemSprite itemFromNormalSprite:citySpriteOff selectedSprite:citySpriteOn target:self selector:#selector(btnCity:)];
[mapMenuItem setTag:i];
[mapMenuItem setIsRelativeAnchorPoint:YES];
[mapMenuItem setAnchorPoint:CGPointMake(0, 0)];
[mapMenuItem setPosition:CGPointMake(x, y)];
[mapMenuItem setIsEnabled:YES];
[mapMenu addChild:mapMenuItem];
i++;
} // next
[self addChild:mapMenu z:2];
}
}
-(void) btnCity:(id)sender
{
NSLog(#"clicked a city button");
int tag = [sender tag];
City *cityObj = [listOfCities objectAtIndex:tag];
NSLog(#"You clicked on city: %#", cityObj.name);
[self lockLayers];
CCLayer *layer = [CCLayer node];
[self addChild:layer z:100];
[MapModalLayer ConfirmCity:cityObj onLayer:layer yesBlock:^{[self btnConfirmedCity:cityObj];} noBlock:^{[self unlockLayers];}];
}
-(void) btnConfirmedCity:(City *)cityObj
{
NSLog(#"confirmed city: %#", cityObj.name);
}
#pragma mark - Lock/Unlock layers
-(void) lockLayers
{
[self MenuStatus:NO Node:self];
}
-(void) unlockLayers
{
[self MenuStatus:YES Node:self];
}
// Disabled/Enable layers
-(void) MenuStatus:(BOOL)_enable Node:(id)_node
{
for (id result in ((CCNode *)_node).children) {
if ([result isKindOfClass:[CCMenu class]]) {
for (id result1 in ((CCMenu *)result).children) {
if ([result1 isKindOfClass:[CCMenuItem class]]) {
((CCMenuItem *)result1).isEnabled = _enable;
}
}
}
else
[self MenuStatus:_enable Node:result];
} // next
}
The actual modal code appears here,
#implementation MapModalLayer
- (id)init {
self = [super init];
if (self) {
// This method never seems to be called
NSLog(#"MapModalLayer init");
}
return self;
}
// This method never seems to be called
- (void) visit {
NSLog(#"Visit");
if (!self.visible)
return;
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(50, 50, 100 , 150);
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
+ (void) CloseAlert: (CCSprite*) alertDialog onCoverLayer: (CCLayer*) coverLayer executingBlock: (void(^)())block {
// shrink dialog box
[alertDialog runAction:[CCScaleTo actionWithDuration:kAnimationTime scale:0]];
// in parallel, fadeout and remove cover layer and execute block
// (note: you can't use CCFadeOut since we don't start at opacity 1!)
[coverLayer runAction:[CCSequence actions:
[CCFadeTo actionWithDuration:0.2f opacity:0],
[CCCallBlock actionWithBlock:^{
[coverLayer removeFromParentAndCleanup:YES];
if (block) block();
}],
nil]];
}
+(void) ConfirmCity:(City *)cityObj onLayer:(CCLayer *)layer yesBlock :(void (^)())yesBlock noBlock:(void (^)())noBlock
{
CCLayerColor *coverLayer = [CoverLayer new];
[layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
[coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:#"modal.png"];
[dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
[dialog setTag:kDialogTag];
//
// We put our CCScrollLayer *scroller content here... it doesn't matter what it is right now
//
//
// Finally we put our accept/reject buttons
//
// Tick/Cross buttons
CCSprite *closeButtonOn = [CCSprite spriteWithSpriteFrameName:#"btn_close.png"];
CCSprite *tickButtonOn = [CCSprite spriteWithSpriteFrameName:#"btn_accept.png"];
// add one or two buttons, as needed
CCMenuItemSprite *opt1Button = [CCMenuItemSprite itemFromNormalSprite:closeButtonOn
selectedSprite:nil
block:^(id sender){
// close alert and call opt1block when first button is pressed
[self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:noBlock];
} ];
[opt1Button setPosition:CGPointMake(-200, -120)];
// create second button, if requested
CCMenuItemSprite *opt2Button = [CCMenuItemSprite itemFromNormalSprite:tickButtonOn
selectedSprite:nil
block:^(id sender){
// close alert and call opt2block when second button is pressed
[self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:yesBlock];
} ];
[opt2Button setPosition:CGPointMake(40, -120)];
CCMenu *menu = [CCMenu menuWithItems:opt1Button, opt2Button, nil];
[menu setContentSize:dialog.contentSize];
[dialog addChild:menu z:2];
[coverLayer addChild:dialog];
}
#end
I think its because I only ever use MapModalLayer's private methods only.
But I am not sure.
Is there a way to allow me to use the glScissor in a modal like explained above?
I've tried moving the glScissor code to the display of the modal, but it never seems to do anything.
To confirm it is working, I moved the glScissor code to the parent and it seems to work fine.
Thus, how do I make the modal layer use/work with glScissor?
I have since resolved this problem.
I used the Viewport from http://pastebin.com/tWsEbxvJ
The way I did it was:
CoverLayer *coverLayer = [CoverLayer new];
[layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
[coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency
// ------------------------------
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:#"modal.png"];
[dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
[dialog setTag:kDialogTag];
.. // Build your pagesArray here for ScrollLayer...
// Now create the scroller and pass-in the pages (set widthOffset to 0 for fullscreen pages)
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:pagesArray widthOffset: 350];
[scroller setShowPagesIndicator:NO];
// finally add the scroller to your scene
//[dialog addChild:scroller];
Viewport *cn = [[Viewport alloc] initWithRect:CGRectMake(3, 0, dialog.contentSize.width-12, dialog.contentSize.height-5)];
[cn addChild:scroller];
[scroller release];
[coverLayer addChild:dialog z:1];
This allows me to put a modal on a layer, put a CCScrollLayer and make sure that the contents do not spill over the internals of the modal sprite I have made (this is why the width configuration looks a bit odd).
Thanks.

cocos2d and MPMoviePlayerController crash

I try to show an intro and replaceScene when the intro has finished. But, when the movie finish, app is crashing on [[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:0.5f scene:[MenuScene scene]]];.
code is;
- (void) moviePlayBackDidFinish {
[self.moviePlayer stop];
[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:0.5f scene:[MenuScene scene]]];
}
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
//pencere boyutu elde ediliyor
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"intro" ofType:#"mp4"]];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
if ([self.moviePlayer respondsToSelector:#selector(setFullscreen:animated:)]) {
// Use the new 3.2 style API
self.moviePlayer.controlStyle = MPMovieControlStyleNone;
self.moviePlayer.shouldAutoplay = YES;
// This does blows up in cocos2d, so we'll resize manually
// [moviePlayer setFullscreen:YES animated:YES];
[self.moviePlayer.view setTransform:CGAffineTransformMakeRotation((float)M_PI_2)];
CGSize winSize = [[CCDirector sharedDirector] winSize];
self.moviePlayer.view.frame = CGRectMake(0, 0, winSize.height, winSize.width);// width and height are swapped after rotation
[[[CCDirector sharedDirector] openGLView] addSubview:self.moviePlayer.view];
} else {
// Use the old 2.0 style API
self.moviePlayer.movieControlMode = MPMovieControlModeHidden;
[self.moviePlayer play];
}
}
return self;
}
This line:
selector:#selector(moviePlayBackDidFinish:)
should be:
selector:#selector(moviePlayBackDidFinish)
CCScene* scene = [AboutLayer scene];
CCTransitionFade* transitionScene = [CCTransitionFade transitionWithDuration:0.1 scene:scene withColor:ccWHITE];
[[CCDirector sharedDirector] pushScene:transitionScene];