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.
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
I am using Facebook SDK in my game in order to post some scores on Facebook.
My code is using the Cocos2D framework so I had to add some code to enable the use of UIView.
Everything works fine except that the view appears in portrait orientation despite the fact that my nibs attributes indicate landscape, the ShouldautoRotate method returns landscape, and the app orientation is also the to landscape.
here is the code that set up the view:
// share to facebook methods
-(void)shareFacebookSelected
{
[[SimpleAudioEngine sharedEngine]stopBackgroundMusic];
[[CCDirector sharedDirector] pause];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
myViewController1 = [[HFViewController alloc] initWithNibName:#"HFViewController_iPhone" bundle:nil];
} else {
myViewController1 = [[HFViewController alloc] initWithNibName:#"HFViewController_iPad" bundle:nil];
}
UIWindow* window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES];
[[[CCDirector sharedDirector]view] removeFromSuperview];
myViewController1.view.hidden = false;
[window addSubview:myViewController1.view];
[UIView commitAnimations];
}
I also enabled a button to return to the normal cocos game and remove the UIView but upon return even my main game orientation has changed to portrait.
any ideas???
The following lines solved my problem:
#define DegreesToRadians(x) ((x) * M_PI / 180.0)
CGRect screenRect = [[UIScreen mainScreen]bounds];
myViewController1.view.transform = CGAffineTransformMakeRotation(DegreesToRadians(90));
myViewController1.view.hidden = false;
myViewController1.view.frame = screenRect;
I basically rotated the view 90 degrees, not the most elegant solution, just brute force but it works. I would still like to understand why it renders the way it does, oh well
I have an app that I want to only work with in Landscape.
For the first time ever, I'm foregoing IB and trying to set up all my views programmatically, so I'm creating a view and adding a bunch of subviews in loadView method:
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86
longitude:151.20
zoom:6];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.myLocationEnabled = YES;
self.mapView.delegate = self;
self.mapView.mapType = kGMSTypeHybrid;
self.mapView.frame = self.view.frame;
[self.view addSubview:self.mapView];
// add the toolbar
UIToolbar* toolbar = [[UIToolbar alloc] init];
toolbar.frame = CGRectMake(0, self.view.frame.size.height - 44, self.view.frame.size.width, 44);
toolbar.barStyle = UIBarStyleDefault;
NSMutableArray* items = [NSMutableArray array];
[items addObject:[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"location-arrow.png"]
style:UIBarButtonItemStyleBordered
target:self
action:#selector(locateMe:)]];
[items addObject:[[UIBarButtonItem alloc] initWithTitle:#"Tools"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(toolsButtonTapped:)]];
[toolbar setItems:items];
[self.view addSubview:toolbar];
In my project settings, I have disabled both portrait orientations. I also have this in my root view controller:
// Enforce Landscape Orientation
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
My problem is that the simulator starts in landscape mode, but all of the views are sized for portrait - so the bottom chunk of my views are below the screen and the right side of my screen is a big empty region.
I tried fixing this by switching the width and height of the application frame in the first line, but then that leaves some empty vertical room on the left edge of the screen for the status bar.
So, what's the correct way of doing what I'm trying to do?
Instead of using [[UIScreen mainScreen] applicationFrame]
try using [[[[[self view] window] rootViewController] view] bounds]
The bounds will represent the width and height correctly in Landscape orientation, because the bounds will take into account the transform (rotation) that has been applied, while the frame will not.
To see what I mean, set a breakpoint, and in the debugger print out the description of the top level view lldb> po [[[[self view] window] rootViewController] view]
You'll see that the view has a rotation transform and that its frame does not represent the dimensions of the screen in landscape, but represents the dimensions in portrait!
The long way to calculate the correct applicationFrame would be
BOOL iOS7 = NO;
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending)
iOS7 = YES;
CGRect theFrame;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
theFrame.origin = CGPointZero;
theFrame.size.width = screenBounds.size.height;
theFrame.size.height = screenBounds.size.width;
if (iOS7 == NO) {
// statusBarFrame will be CGRectZero if not visible, so this is safe
theFrame.size.height -= statusBarFrame.size.width; // because we're in landscape orientation
}
}
else {
theFrame = screenBounds;
if (iOS7 == NO) {
// statusBarFrame will be CGRectZero if not visible, so this is safe
theFrame.size.height -= statusBarFrame.size.height; // because we're in portrait orientation
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape( interfaceOrientation))
{
return YES;
}
return NO;
}
Put this code Appdelegate .M.....
Put this in current viewcontroller
// ios 5
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape( interfaceOrientation)) {
return YES;
}
return NO;
}
// ios6
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
I have a simple app that is targeting iPad and iOS 5+ only. The app is landscape-only. Now, I want to take advantage of AirPlay mirroring on the iPad 2.
I have followed all of Apple's examples/documentation I can find and can't get past this drawing problem. The secondary display doesn't draw in the correct orientation.
Below is the output I am seeing from a small test app. The blue box is just a simple UIView that should be taking up the entire screen, but is not. It seems to be drawing correctly in landscape, but the view is rotated 90 degrees. Notice how the blue extends past the margin on the bottom of the TV:
I think I need to somehow force the ViewController of the external window to correctly draw in landscape, but I don't know the proper way to do this. Any ideas?
Below are the relevant pieces code:
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(screenDidConnect:)
name:UIScreenDidConnectNotification
object:nil];
[self initScreens];
return YES;
}
- (void)screenDidConnect:(NSNotification *)note
{
[self initScreens];
}
- (void)initScreens
{
if ([[UIScreen screens] count] > 1)
{
UIScreen *screen = [[UIScreen screens] lastObject];
if (!self.secondaryWindow)
{
self.secondaryWindow = [[UIWindow alloc] initWithFrame:screen.bounds];
self.secondaryWindow.screen = screen;
self.secondaryWindow.hidden = NO;
}
if (!self.secondaryViewController)
{
self.secondaryViewController = [[CCKSecondaryViewController alloc] init];
}
self.secondaryWindow.rootViewController = self.secondaryViewController;
}
}
CCKSecondaryViewController.m: This is the rootViewController of the external window
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
view.backgroundColor = [UIColor blueColor];
self.view = view;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = #"Secondary Screen";
[label sizeToFit];
[self.view addSubview:label];
label.center = self.view.center;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
You can find the sample app here:
http://dl.dropbox.com/u/360556/AirplayTest.zip
It's displaying in portrait on the connected screen. Having your shouldAutorotateToInterfaceOrientation method always return NO should sort it out for you.