unrecognized selector sent to instance | Objective C - ios

The app crash on startup and I have this error in the console :
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[Chartboost showInterstitial]:
unrecognized selector sent to instance 0x7f844c9b74e0'
my code is :
#import "cocos2d.h"
#import "AppDelegate.h"
#import "IntroLayer.h"
#import "AppSpecificValues.h"
#import <RevMobAds/RevMobAds.h>
#import <Chartboost/Chartboost.h>
#implementation AppController
#synthesize gameCenterManager=gameCenterManager_, currentLeaderBoard=currentLeaderBoard_;
#synthesize window=window_, navController=navController_, director=director_;
#synthesize cb;
#synthesize nScore;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the main window
window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds]
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];
// [director setProjection:kCCDirectorProjection3D];
// 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 anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// If the 1st suffix is not found and if fallback is enabled then fallback suffixes are going to searched. If none is found, it will try with the name without suffix.
// On iPad HD : "-ipadhd", "-ipad", "-hd"
// On iPad : "-ipad", "-hd"
// On iPhone HD: "-hd"
CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
[sharedFileUtils setEnableFallbackSuffixes:NO]; // Default: NO. No fallback suffixes are going to be used
[sharedFileUtils setiPhoneRetinaDisplaySuffix:#"-hd"]; // Default on iPhone RetinaDisplay is "-hd"
[sharedFileUtils setiPadSuffix:#"-ipad"]; // Default on iPad is "ipad"
[sharedFileUtils setiPadRetinaDisplaySuffix:#"-ipad-hd"]; // Default on iPad RetinaDisplay is "-ipadhd"
// Assume that PVR images have premultiplied alpha
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
self.nScore = 0;
//Revmobs
[RevMobAds startSessionWithAppID:[[NSBundle mainBundle] objectForInfoDictionaryKey:#"RevMobAPI"]];
// and add the scene to the stack. The director will run it when it automatically when the view is displayed.
[director_ pushScene: [IntroLayer scene]];
[self initGameCenter];
// Create a Navigation Controller with the Director
navController_ = [[UINavigationController alloc] initWithRootViewController:director_];
navController_.navigationBarHidden = YES;
// set the Navigation Controller as the root view controller
// [window_ addSubview:navController_.view]; // Generates flicker.
[window_ setRootViewController:navController_];
// make main window visible
[window_ makeKeyAndVisible];
return YES;
}
-(void) lunchRevmobADLink
{
[[RevMobAds session] openAdLinkWithDelegate:self];
}
- (void) setUpRevMob {
[[RevMobAds session] showFullscreen];
}
-(void) launchChartboost
{
// Initialize the Chartboost library
[Chartboost startWithAppId:#"53be6ed01873dc9741aafa"
appSignature:#"fcd1715a73c97b22c5ad557323a59d7348476"
delegate:self];
// Begin a user session. This should be done once per boot
[cb startSession];
[cb cacheInterstitial];
[cb cacheMoreApps];
}
-(void) showChartboostInterestitial
{
// Show an interstitial
[[Chartboost sharedChartboost] showInterstitial];
}
-(void) showChartboostMoreApps
{
[[Chartboost sharedChartboost] showMoreApps];
}
// Supported orientations: Landscape. Customize it for your own needs
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
// getting a call, pause the game
-(void) applicationWillResignActive:(UIApplication *)application
{
if( [navController_ visibleViewController] == director_ )
[director_ pause];
}
// call got rejected
-(void) applicationDidBecomeActive:(UIApplication *)application
{
if( [navController_ visibleViewController] == director_ )
[director_ resume];
[self launchChartboost];
#ifdef FREE_VERSION
[self showChartboostInterestitial];
[self setUpRevMob];
[self hideAdBanner:YES];
#endif
}
and other code.
I tried lot of things! So I ask you now, How I can resolve this???
Thank's in advance!

According to Chartboost documentation you are not trying to show interstitial the right way :
To show a static or interstitial video ad:
// Show interstitial at location HomeScreen. See Chartboost.h for available location options.
[Chartboost showInterstitial:CBLocationHomeScreen];
The way you are doing it has been removed in their SDK 5.x
All references to [Chartboost sharedChartboost] are now changed to
Chartboost:
[[Chartboost sharedChartboost] showInterstitial:CBLocationHomeScreen]; is now [Chartboost
showInterstitial:CBLocationHomeScreen];

you are calling showInterstitial on an instance although it is a class method. it should be something like [Chartboost showInterstitial...

Related

Restricting an application to a specific orientation on IOS 5

I have an IOS application developed using Cocos2dx engine.
The application is locked for a specific orientation (for example portrait)
everything in the application seems to work fine and according to the right orientation except for the recent apps bar and notifications which are according to the device orientation.
I want to be able to restrict it so it will have the same orientation as the application itself.
I noticed that removing the landscape orientation inside the info.plist file does the job, but I want to be able to do it through code.
In IOS 6 I found that all I had to was to override referredInterfaceOrientationForPresentation in my RootViewController
and give the right orientation and this does the trick,
but this method doesn't work for IOS 5 and below.
What do I need to do to make this work on devices with IOS 5 and below?
This is the code for the RootViewController (I didn't write it, I just added the last method and I'm trying to figure out how to fix the notifications and recent apps problem)
#include "cocos2d.h"
#import "RootViewController.h"
#import "AppDelegate.h"
#import "misc/deviceOrientation.h"
#import "services/ios/ConfigurationServiceImpl.h"
#implementation RootViewController
#synthesize progressView;
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
-(NSUInteger)supportedInterfaceOrientations{
ConfigurationServiceImpl* configurationService = [ConfigurationServiceImpl instance];
if ([configurationService isLandscape])
return UIInterfaceOrientationMaskLandscape;
else
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
-(BOOL)shouldAutorotate{
return YES;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// printf("shouldAutorotateToInterfaceOrientation\n");
//
// There are 2 ways to support auto-rotation:
// - The OpenGL / cocos2d way
// - Faster, but doesn't rotate the UIKit objects
// - The ViewController way
// - A bit slower, but the UiKit objects are placed in the right place
//
#if GAME_AUTOROTATION==kGameAutorotationNone
//
// EAGLView won't be autorotated.
// Since this method should return YES in at least 1 orientation,
// we return YES only in the Portrait orientation
//
return ( interfaceOrientation == UIInterfaceOrientationPortrait );
#elif GAME_AUTOROTATION==kGameAutorotationCCDirector
//
// EAGLView will be rotated by cocos2d
//
// Sample: Autorotate only in landscape mode
//
if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {
[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeRight];
} else if( interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeLeft];
}
}
// Since this method should return YES in at least 1 orientation,
// we return YES only in the Portrait orientation
return ( interfaceOrientation == UIInterfaceOrientationPortrait );
#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
//
// EAGLView will be rotated by the UIViewController
//
// Sample: Autorotate only in landscpe mode
//
// return YES for the supported orientations
ConfigurationServiceImpl* configurationService = [ConfigurationServiceImpl instance];
return [configurationService shouldAutorotateToInterfaceOrientation: interfaceOrientation];
#else
#error Unknown value in GAME_AUTOROTATION
#endif // GAME_AUTOROTATION
// Shold not happen
return NO;
}
//This callback only will be called when GAME_AUTOROTATION == kGameAutorotationUIViewController
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
CDeviceOrientation::setDeviceOrientation(CDeviceOrientation::left);
else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
CDeviceOrientation::setDeviceOrientation(CDeviceOrientation::right);
else if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
CDeviceOrientation::setDeviceOrientation(CDeviceOrientation::down);
else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
CDeviceOrientation::setDeviceOrientation(CDeviceOrientation::up);
}
#endif // GAME_AUTOROTATION == kGameAutorotationUIViewController
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
ConfigurationServiceImpl* configurationService = [ConfigurationServiceImpl instance];
if ([configurationService isLandscape])
return UIInterfaceOrientationLandscapeRight;
else
return UIInterfaceOrientationPortrait;
}
#end
Use shouldAutorotateToInterfaceOrientation for iOS 5 and shouldAutorotate for iOS 6. In iOS5 method, use if case for your supported orientations and return YES for them. In your app summary, enable all the orientations. Hope these will help you.
I make this code skeleton for dealing with wanted & unwanted devices orientations, in my case i want to ignore the UIDeviceOrientationUnknown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown, caching the last allowed orientation. This code deals with iPhone and iPad devices and can be useful for you.
- (void)modXibFromRotation {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
NSString *device = [[UIDevice currentDevice]localizedModel];
UIInterfaceOrientation cachedOrientation = [self interfaceOrientation];
if ([device isEqualToString:#"iPad"]) {
if (orientation == UIDeviceOrientationUnknown ||
orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown) {
orientation = (UIDeviceOrientation)cachedOrientation;
}
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
/* Your code */
}
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) {
/* Your code */
}
}
if ([device isEqualToString:#"iPhone"] || [device isEqualToString:#"iPod"]) {
if (orientation == UIDeviceOrientationUnknown ||
orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown) {
orientation = (UIDeviceOrientation)cachedOrientation;
}
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
/* Your code */
}
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) {
/* Your code */
}
}
}
Yo have to call this method from two places in your view controller:
Fist begin generating device Orientation Notifications in your App delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//**** ADD THIS CODE *****
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
// Add the main view controller's view to the window and display.
self.window.rootViewController = self.mainViewController;
[self.window makeKeyAndVisible];
return YES;
}
then listen for device Orientation Notifications in your view controller:
- (void)viewDidLoad {
[notificationCent addObserver:self
selector:#selector(modXibFromRotation)
name:UIDeviceOrientationDidChangeNotification object:nil];
}
Finally call the modXibFromRotation method from:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear];
[self modXibFromRotation];
}
This will call the check orientation method before the view is shown.

