I have an iOS app that uses UIKit for the most part, bot for two UIViewControllers, I use Cocos2D.
I set up Cocos2D like so:
#implementation CocosScreen1 {
#private
CCDirectorIOS* director;
CCScene* scene;
CCLayer* comicLayer;
UINavigationBar* navBar;
UIView* bottomOptionsBar;
CCGLView *glView;
}
-(void) setupCocos2d; {
glView = [CCGLView viewWithFrame:self.view.bounds pixelFormat:kEAGLColorFormatRGB565 depthFormat:0 preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0];
director = (CCDirectorIOS*) [CCDirector sharedDirector];
director.wantsFullScreenLayout = YES;
[director setAnimationInterval:1.0/60]; // set FPS at 60
[director setView:glView]; // attach the openglView to the director
[director setDelegate:self]; // for rotation and other messages
[director setProjection:kCCDirectorProjection2D]; // 2D projection
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
[sharedFileUtils setEnableFallbackSuffixes:NO];
[sharedFileUtils setiPhoneRetinaDisplaySuffix:#"-hd"];
[sharedFileUtils setiPadSuffix:#"-ipad"];
[sharedFileUtils setiPadRetinaDisplaySuffix:#"-ipadhd"];
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
CCScene* bottomScene = [CCScene node];
[director pushScene:bottomScene];
scene = [CCScene node];
comicLayer = [[AgComicLayer alloc] initWithOptionsView:optionsParentView withReaderScreenReference:self];
UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonSystemItemCancel target:self action:#selector(backButtonTapped)];
[self.navigationItem setBackBarButtonItem:backButton];
}
And then the two screens have this called before they appear:
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view insertSubview:director.view atIndex:0];
[[CCDirector sharedDirector] startAnimation];
[director pushScene:scene];
}
And then the two screens have this called when they disappear:
-(void) viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[CCDirector sharedDirector] pause];
[director popScene];
}
What happens is that one of the screens works perfectly fine. However, the other Cocos2D scene suffers an insane amount of framerate drop from 60 to 4. And it fails to start animations performed via the runAction method.
I need to solve the framerate issue and have the second scene resume correctly and play animation. What is wrong with my implementation? Are there best practices for what I am trying to achieve?
Resume the director. You're pausing it, but never resume. Pause means reducing the fps to 4. Since the director is a singleton pause/resume affects both views.
Related
I am loading a cocos2d game inside an Storyboard. I implemented a CocosViewController that loads the cocos2d scene (IntroLayer) and IntroLayer that starts the game. I would like to go back to CocosViewController or open a new viewcontroller when the timer (countdown) is zero in the game.
I tried calling [[CCDirector sharedDirector] popScene]; when the countdown arrives to zero and with CocosViewController *cocos = [[CocosViewController alloc] init]; [cocos.navigationController dismissViewControllerAnimated:YES completion:nil];
in onExit method but the app crashes when the countdown arrives to zero, any suggestion?
My CocosViewController set up cocos2d
-(void)setupCocos2d {
CCDirector *director = [CCDirector sharedDirector];
//[[[self navigationController] navigationBar] setHidden:YES];
if([director isViewLoaded] == NO)
{
// Create the OpenGL view that Cocos2D will render to.
CCGLView *glView = [CCGLView viewWithFrame:self.view.bounds
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
// Assign the view to the director.
director.view = glView;
// Initialize other director settings.
[director setAnimationInterval:1.0f/60.0f];
[director enableRetinaDisplay:YES];
}
// Set the view controller as the director's delegate, so we can respond to certain events.
director.delegate = self;
// Add the director as a child view controller of this view controller.
[self addChildViewController:director];
// Add the director's OpenGL view as a subview so we can see it.
[self.view addSubview:director.view];
[self.view sendSubviewToBack:director.view];
// Finish up our view controller containment responsibilities.
[director didMoveToParentViewController:self];
// Run whatever scene we'd like to run here.
NSArray *parameters = [[NSArray alloc] initWithObjects:#"3", #"sound", #"countdown", nil];
if(director.runningScene)
[director replaceScene:[IntroLayer scene];
else
[director pushScene:[IntroLayer scene];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"cocos2d controller viewdidload");
[self setupCocos2d];
}
-(void)viewDidUnload {
NSLog(#"did unload");
[[CCDirector sharedDirector] setDelegate:nil];
[[CCDirector sharedDirector] end];
}
IntroLayer creates the scene for the game. This is my onExit method:
-(void) onExit{
NSLog(#"Introscene exit");
[super onExit];
}
And this is the game. I want to load a viewcontroller when the game finished.
-(void)update:(ccTime)dt{
if (myTime > 0) {
myTime -= (float)dt;
[timeLabel setString:[NSString stringWithFormat:#"%.2f", myTime]];
} else {
myTime = 0;
[timeLabel setString:[NSString stringWithFormat:#"0.00"]];
[[CCDirector sharedDirector] popScene];
}
if (clicks < currentClicks) {
clicks = currentClicks;
//[clicksLabel setString:[NSString stringWithFormat:#"%i", clicks]];
}
}
-(void) onExit
{
[super onExit];
[[CCDirector sharedDirector] stopAnimation];
CocosViewController *cocos = [[CocosViewController alloc] init];
[cocos.navigationController dismissViewControllerAnimated:YES completion:nil];
// [cocos.navigationController popViewControllerAnimated:YES];
//AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//[app.navController popViewControllerAnimated:YES];
//dismissModalViewControllerAnimated:YES
NSLog(#"game exit");
}
For pop IntroLayer To ViewConrtroller As below code
[[[CCDirector sharedDirector] navigationController] popViewControllerAnimated:YES];
When I launch my universal app on the iPad in landscape mode, the app won't recognize taps or gestures on the side of the screen closest to the home button. I've gone over every similar question on stackoverflow trying to get to the bottom of this but I just can't get it to work.
It would appear that one of the views in the view hierarchy is in portrait rather than landscape but I can't find any views that are incorrectly sized. Also, note that the app works fine when launched in portrait mode and rotates correctly and recognizes all taps after rotation. But when launched in landscape there is always a "dead zone" on one side of the screen where taps are not recognized.
The view hierarchy looks like:
UIWindow (frame: 0, 0, 1024, 768)
UINavigationController
UIViewController
UIView (frame: 0, 0, 1024, 768)
GLView (frame: 0, 0, 1024, 768)
I have checked the frames and bounds for the views, sets clipsToBounds = YES and changed the background colors of them to see if they are not being layed out correctly but they are all occupying the entire screen (1024x768) as intended.
I have subclassed UIWindow and overridden the sendEvent: method and it is NOT being called at all when I tap on the dead zone at the left hand side of the screen. Does this indicate where the problem might lie?
Here is my app delegate where the window is created:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the main window
CGRect windowFrame = [[UIScreen mainScreen] bounds];
if (application.statusBarOrientation == UIInterfaceOrientationLandscapeLeft || application.statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
windowFrame = CGRectMake(0, 0, windowFrame.size.height, windowFrame.size.width);
}
window_ = [[MyUIWindow alloc] initWithFrame:windowFrame];
navController_ = [[BFNavigationController alloc] init];
navController_.navigationBarHidden = YES;
// for rotation and other messages
[[CCDirector sharedDirector] setDelegate:navController_];
// set the Navigation Controller as the root view controller
[window_ setRootViewController:navController_];
bfViewController_ = [[BFViewController alloc] init];
[navController_ pushViewController:bfViewController_ animated:NO];
// make main window visible
[window_ makeKeyAndVisible];
return YES;
}
And this is the UIViewController's viewDidLoad method where the UIView is configured:
- (void)viewDidLoad
{
[super viewDidLoad];
UIWindow *mainWindow = (UIWindow*)[UIApplication sharedApplication].windows.firstObject;
self.view.frame = mainWindow.bounds;
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.view.autoresizesSubviews = YES;
self.view.clipsToBounds = YES;
[self initCocos2D];
}
And here's where the GLView is created:
- (void)initCocos2D {
UIWindow *window = [[[UIApplication sharedApplication] windows] firstObject];
CCDirector *director = (CCDirectorIOS*) [CCDirector sharedDirector];
CCGLView *glView = [CCGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
glView.clipsToBounds = YES;
[glView setMultipleTouchEnabled:YES];
director.wantsFullScreenLayout = YES;
// set FPS at 60
[director setAnimationInterval:1.0/60];
// attach the openglView to the director
[director setView:glView];
// 2D projection
[director setProjection:kCCDirectorProjection2D];
// Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change this setting at any time.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Assume that PVR images have premultiplied alpha
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
[self.view insertSubview:glView atIndex:0];
[[CCDirector sharedDirector] startAnimation];
}
The gesture recognizers are added to the glView and handled by the cocos2D game layer:
UIPanGestureRecognizer *panGestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePan:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:panGestureRecognizer];
UITapGestureRecognizer *tapGestureRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:layer action:#selector(handleTap:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:tapGestureRecognizer];
UIPinchGestureRecognizer *pinchGestureRecognizer = [[[UIPinchGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePinch:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:pinchGestureRecognizer];
This is driving me crazy; any help would be much appreciated.
I was able to solve this with the following steps:
Create the UIWindow with [UIScreen mainscreen].bounds as its frame, which will always be portrait. I was previously changing the window bounds depending on orientation which is incorrect.
Use the current status bar orientation to determine portrait/landscape and set the lowest level UIView's frame accordingly. (ie 1024x768 for landscape and 768x1024 for portrait)
Set the glView's frame to its parent UIView's bounds, NOT the window's bounds
Normally, the coco2d OpenGL view is launched from the appdelegate.
Method1: luanching from appdelegate
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Try to use CADisplayLink director
// if it fails (SDK < 3.1) use the default director
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
CCDirector *director = [CCDirector sharedDirector];
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
//
// Create the EAGLView manually
// 1. Create a RGB565 format. Alternative: RGBA8
// 2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
// attach the openglView to the director
[director setOpenGLView:glView];
but I need to able to launch the OpenGL view from a viewcontroller
so, inside my viewcontroller's viewdidload function I did this
method2: launch from viewcontroller
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.frame = CGRectMake(0, 0, 320, 480);
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
CCGLView *glView = [CCGLView viewWithFrame:CGRectMake(0,0,320,480)
pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
depthFormat:0 //GL_DEPTH_COMPONENT24_OES
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
director_ = (CCDirectorIOS*) [CCDirector sharedDirector];
director_.wantsFullScreenLayout = YES;
// Display FSP and SPF
[director_ setDisplayStats:YES];
// set FPS at 60
[director_ setAnimationInterval:1.0/60];
// attach the openglView to the director
[director_ setView:glView];
// for rotation and other messages
[director_ setDelegate:self];
// 2D projection
[director_ setProjection:kCCDirectorProjection2D];
// Run the intro Scene
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// and add the scene to the stack. The director will run it when it automatically when the view is displayed.
[director_ pushScene: [helloworld scene]];
method2 is not working I don't see any scene, nothing shows up. so the question is how to make OpenGL View present from a viewcontroller?
Have you tried as in the class reference attachInView: method?
It'be of the form
[director_ attachInView:self.view];
else you can do it by
[self.view addSubview:director_.view];
Hope this helps you.
since CCDirectorIOS inherits CCDirector class which in turn inherits uiviewcontroller class, and i am assuming you are using uinavigationcontroller, therefore just push the director_ class at the end viewdidload
[self.navigationController pushViewController:director_ animated:YES];
I've a problem with a little game application running on iPad. When I lunch the simulator iOS 5.1 with iPad retina display, the application start with my default image #x2 and after show the image go to a black screen. In normal iPad iOS 5.1 simulator run well. Xcode tell me only this:
2012-04-25 14:24:26.978 AppName[83696:10a03] cocos2d: Frame interval: 1
2012-04-25 14:24:26.980 AppName[83696:10a03] cocos2d: surface size: 1536x2048
Any idea?
Thank you
#Smamim Hossain: Same error I put my full Appdelegate.m
#import "cocos2d.h"
#import "AppDelegate.h"
#import "GameConfig.h"
#import "Intro.h"
#import "RootViewController.h"
#implementation AppDelegate
#synthesize window;
- (void) removeStartupFlicker
{
//#if GAME_AUTOROTATION == kGameAutorotationUIViewController
//#endif // GAME_AUTOROTATION == kGameAutorotationUIViewController
}
- (void) applicationDidFinishLaunching:(UIApplication*)application
[director setProjection:kCCDirectorProjection2D]
{
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
[director setProjection:kCCDirectorProjection2D]
CCDirector *director = [CCDirector sharedDirector];
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
//
// Create the EAGLView manually
// 1. Create a RGB565 format. Alternative: RGBA8
// 2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
// // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
#else
[director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];
#endif
[director setAnimationInterval:1.0/60];
[director setDisplayFPS:NO];
[director setDepthTest:NO];
// make the OpenGLView a child of the view controller
[viewController setView:glView];
// make the View Controller a child of the main window
[window addSubview: viewController.view];
[window makeKeyAndVisible];
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Removes the startup flicker
[self removeStartupFlicker];
// Run the intro Scene
[[CCDirector sharedDirector] runWithScene: [Intro scene]];
}
- (void)applicationWillResignActive:(UIApplication *)application {
[[CCDirector sharedDirector] pause];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[CCDirector sharedDirector] resume];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[CCDirector sharedDirector] purgeCachedData];
}
-(void) applicationDidEnterBackground:(UIApplication*)application {
[[CCDirector sharedDirector] stopAnimation];
}
-(void) applicationWillEnterForeground:(UIApplication*)application {
[[CCDirector sharedDirector] startAnimation];
}
- (void)applicationWillTerminate:(UIApplication *)application {
CCDirector *director = [CCDirector sharedDirector];
[[director openGLView] removeFromSuperview];
[viewController release];
[window release];
[director end];
}
- (void)applicationSignificantTimeChange:(UIApplication *)application {
[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
}
- (void)dealloc {
[[CCDirector sharedDirector] end];
[window release];
[super dealloc];
}
#end
try this line of code at
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
[director setProjection:kCCDirectorProjection2D];
hope this will fix your issue.
Unfortunately, I don't understand UIViewControllers very well, nor do I understand exactly how they mesh with cocos2d scenes. However, I am able to load a standard Game Center leaderboard view on top of my cocos2d (landscape-only) game successfully on the iPhone. But, my game is a universal app and when I try it on iPad, the Game Center view loads in portrait orientation, is about half the size it should be (fills up only one quarter of the screen), and is not centered. When I rotate the device, the Game Center view orients itself to landscape but gets really stretched out and looks like it wasn't designed for iPad in landscape view.
Does anyone have any advice?
- (void) showLeaderboard
{
if(![MyAppDelegate isGameCenterAPIAvailable])
return;
if ([GKLocalPlayer localPlayer].isAuthenticated == YES)
{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
tempVC = [[RootViewController alloc] init];
GKLeaderboardViewController *leaderboard = [[[GKLeaderboardViewController alloc] init] autorelease];
if (leaderboard != NULL)
{
leaderboard.leaderboardDelegate = self;
[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];
// Pause game
[[CCDirector sharedDirector] pause];
[tempVC presentModalViewController:leaderboard animated: NO];
leaderboard.view.transform = CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(0.0f));
[leaderboard.view setCenter:CGPointMake(screenSize.height/2, screenSize.width/2)];
leaderboard.modalPresentationStyle = UIModalPresentationCurrentContext;
}
}
}
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[tempVC dismissModalViewControllerAnimated: YES];
[tempVC.view.superview removeFromSuperview];
[tempVC release];
tempVC = nil;
// Resume game
[[CCDirector sharedDirector] resume];
}
Please take a look at Implementing iAds in Cocos2d Application.
[self.view addSubview:self.bannerView];
In this tutorial, addSubview UIView object to RootViewController.view, that is in the cocos2d application template, instead of EAGLView.