My iOS game is using Game Center.
I am authenticating via the following code:
GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController* viewController, NSError* error) {
if (viewController != nil) { [self.window.rootViewController presentViewController:viewController animated:YES completion:nil]; }
else {
if ([GKLocalPlayer localPlayer].authenticated) {
// code for Game Center enabled
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:getLeaderboardIdentifier]; }
else {
// code for Game Center disabled
}
} // viewController was nil
}; // localPlayer.authenticateHandler
It all works well, but when the game has been in the background for some time and gets restarted, the annoying "welcome back banner" is displayed even though I am not calling the previous code as I have checked that ([GKLocalPlayer localPlayer].authenticated == YES)...
Is there a way to know if this banner is going to appear that I could use in applicationWillEnterForeground?
At worse, is there a known background delay that triggers it?
In this case I would slightly delay resuming into the game for a better UX...
As there does not seem to be a way to know in advance for sure if the "Welcome Back" banner is going to be displayed when localPlayer is already authenticated, I will for now stick with the background delay trick.
I have done a dichotomic test by playing the game, leaving the App in the background and returning to the App after delay D.
It seems that the "Welcome Back" banner does not appear if D < 8 minutes and does if D is greater. If that may help others in improving their user experience...
In my case, if D >= 8 minutes when applicationWillEnterForeground, I disable the resume game button for 2.5 seconds. Most of the time, the "Welcome Back" banner appears during that lapse and doesn't bother the user while a tough game is restarting.
Related
I am currently making an iOS game using sprite kit. In one of my SKScenes, my store scene, the user can watch an AdColony ad. The ad plays fine, but after it is finished, the store scene is deallocated and the app returns to the menu screen. Why is this happening, and how can I return to the store scene without deallocating it?
Edit: Here's my code
//User taps a button (really a skspritenode)
//UIAlertView pops up asking them to watch a video
alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//User tapped button 1 (aka agreed to watch video)
if (buttonIndex == 1){
//Present video
[AdColony playVideoAdForZone:#"xxxxxxxxxxxxxxxxxxxx" withDelegate:self];
}];
}
I am trying to integrate Game Centre to my Sprite Kit game. I am referring to this link:
http://www.appcoda.com/ios-game-kit-framework/
I have created a record on my iTunes Connect account for the game I am building. I try connecting to the Game Centre in the Simulator by trying to login through the Game Centre App itself and it gives me this error:
Could not Connect to the Game Center Server
And if I try to login through settings > Game Center, I get an error saying:
Unable to connect to server,
The network connection was lost
When I open my game, I have code written which checks if there is an authenticated user or not, and if not, it shows up the login to game centre scene. It showed this a couple of times but I canceled it because I kept getting the first error. Now that screen doesn't even show up.
What am I doing wrong?
PS: I have Game Centre enabled in my game in the capabilities menu.
EDIT:
This is in my viewController.m:
-(void)authenticateLocalPlayer {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
gameCenterEnabled = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
gameCenterEnabled = NO;
}
}
};
}
I call it in the viewDidLoad of my viewController.m
Issue might be with your device and not your code. Try these steps:
Press and hold the Sleep/Wake button and the Home button together for at least ten seconds, until the Apple logo appears.
If that doesn't help, tap Settings -> General -> Reset -> Reset Network Settings.
You will have to re-enter your WiFi password.
Also confirm your device Apple ID matches your developer ID.
I have an iOS Application which will load a particular view controller for authentication. However no matter what, the view controller will not load. Below is the code for my method which handles this (This is for a Game Center authentication popup):
-(void)authenticateLocalUser {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
if (viewController != nil) {
NSLog(#"AUTH VIEW CONTROLLER");
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:viewController animated:YES completion:nil];
}
else if (localPlayer.isAuthenticated) {
NSLog(#"User is authenticated");
}
else {
NSLog(#"Game Center Auth error.");
}
};
}
As you can see, I have followed the official Apple developer documentation. However the output of this method is always:
Game Center Auth Error (Last NSLog).
Why doesn't the view controller ever load? Because I need it to load so that the user can login to Game Center if they haven't done so already.
Thanks for your time, Dan.
It turned out that the issue in the end was to do with the Game Center app itself. I just logged in/out of that and it all worked. I have also now seen this same issue replicated in other iOS apps too which use Game Center.
I have an app that uses GameCenter in a very simple way (just a simple leaderboard with an all time high score). Sometimes when I switch to my app I'll see the notification saying "welcome back to Game Center" but sometimes this notification appears squished like in the following image:
http://i.imgur.com/KOCFIJo.jpg
Does anybody know what might the causing this? Because I have absolutely no idea.
My authentication code which generates the notification banner is fairly standard.
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[GKLocalPlayer localPlayer].authenticateHandler = ^(UIViewController *viewController, NSError *error) {
// If there is an error, do not assume local player is not authenticated.
if (localPlayer.isAuthenticated) {
// Enable Game Center Functionality
self.gameCenterAuthenticationComplete = YES;
[self enableGameCenter:YES];
gameCenterButton.enabled=true;
} else {
NSLog(#"game center not logged in");
// User has logged out of Game Center or can not login to Game Center, your app should run
// without GameCenter support or user interface.
self.gameCenterAuthenticationComplete = NO;
[self enableGameCenter:NO];
[self presentViewController:viewController animated:true completion:nil ];
gameCenterButton.enabled=false;
}
};
One additional piece of information is that my app is in portrait orientation when this problem occurs. It seems like if I rotate my phone 90 degrees while the banner is showing, it will look normally in landscape but in portrait it looks all squished. Does this help explain it?
I figured it out. I hadn't implemented preferredInterfaceOrientationForPresentation so I did that
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
And also I made sure that supportedInterfaceOrientations returend UIInterfaceOrientationMaskPortrait (note that it returns UIInterfaceOrientationMASKPortrait not just UIInterfaceOrientationPortrait). After that everything worked fine.
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
According to Apple's Game Center programming guide, this code sets up an authentication handler. If you run this at the beginning of your game, the first time you run it, it will prompt the user to log in if they haven't yet.
- (void)authenticateLocalPlayer {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
NSLog(#"Player not authenticated.");
} else if (localPlayer.isAuthenticated) {
NSLog(#"Authentication successful.");
} else {
NSLog(#"Authentication failed. Error: %#.",error);
}
};
}
Suppose that the user hasn't logged in yet, and cancels the authentication screen to play the game normally.
There is a button for playing a multiplayer match in my game. If the user presses the button, it will attempt to search for other players by presenting a GKMatchmakerViewController instance.
Since the player isn't logged in, the player will actually receive an error dialog saying that they aren't logged in. The dialog only has an OK button, which dismisses it.
If the player insists on pressing this button, the same dialog will come.
However, this is an odd behaviour. It would be more reasonable that if the player wants to play a multiplayer match but isn't logged in yet, the game will prompt the user to log in.
The above code sets up a handler, so it really isn't what I'm looking for. However, I made a breakpoint and noticed that viewController is a GKHostedAuthenticateViewController instance. I figured that maybe I could create an instance of that class and present it, which should technically be equivalent to prompting the user to log in.
However, Xcode doesn't seem to recognise that class when I write it. I'm under the impression that I'm not allowed to do this.
How can I manually prompt the user to log in to Game Center?
You can first check if the player is authenticated or not, by reading the GKLocalPlayer object.
If there is not authenticated user, you can open the game centre app. The downside with this method is that after the user authenticates through the game centre app, he is still in the game centre app and has to "switch back" to your app. When he switches back, the authentication handler you defined in your code gets triggered.
-(void)clickedOnStartGame
{
if (_signedIn)
{
//Do what you need to.
}
else if (!_signedIn)
{
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Game Center"
message:#"If Game Center is disabled try logging in through the Game Center app"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Open Game Center", nil];
[alertView show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"gamecenter:"]];
}
}
EDIT: Note, that in Apple's documentation, they say that you shouldn't be prompting the user to log in again, or show a login prompt. The automated way, (which your code already has) is supposed to be the accepted way. Showing the alert view I described above just helps the user log into game centre since you aren't supposed to force the app to show a dialogue.