ios6 autorotation portraitupsidedown to portrait

Please don't suggest me it is a bad idea to have the rotation at ios 4.3-6.0 in 1 build, because I told to many times and didn't listen to me.
At project settings I have setted all interface orientations to be supported, just to be sure.
Right now I am testing on ios6 with iphone4. Starting at app delegate it is a code, like this:
mainController = [[MainViewController alloc] initWithNibName:nil bundle:nil];
navigationController=[[RotatingNavigationController alloc] initWithRootViewController:mainController];
navigationController.navigationBar.hidden =true;
// ios: 4 and 5
//[window addSubview:navigationController.view];
//ios6:
window.rootViewController = navigationController;
[window makeKeyAndVisible];
So I did 2 custom classes, which are recommended in may cases for autorotations, and for they the problem is solved.
The RotatingNavigationController is a custom UINavigationController has a bit ugly code, but I have collected this parts from this forum, so it should be allowed to post it:
#implementation RotatingNavigationController
- (id)init {
self = [super init];
if (self) {
self.view.autoresizesSubviews = YES;
[self.view setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
}
return self;
}
// ios6 require this method for rotation detection, available from ios5, ios4.3 not available: sux
//- (void)viewWillLayoutSubviews
//{
//UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
//[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];
// [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
/*
if(UIInterfaceOrientationIsLandscape(statusBarOrientation)){
[self willRotateToInterfaceOrientation: statusBarOrientation duration: 0.3 ];
}
else{
[self willRotateToInterfaceOrientation: statusBarOrientation duration: 0.3 ];
}
*/
//}
//ios 4.3 and ios 5.0, at ios6 it isn't called by iOS...sux
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self.visibleViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
// //ios 4.3 and ios 5.0, at ios6 need different methods, which sux
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
//Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
// ios6
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
// ios6
- (BOOL)shouldAutorotate
{
return YES;
}
// ios6
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
#end
this should generate the autorotation notifications properly, I think he it does his job.
The MainViewController is a custom UIViewController.
just to be sure I have copy-pasted the code:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
// return (interfaceOrientation == UIInterfaceOrientationPortrait);
return YES;
}
// ios6:
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
// ios6
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
His job is to change the different UIViewController based on device state ( rotations )
I have somewhere a Menu screen, which has different xib, but h and m file too ( because has different elements, which doesn't appear in Portait or Landscape. ( I don't have the power to change the whole architecture )
A part of the code - and here should be some problem, I think is below in this Maincontroller:
#pragma mark
#pragma mark Rotation
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(deviceOrientation == UIDeviceOrientationFaceUp || deviceOrientation == UIDeviceOrientationFaceDown){
if(debug){
NSLog(#"Nothing to change because it is gone to Flat");
}
return;
}
NSArray *viewControllers = [self.navigationController viewControllers];
if (UIDeviceOrientationIsLandscape(deviceOrientation)){
//if(debug)
// NSLog(#"Portait -> Landscape size : %3.0fw, %3.0fh", self.view.bounds.size.width, self.view.bounds.size.height);
id lastviewController = viewControllers.lastObject;
// check what is there:
if([lastviewController isKindOfClass:[MenuController class]]){
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:menuLandscape animated:NO];
NSLog(#"poped Menu Portrait, pushed Menu Landscape");
}
...
else if(UIDeviceOrientationIsPortrait(deviceOrientation)){
//else if(UIInterfaceOrientationIsLandscape(statusBarOrientation)){
//if(debug)
// NSLog(#"Landscape -> Portait , size : %3.0fw, %3.0fh", self.view.bounds.size.width, self.view.bounds.size.height);
id lastviewController = viewControllers.lastObject;
// check what is there:
if([lastviewController isKindOfClass:[MenuLandscapeController class]]){
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:menuPortait animated:NO];
}
...
The problem is: the landscape is taken out and is pushed the portait, when is upside down, but that portait aren't rotating and it shows a broken layout.
How can I wake up that controller and tell him is time to rotate, because it isn't in portrait mode?
Thanks any suggestion related to my question of any improvement beside of architecture change.
Update:
at app delgate doesn't helped adding the:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
return UIInterfaceOrientationMaskAll;
}
code from other answer: presented here
Update2:
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
doesn't want to take the UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown value for some reason, I think that need to be solved.
Update3:
Read very carefully twice and third the ios6 release notes
The system determines whether an orientation is supported by
intersecting the value returned by the app’s
supportedInterfaceOrientationsForWindow: method with the value
returned by the supportedInterfaceOrientations method of the top-most
full-screen controller.
now read again :)
Add this category to viewcontroller which doesn't rotate
#implementation UINavigationController(Rotation)
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
#end

