I used the code below to show the Leaderboard but all i got it the console this
cocos2d: surface size: 480x320
the code:
- (void)showLeaderboardForCategory:(NSString *)category
{
// Only execute if OS supports Game Center & player is logged in
if (hasGameCenter)
{
// Create leaderboard view w/ default Game Center style
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
// If view controller was successfully created...
if (leaderboardController != nil)
{
// Leaderboard config
leaderboardController.leaderboardDelegate = self; // The leaderboard view controller will send messages to this object
leaderboardController.category = category; // Set category here
leaderboardController.timeScope = GKLeaderboardTimeScopeAllTime; // GKLeaderboardTimeScopeToday, GKLeaderboardTimeScopeWeek, GKLeaderboardTimeScopeAllTime
// Create an additional UIViewController to attach the GKLeaderboardViewController to
myViewController = [[UIViewController alloc] init];
// Add the temporary UIViewController to the main OpenGL view
[[[CCDirector sharedDirector] openGLView] addSubview:myViewController.view];
// Tell UIViewController to present the leaderboard
[myViewController presentModalViewController:leaderboardController animated:YES];
}
}
}
Finally I called the code like this :
[[GameCenterManager sharedGameCenterManager] showLeaderboardForCategory:#"LeaderBoard"];
I found the solution I must write :
[[[[CCDirector sharedDirector] openGLView] window] addSubview:myViewController.view];
instead of :
[[[CCDirector sharedDirector] openGLView] addSubview:myViewController.view];
Related
I enabled Game Center functionality in my SpriteKit game in the ViewController. Everything works fine, but I want to show the Leaderboard in another Scene after a Button is touched. I imported everything correctly. My project crashes now after touching the 'HighScoreButton' in the Head.m file, with following Output:
'NSInvalidArgumentException', reason: '-[UIView presentScene:]: unrecognized selector sent to instance 0x7feec2ff2920'
My recent Code that doesn't work:
ViewController.h
#interface ViewController : UIViewController <GKGameCenterControllerDelegate>
- (void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard;
+ (ViewController*)defaultHelper;
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
[self authenticateLocalPlayer];
// Create and configure the scene.
SKScene * scene = [Head sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
self.canDisplayBannerAds = YES;
// Present the scene.
[skView presentScene:scene];
}
static ViewController *_sharedHelper = nil;
+ (ViewController*)defaultHelper {
// dispatch_once will ensure that the method is only called once (thread-safe)
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
_sharedHelper = [[ViewController alloc] init];
});
return _sharedHelper;
}
-(void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
if (shouldShowLeaderboard) {
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
}
else{
gcViewController.viewState = GKGameCenterViewControllerStateAchievements;
}
[self presentViewController:gcViewController animated:YES completion:nil];
}
-(void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
Head.m
if ([Node.name isEqualToString:#"HighScoreButton"]){
[[ViewController defaultHelper] showLeaderboardAndAchievements:YES];
}
I believe the problem is with the singleton initialization of your view controller (which is correct btw).
When first loaded the view controller is created "behind the scenes" (I am not sure where exactly but I'll look for it) and its view is initialized with an skView instance. (And since it is not created by you your singleton instance is not initialized and a different ViewController instance is used)
Since your defaultHelper method is not used on the first creation of your view controller you are creating a new view controller which its view is an instance of UIView and it does not comply to the SKView methods (such as setShowFPS and presentScene). And of course since you create a new view controller it is not part of the view hierarchy.
What I recommend for you is to retrieve the view controller as follows :
if ([Node.name isEqualToString:#"HighScoreButton"]){
ViewController *viewController = self.view.window.rootViewController;
[viewController showLeaderboardAndAchievements:YES];
}
I am trying to remove an iAd view from the view hierarchy. My implementation successfully removes the iAd banner from the view, but I continue to receive the following error:
Unhandled error (no delegate or delegate does not implement didFailToReceiveAdWithError:)
According to Apple documentation, removing the iAd view is reasonable in cases where the user navigates away from a screen that displays an iAd and you don't expect them to return to that screen for a while:
If the user navigates from a screen of content with a banner view to a screen that does
not have a banner view, and you expect them to be on that screen for a long period of
time, remove the banner view from the view hierarchy, set its delegate to nil and
release it before transitioning to the new screen of content. More generally, avoid
keeping a banner view around when it is invisible to the user.
So, I removed the banner view and set the delegate to nil, and this results in the banner disappearing from the view. However, I then start receiving the above mentioned error. Its not really clear how to do what Apple suggests. Here is what I have done. My use of iAd is in a class that is not a UIViewController (i.e. this is a cocos2d project). Hence, I utilize the RootViewController. In the header file of my class, I have:
RootViewController *viewController;
AppDelegate *app;
BannerViewController *bannerViewController;
In my class implementation file, I initialize the bannerViewController as follows:
app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
viewController = [(AppDelegate *)[[UIApplication sharedApplication] delegate] viewController];
bannerViewController = [[BannerViewController alloc] initWithContentViewController:viewController];
app.window.rootViewController = bannerViewController;
When I am ready to remove the iAd banner permanently, I attempt to remove the banner view from the view hierarchy and set its delegate to nil as follows:
if (bannerViewController) {
[viewController removeFromParentViewController];
bannerViewController._bannerView.delegate = nil;
[bannerViewController._bannerView removeFromSuperview];
[bannerViewController release];
bannerViewController = nil;
}
The bannerViewController is from Apples iAd Suite. The initialization and construction of the view hierarchy is as follows:
#interface BannerViewController () <ADBannerViewDelegate>
#end
#implementation BannerViewController {
ADBannerView *_bannerView;
UIViewController *_contentController; // RootViewController
}
- (instancetype)initWithContentViewController:(UIViewController *)contentController
{
self = [super init];
if (self != nil) {
// On iOS 6 ADBannerView introduces a new initializer, use it when available.
if ([ADBannerView instancesRespondToSelector:#selector(initWithAdType:)]) {
_bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
}
else {
_bannerView = [[ADBannerView alloc] init];
}
_contentController = contentController;
_bannerView.delegate = self;
}
return self;
}
- (void)loadView
{
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[contentView addSubview:_bannerView];
// Setup containment of the _contentController.
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
self.view = contentView;
}
My RootViewController handles the observers for iAd BannerViewActionNotification's.
What I have noticed is that even though I release the bannerViewController, the dealloc method is not called. Like I said, the iAd banner does disappear from the view, but the error messages keep coming. This suggests that I have not properly disconnected from iAd and continue to receive ad notifications.
So, what am I doing wrong? How should I be removing the banner view from the view hierarchy per Apple's recommendation.
I'm using Apple's code to show a GKGameCenterViewController:
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
This is the text describing the code above:
Game Center UI is Displayed by Your View Controller (iOS)
The convention used by Game Kit is for one of your view controllers to present the Game Kit view controller. Your view controller acts as a delegate to the view controller it presents so that it can be informed when the player is finished looking at the presented screen. Listing 2-1 shows most common use of this pattern, which is to show the Game Center user interface. The Game Center view controller displays many different pieces of Game Center content, so most games should offer a button that brings the player to this screen, even if the game also shows Game Center content using a custom user interface.
When I use the recommended code I get to this screen (GameCenter Challenges), which is not what I want:
I have also tried this code:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"gamecenter:"]];
By using that code, I get to the screen I expected to display:
Do I misunderstand something or am I doing something wrong? Shouldn't the first piece of code bring me to the main menu? Why won't it show the leaderboards?
UPDATE
I implemented viewState as suggested by phix23:
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
But, it still displays the same Challenges screen, despite the fact that I want /try to display the Leaderboards screen.
The GKGameCenterViewController which is available since iOS 6 can show the leaderboards, achievements and challenges of your game center enabled application.
You can change the initial view by setting the viewState of the GKGameCenterViewController. If you don't set this property it will show the default view, which is the challenges view in your case. I guess you don't have setup any leaderboards or achievements so there is nothing to be shown.
Try using this code:
-(void)showGameCentersDefaultPage {
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateDefault;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
}
If you want to begin with a specific type of GameCenter Leaderboard you can call the following method with your leaderboardID
- (void)showLeaderboard:(NSString*)leaderboardID {
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
//The next three lines are the lines of interest...
gameCenterController.viewState = GKGameCenterViewControllerStateDefault;
gameCenterController.leaderboardTimeScope = GKLeaderboardTimeScopeToday;
gameCenterController.leaderboardCategory = leaderboardID;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
}
For iOS 7.0, I use the following:
Display Leaderboard:
- (void)displayLeaderboard:(UIViewController *)viewController
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
[viewController presentViewController:gameCenterController animated:YES completion:nil];
}
}
Display Achievements:
- (void)displayAchievements:(UIViewController *)viewController
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterController animated:YES completion:nil];
}
}
Note that the view controller trying to use these functions will need to pass itself (i.e. viewController param must be set to some active view controller).
Hope this helps.
Use GKGameCenterViewController and set the view state:
//Create a leaderboard view controller
GKGameCenterViewController *leaderboardViewController = [[GKLeaderboardViewController alloc] init];
leaderboardViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
//Set the time scope (ex. All Time, This Week, Today) and the leaderboard ID
leaderboardViewController.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardViewController.leaderboardCategory = leaderboardID;
//Set the delegate so we can handle various actions including dismissal
leaderboardViewController.leaderboardDelegate = self;
//Present the view controller
[self presentViewController:leaderboardViewController animated:YES completion:nil];
This code will present a view controller that displays all of your games leaderboards (or the rankings if there is only one). You can also set properties such as which leaderboard to show, the time scope, delegate, etc. Also note that you can do a similar thing with achievements using the GKAchievementViewController.
The code that you provided in your question,
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"gamecenter:"]];
Launches the GameCenter app. This means that iOS will exit your app and switch to GameCenter. This could be confusing to the user. You should also avoid making the user leave your app. Instead, use the GKViewControllers which are presented modally inside of your app.
I'm working on integrating Ben Gottlieb's Twitter-OAuth-iPhone code into my cocos2d 0.99.5 project using this tutorial. I'm having some difficulties getting the view controller to properly load. I've never mixed cocos2d with standard Cocoa Touch UI things before and I'm a bit out of my depth.
I call the following code in my app delegate when it's time to connect to Twitter:
-(void) twitterAccountLogin
{
UIViewController *controller = nil;
if (!_engine) {
_engine = [[SA_OAuthTwitterEngine alloc] initOAuthWithDelegate: self];
_engine.consumerKey = kOAuthConsumerKey;
_engine.consumerSecret = kOAuthConsumerSecret;
controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _engine delegate: self];
}
if (controller) {
[[CCDirector sharedDirector] stopAnimation];
[viewController presentModalViewController:controller animated:YES];
[controller release];
return;
}
}
When this is called, the Twitter UIViewController is created, it animates onscreen, and then, as soon as it has finished animating (i.e. it reaches the top of the screen), it disappears. The currently running CCScene reappears, but it doesn't respond to touches. On the simulator, instead of the running scene reappearing, the screen turns black. In case it is unclear, viewController is the RootViewController recently added to cocos2d in 0.99.5.
It seems to me that the UIViewController is being created and then somehow is drawn under the running scene, but debugging has gotten me nowhere. Where have I gone wrong?
your view controller should be something like this:
[[[CCDirector sharedDirector]openGLView] addSubview: viewController.view];
[viewController presentModalViewController: controller animated:YES];
After searching for help here and on the cocos2d forums, here's what I have ended up doing.
-(void)pauseMenuButtonPressed
{
if(!paused)
{
paused = TRUE;
[[CCDirector sharedDirector] pause];
CGSize s = [[CCDirector sharedDirector] winSize];
pauseLayer = [CCColorLayer layerWithColor: ccc4(150, 150, 150, 125) width: s.width height: s.height];
pauseLayer.position = CGPointZero;
[self addChild: pauseLayer z:8];
CCMenuItem *pauseMenuItemResume =[CCMenuItemImage itemFromNormalImage:#"menuItemResumeSmall.png"
selectedImage: #"menuItemResumeSmallSelected.png"
target:self
selector:#selector(pauseMenuResumeSelected)];
CCMenuItem *pauseMenuItemMainMenu =[CCMenuItemImage itemFromNormalImage:#"menuItemMainMenuSmall.png"
selectedImage: #"menuItemMainMenuSmallSelected.png"
target:self
selector:#selector(pauseMenuExitToMainMenuSelected)];
// Create the pause menu and add the menu items to it
pauseMenu = [CCMenu menuWithItems:pauseMenuItemResume, pauseMenuItemMainMenu, nil];
// Arrange the menu items vertically
[pauseMenu alignItemsVertically];
// add the menu to the scene
[self addChild:pauseMenu z:10];
[hudButtons setIsTouchEnabled:NO];
}
}
In short, rather than pushing a new scene for a pause menu, I pause all action in the game, create a transparent layer to overlay the screen, and then display the menu on top of that. This appears to be the conventional means of handling this problem in cocos2d, at least as of 0.99.5 (which is what the game is currently running in).
Cocos2d version: v0.99.04
I'm adding Game Center to my current application and I found some code to open up the GKMatchmakerViewController. It seems to work well, except when it gets dismissed it changes the orientation in the simulator to portrait. The game only runs in landscape. I rotate the device back to landscape and all the cocos2d scenes still work fine, but if I open up an alert or peer picker, they open in portrait mode. I can open and close scenes, but they will now all display this behavior. This happens using an actual device also.
// *.h
UIViewController *tempVC;
// *.m
// Open
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 2;
request.maxPlayers = 2;
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
mmvc.matchmakerDelegate = self;
tempVC=[[UIViewController alloc] init];
[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];
[tempVC presentModalViewController: mmvc animated: YES];
// Close
[tempVC dismissModalViewControllerAnimated:YES];
[tempVC.view removeFromSuperview];
[tempVC release];
As soon as I hit the dismissModalViewControllerAnimated, that's when the simulator rotates.
Thanks in advance for any help.
I had the same problem (not using cocos2d) and I solved it by subclassing the UIViewController that the Game Center is attached to:
#interface GameCenterViewController : UIViewController
{
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation;
#end
#implementation GameCenterViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
// Does it match my screenOrientation?
if (sceneOrientation == (UIDeviceOrientation)toInterfaceOrientation)
return YES;
return NO;
}
#end
Put this in AppDelegate.m before #implementation
#interface UINavigationController (Private)
- (NSUInteger)supportedInterfaceOrientations;
- (BOOL)shouldAutorotate;
#end
#implementation UINavigationController (Private)
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotate
{
return YES;
}
#end