Seguing from inside cocos2d programmatically

I'm a beginner at cocos2d, and I'm trying to perform a segue from inside cocos2d.
Currently I set up the following function:
-(void) return_mm {
NSLog(#"returned to main menu");
UIViewController * con = self.controller;
[con performSegueWithIdentifier:#"Game2MenuSegue" sender:con];
}
to ran whenever a CCMenuItem is pressed. This actually does indeed work once. However, when I segue back into the game scene, the menu button stops working.
To be more specific, the segue is called, and the preparetosegue function is ran, but no transition happens. The other view's viewWillAppear function never runs.
I'm probably doing something stupid, so if anyone has suggestions on doing this, it would be greatly appreciated.
This is what I currently have in the game view controller's willDidAppear function.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([[CCDirector sharedDirector] isPaused]) {
[[CCDirector sharedDirector] resume];
[mainView addSubview:[[CCDirector sharedDirector] openGLView]];
return;
}
EAGLView *glview = [EAGLView viewWithFrame:self.view.bounds
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
CCDirector *director = [CCDirector sharedDirector];
//[director setDisplayStats:kCCDirectorStatsFPS];
// 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");
[window makeKeyAndVisible];
[mainView addSubview:glview];
[director setOpenGLView:glview];
CCScene *scene = [CCScene node];
GameScene * gs =[GameScene sceneWithController:self];
[gs returnFromMenu];
[scene addChild:gs];
if (director.runningScene) {
[director replaceScene:scene];
} else {
[director runWithScene:scene];
}
}
I found the problem. I saved the controller on creation, but didn't update it when it segues back into the game view. The controller was outdated so the segue didn't do anything.
I just had to add
gs.controller = self
below the call to super

cocos2d 2.0-rc2: end the director and restart

I have a cocos2d powered game that uses UIKit menues, so I only use the framework for one viewcontroller, which is the game itself. Also, it only has one scene. Since cocos2d 2.0 the director itself is a UIViewController subclass, so I just push it in my MenuViewController when the user taps a start button:
-(void)startGameButtonPressed {
CCDirectorIOS* director = (CCDirectorIOS *) [CCDirector sharedDirector];
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
self.glView = [CCGLView viewWithFrame:CGRectMake(0, 0, 480, 320)
pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
depthFormat:0 //GL_DEPTH_COMPONENT24_OES
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
// attach the openglView to the director
[director setView:glView];
[director runWithScene:[GameLayer scene]];
[director setDelegate:(id <CCDirectorDelegate>) [[UIApplication sharedApplication] delegate]];
[self.navigationController pushViewController:director animated:YES];
}
This works fine for the first time the method is called, when the user starts the first game. When the game is over, I call [[CCDirector sharedDirector] end].
Most of the director setup is done in the appDelegate (it's taken unchanged from the default Cocos2d template). I only put the CCGLView as a retained property into my MenuViewController, because otherwise the app crashes when [[CCDirector sharedDirector] end] is called and the CCGLView is not retained. I think that might be a cocos2d bug. In [[CCDirector sharedDirector] end] the framework calls [self setView:nil], but it still tries to access the view later on (probably on another thread).
The problem now is that on the second call of my method above (when the user wants to start another game from the menu), startGameButtonPressed, the director gets pushed but the screen remains black. The game is running and responding, I just don't see anything. Can someone please help me out with that?
OK, I had the same problem and I was able to "fix it".
When you set the CCGLView and [director setView:], even if you pop the controller the scene still exists. the only thing that happens is that the scene gets stopped.
So in order to have the "restart" working, you have to check if there is already a running scene (even if it's stopped, and instead of runWithScene: you use replaceScene:.
Here is my code so you can see:
- (void)setupCocos2D {
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];
// HERE YOU CHECK TO SEE IF THERE IS A SCENE RUNNING IN THE DIRECTOR ALREADY
if(![director_ runningScene]){
[director_ setView:glView]; // SET THE DIRECTOR VIEW
if( ! [director_ enableRetinaDisplay:YES] ) // ENABLE RETINA
CCLOG(#"Retina Display Not supported");
[director_ runWithScene:[HelloWorldLayer scene]]; // RUN THE SCENE
} else {
// THERE IS A SCENE, START SINCE IT WAS STOPPED AND REPLACE TO RESTART
[director_ startAnimation];
[director_ replaceScene:[HelloWorldLayer scene]];
}
[director_ setDelegate:(id <CCDirectorDelegate>) [[UIApplication sharedApplication] delegate]];
// I DO NOT PUSH BECAUSE I ALREADY PUSHED TO THIS CONTROLLER, SO I ADD THE COCOS2D VIEW AS A SUBVIEW
[self.view addSubview:[director_ view]];
}
Hope this code will help you, because I spent a whole day trying to figure this out.
It may not be the correct way or even the prettiest way, but it's working :)
EDIT:
Also, please not that if you POP the COCOS2D scene, you don't have to [[CCDirector sharedDirector] end] as the animation will be stopped when the view is dealloc/removed.
I have spent several days looking for information relating to this, and will share with you my own experience. I am also trying to create a game that loads into a UITableViewController, from which the CCDirector is loaded when a cell is touched. This is a Game Center turn-based game, hence the design (think Words With Friends). The best approach I have found so far for this is as follows (note I'm working in 2.0 - where CCDirector is a UIViewController subclass):
In AppDelegate.h, create a new ivar to hold the CCGLView that is created from the template code. Then assign the CCGLView created in didFinishLaunching to your new ivar. This allows the director to reuse the originally created view instead of trying to recreate it every time you reload the CCDirector, which seems to cause all sorts of weird issues in my experience.
You also want to create a new method in AppDelegate called -setupDirector or something of the like where you will, well, setup the director. This should be called each time you are recreating the CCDirector. I have posted my version below. Note my ivar for the CCGLView is called "GLView".
- (void)setupDirector {
if (![CCDirector sharedDirector]) {
CCLOG(#"Calling setupDirector");
director_ = (CCDirectorIOS*) [CCDirector sharedDirector];
director_.wantsFullScreenLayout = YES;
// Display FSP and SPF
[director_ setDisplayStats:NO];
// 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];
// [director setProjection:kCCDirectorProjection3D];
// 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 anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// If the 1st suffix is not found and if fallback is enabled then fallback suffixes are going to searched. If none is found, it will try with the name without suffix.
// On iPad HD : "-ipadhd", "-ipad", "-hd"
// On iPad : "-ipad", "-hd"
// On iPhone HD: "-hd"
CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
[sharedFileUtils setEnableFallbackSuffixes:NO]; // Default: NO. No fallback suffixes are going to be used
[sharedFileUtils setiPhoneRetinaDisplaySuffix:#"-hd"]; // Default on iPhone RetinaDisplay is "-hd"
[sharedFileUtils setiPadSuffix:#"-ipad"]; // Default on iPad is "ipad"
[sharedFileUtils setiPadRetinaDisplaySuffix:#"-ipadhd"]; // Default on iPad RetinaDisplay is "-ipadhd"
// Assume that PVR images have premultiplied alpha
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
}
In addition, you will want to make a couple changes to the way the template loads up the view controllers. Normally, cocos2D sets up the navigation controller with director_ as the root view controller. Here, you want to alloc and init your menu view controller and add THAT instead of director_:
// Create a Navigation Controller with the Director
gamesTVC_ = [[GamesTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
navController_ = [[UINavigationController alloc] initWithRootViewController:gamesTVC_];
navController_.navigationBarHidden = NO;
Everything else in didFinishLaunching can remain the same. Now, in your menuViewController in your startGameButtonPressed method, you will call the newly created setupDirector method on your app instance, which is referenced by calling:
AppController *app = (AppController *)[[UIApplication sharedApplication] delegate];
if ([CCDirector sharedDirector].runningScene) {
[[CCDirectorIOS sharedDirector] end];
}
[app setupDirector];
[app.navController pushViewController:app.director animated:YES];
I include a check to make sure the CCDirector isn't still running, and if it is, end it. In your game layer, when the time comes that you want to pop the view controller, you will simply call it like so:
AppController *app = (AppController *)[[UIApplication sharedApplication] delegate];
[app.navController popViewControllerAnimated:YES];
[[CCDirector sharedDirector] end];
This flow should allow you to freely use a navigation controller to push your game scene with CCDirector, and pop that view controller when you want to go back to your UIKit-based main menu. I hope this helps, as I have spent a lot of frustrating time trying to get this right for my own game.
What works well is to just call startAnimation and stopAnimation in the director but keep the cocos2d view around and just re-use it.
Any attempts to shut down cocos2d and its OpenGL view and re-initializing it later on will cause more or less issues, because it really hasn't been tested well enough. Other than that cocos2d works just fine with UIKit, it just has the same issues any other OpenGL ES app has when mixing it with UIKit views.
In my experience, Cocos doesn't really support ending and resuming, it acts like it's done and pretty much shuts itself down.
There are two things you can try, the first one (and it just came to my mind) is to call CC_DIRECTOR_INIT (may not be the exact name) after the director ended, and before you want to start it again.
The second one is to edit the director source code, and modify the end method so that it leaves cocos in a usable state (stop it from releasing the view and purging the cache, etc). Alternatively to this, you can modify the start method so that it makes sure Cocos is in a usable state before starting.
Sadly, Cocos doesn't make it easy for us to use UIKit+Cocos, but with luck with it.

Window turns black in OpenGL

Hi I'm very new to ios and OpenGL. I'm trying to follow the instructions from the book iPhone 3d programming. I just want to render a grey screen from OpenGL.
I really don't know what I've done wrong, and I need to understand why I don't get my OpenGL window right before I can venture forth.
If I can help any further just post a comment :)
GLView.h:
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#interface GLView : UIView {
// Protected fields
EAGLContext* m_context;
}
// public fields
-(void)drawWiew;
#end
GLView.mm:
#import "GLView.h"
#implementation GLView
+(Class) layerClass {
return [CAEAGLLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
eaglLayer.opaque = YES;
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
[self release];
return nil;
}
// Initialization code
GLuint framebuffer, renderbuffer;
glGenFramebuffersOES(1, &framebuffer);
glGenRenderbuffersOES(1, &renderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, renderbuffer);
[m_context
renderbufferStorage:GL_RENDERBUFFER_OES
fromDrawable:eaglLayer];
glFramebufferRenderbufferOES(
GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES, renderbuffer);
glViewport(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));
[self drawWiew];
}
return self;
}
-(void)drawWiew {
glClearColor(0.5f, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT);
[m_context presentRenderbuffer:GL_RENDERBUFFER_OES];
NSLog(#"drawView called");
}
-(void)dealloc {
if ([EAGLContext currentContext] == m_context)
[EAGLContext setCurrentContext:nil];
[m_context release];
[super dealloc];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
HellowArrowAppDelegate.h:
#import <UIKit/UIKit.h>
#import "GLView.h"
#interface HelloArrowAppDelegate : UIResponder <UIApplicationDelegate> {
UIWindow* window;
GLView* view;
}
#property (strong, nonatomic) UIWindow *window;
#end
HellowArrowAppDelegate.mm:
#import "HelloArrowAppDelegate.h"
#implementation HelloArrowAppDelegate
#synthesize window = _window;
- (void)dealloc
{
[_window release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
_window = [[UIWindow alloc] initWithFrame:screenBounds];
view = [[GLView alloc] initWithFrame:screenBounds];
[_window addSubview:view];
[_window makeKeyWindow];
// self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// // Override point for customization after application launch.
// self.window.backgroundColor = [UIColor whiteColor];
// [self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
#end
OpenGL screens can turn black depending upon the version of the OS used, as well as the size of the screen window being drawn into. For instance, code that runs fine on 4.0, 4.1, and 4.3 can show up black in 4.2. Or if you double the size of the OpenGL window it works. Sometimes the firmware gets in the way--try messing around with using a newer version of the OS, and see if it works better.

Resources