In IOS, how to get leaderboard rank in Google Play Games SDK? - ios

My english is little short. I attach Google Play Games to iPhone5. Everything is fine except leaderboard rank. When I attempt to get rank from leaderboard, It always return zero.
Below is my code. What is problem?
- (void)viewDidLoad {
[super viewDidLoad];
[GPGManager sharedInstance].statusDelegate = self;
}
- (IBAction)signInWasClicked:(id)sender {
[[GPGManager sharedInstance] signInWithClientID:CLIENT_ID silently:NO];
}
- (IBAction)submitScore: (UIButton *)sender {
GPGScore* myScore = [[GPGScore alloc] initWithLeaderboardId:LEADERBOARD_ID];
[myScore submitScoreWithCompletionHandler:^(GPGScoreReport *report, NSError *error){
if (error) {
// error
NSLog(#"ERROR");
} else {
// Success. Score retern fine. score return right value but rank is not.
NSLog(#"%#, %lld", report.highScoreForLocalPlayerAllTime.formattedScore,
report.highScoreForLocalPlayerAllTime.rank);
}
}];
}
In Google developer's "Leaderboard in iOS" section, there is no mention about leaderboard rank. But in GPGScoreReport object, there is GPGScore object and in GPGScore object, score and rank value are on it.
Help me please.

GPGLeaderboard *myLeaderboard = [GPGLeaderboard leaderboardWithId:LEADERBOARD_ID];
myLeaderboard.timeScope = GPGLeaderboardTimeScopeAllTime;
GPGLocalPlayerScore* localScore = [myLeaderboard localPlayerScore];
GPGLocalPlayerRank* localRank = [localScore publicRank];
NSLog(#"Current rank : %#", localRank.formattedRank);
I didn't try this code, but according to the class references, it should work fine. Let me know whether it works or not.
Also, put that code "after" submitting your score.

Related

GKMatchmaker findMatchForRequest invite never received

I'm trying to invite nearby players to a match, but the invite is either never sent or never received.
GKMatchMaker startBrowsingForNearbyPlayersWithHandler works and returns nearby players that are on same wifi, but then I use findMatchForRequest and it returns a match without any players, and the players I try to invite never receive an invite notification. Here is my code.
I start by authenticating the local player:
GKLocalPlayer.localPlayer.authenticateHandler= ^(UIViewController *controller, NSError *error)
{
if (error)
{
NSLog(#"%s:: Error authenticating: %#", __PRETTY_FUNCTION__, error.localizedDescription);
return;
}
if(controller)
{
// User has not yet authenticated
[pViewController presentViewController:controller animated:YES completion:^(void)
{
[self lookForNearbyPlayers];
}];
return;
}
[self lookForNearbyPlayers];
};
-(void)lookForNearbyPlayers
{
if(!GKLocalPlayer.localPlayer.authenticated)
{
NSLog(#"%s:: User not authenticated", __PRETTY_FUNCTION__);
return;
}
I register my view controller as a delegate of GKLocalPlayerListener:
[GKLocalPlayer.localPlayer registerListener:self]; // self is a view controller.
// This works. My test local player which is a second device and appleID I setup shows up when this handler is called.
[GKMatchmaker.sharedMatchmaker startBrowsingForNearbyPlayersWithHandler:^(GKPlayer *player, BOOL reachable)
{
NSArray * paPlayers= [NSArray arrayWithObject:player];
_pMatchRequest= [[GKMatchRequest alloc] init];
_pMatchRequest.minPlayers= 2;
_pMatchRequest.maxPlayers= 4;
_pMatchRequest.recipients = paPlayers;
_pMatchRequest.inviteMessage = #"Join our match!";
_pMatchRequest.recipientResponseHandler = ^(GKPlayer *player, GKInviteeResponse response)
{
// This is never called.
NSLog((response == GKInviteeResponseAccepted) ? #"Player %# Accepted" : #"Player %# Declined", player.alias);
};
// This returns with a match without any players.
[GKMatchmaker.sharedMatchmaker findMatchForRequest:_pMatchRequest withCompletionHandler:^(GKMatch *match, NSError *error)
{
if(error)
{
NSLog(#"%s:: %#", __PRETTY_FUNCTION__, error.localizedDescription);
return;
}
else if(match != nil)
{
_pMatch= match;
match.delegate = self;
NSLog(#"players count= %lu", (unsigned long)_pMatch.players.count); // Always returns 0
}
}];
}
}
I have delegate methods for GKLocalPlayerListener setup, but they are never called:
- (void)player:(GKPlayer *)player didRequestMatchWithRecipients:(NSArray<GKPlayer *> *)recipientPlayers
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
Does anyone know how to get this to work without GKMatchmakerViewController and for iOS9? The only examples I can find have the deprecated -inviteHandler method.
This code is working in Swift if you know how you can convert it to Objective-C and to try it.
GKMatchmaker.sharedMatchmaker().findMatchForRequest(
request,
withCompletionHandler: {(match : GKMatch!, error: NSError!) -> Void in
NSLog("This works")
})
Based on multiple questions here on SO, Game Center seems to be getting stuck from time to time. In the best case, it returns "Game not recognized" errors. In the worst case, it just cheerfully returns nil to GC calls. Sometimes it resumes working on it's own, sometimes it doesn't. But it seems you can kickstart it again by logging into iTunesConnect and do any of the following:
Add a leaderboard
Change the default leaderboard
Add an achievement
I've added this to my debugging routine. If some aspect of GC stops working, or returns nil, I try making one of the above changes in iTunesConnect before proceeding. In my case, I get the "game not recognized" several times per week, but several others have noted the "nil return values."
I know this an older post, but I ran across it when trying to establish a connection between several app instances over the internet. I believe the part you're missing is that after registering for the listener, you need to receive the connected status with
- (void)match:(GKMatch *)match
player:(GKPlayer *)player
didChangeConnectionState:(GKPlayerConnectionState)state
{
NSLog(#">>> did change state");
if (state == GKPlayerStateConnected)
{
NSLog(#">>>> match:%# did change to Connected for player %# ",match, player.displayName);
}
else if (state == GKPlayerStateDisconnected)
{
NSLog(#">>>> match:%# disconnected for player %# ",match, player.displayName);
}
I find the match has 0 players when the completionHandler is called from findMatchForRequest:, but that I can successfully use the GKMatch and GKPlayer as returned in didChangeConnectionState:
Hope that helps someone who reads this long after the OP.

Reporting score from a different UIViewController IOS

I'm not sure what is going on.
If i report an int score from the same viewcontroller, it seems to work fine. I can send that number to the leaderboard set up in game center.
When I report an int score that is from another viewcontroller, it doesn't work. At first I thought it was because the numbers weren't in int64_t. I'm not sure if that is really the issue though.
I'm fairly new to ios programming. If this is a duplicate question, please direct me in the right direction. I really appreciate any help.
-(IBAction)report:(id)sender{
[self reportScore]; //just calling the method
}
-(void)reportScore{
GKScore *score = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier];
score.value = HighScore; //HighScore is the int I want from another viewcontroller.
[GKScore reportScores:#[score] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
I guess
GKScore *score = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier];
This line creating the object each time. And thats the reason you are getting the wrong result.
Try to create GKScore *score object only once which will be global and then access it.

GameCenter not updating leaderboard

Using the sandboxed Gamecenter.
No matter what I do the scores never appear in a leaderboard.
I am using the following code:
- (void)scoreReported: (NSError*) error {
NSLog(#"%#",[error localizedDescription]);
}
- (void)submitScore{
if(self.currentScore > 0)
{
NSLog(#"Score: %lli submitted to leaderboard %#", self.currentScore, self.currentLeaderBoard);
[gameCenterManager reportScore: self.currentScore forCategory: self.currentLeaderBoard];
}
}
And scoreReported doesnt produce an error, yet the score doesnt appear in the leaderboard. I know the category is correct as I use currentLeaderBoard in:
- (void)showLeaderboard {
NSLog(#"leaderboard = %#", self.currentLeaderBoard);
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != NULL)
{
leaderboardController.category = self.currentLeaderBoard;
//leaderboardController.category = nil;
leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated: YES];
}
}
I have tried the usual
2 different sandbox GC accounts to get the leaderboard working
Even tried 4 different GC accounts each logging in on both the simulator (iOS 6.1) and device (iOS 6.0.1)
Yet still no joy
any suggestions - or is it just that the sandboxed gamecenter is far too buggy!!! (I would raise a bug about sandbox but the apple bug reporting form has a bug in it so that doesnt work either)
Score reporting to Game Center works almost immediately for me, even in sandbox mode.
Here are the few things you can try
Make sure the the Leaderboard identifiers are correct when reporting scores (Should exactly match with "Leaderboard ID"s in iTunesConnect)
Try Deleting the test data under "Manage Game Center" section of iTunesConnect
Delete the application, launch "Game Center" application in your device and goto "Games" tab and remove your app. Reinstall the app and try reporting the score again.
Make sure [gkScore reportScoreWithCompletionHandler:^(NSError *error) doesn't return any error
For those who want to know this what I changed my submitScore method to:
- (void)submitScore {
GKScore * GCscore = [[GKScore alloc] initWithCategory:self.currentLeaderBoard];
GCscore.value = [[NSUserDefaults standardUserDefaults] integerForKey:#"NEWSCORE"];
[GCscore reportScoreWithCompletionHandler:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (error == NULL) {
NSLog(#"Score Sent");
} else {
NSLog(#"Score Failed, %#",[error localizedDescription]);
}
});
}];
}
and it worked

Odd Game Center behavior?

I'm trying to enable Game Center Leaderboard to my iPad game and I have learned that you need to post more than one score to a leaderboard for the scores to show in the default leaderboard UI.
I have two separete accounts that I used to post two different scores to the same leaderboard, but when I call loadScoresWithCompletionHandler I only get one score back (the score for the user I currently are logged in with).
Any ideas why?
GKLeaderboard *myLB = [[GKLeaderboard alloc] init];
myLB.category = #"MyLeaderboardId";
myLB.timeScope = GKLeaderboardTimeScopeAllTime;
myLB.playerScope = GKLeaderboardPlayerScopeGlobal;
myLB.range = NSMakeRange(1, 100);
[myLB loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error != nil)
{
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil)
{
for (GKScore *score in scores)
{
NSLog(#"%lld", score.value);
}
}
}];
It works fine for me. Just add scores under another account.
I've got:
scores (
"<GKScore: 0x960e3e0><0x960e3e0> player=G:1208389607 rank=1 date=2012-01-19 12:56:47 +0000 value=27 formattedValue=27 context=(null)",
"<GKScore: 0x96a1bc0><0x96a1bc0> player=G:1176161436 rank=2 date=2012-01-19 08:35:06 +0000 value=16 formattedValue=16 context=(null)"
)
And center by standard controller show same results.
thanks,

iPhone Motion - EXC BAD ACCESS

I'm beginning coding with the DeviceMotion class. After following Apple's documenation, i have the following:
- (void)viewDidLoad {
[super viewDidLoad];
myMM = [[CMMotionManager alloc] init];
myMM.deviceMotionUpdateInterval = 1.0/30.0;
theQ = [[NSOperationQueue currentQueue] retain];
motionHandler = ^ (CMDeviceMotion *motionData, NSError *error) {
if (motionData.rotationRate.z > 5.5 || motionData.rotationRate.z < -5.5) {
NSLog(#"Rotation of Z."); // Reference A
}
};
-(IBAction)toggleClick{
NSLog(#"toggle");
if(myMM.gyroAvailable){
if(myMM.deviceMotionActive){
NSLog(#"Stopping Motion Updates..");
[myMM stopDeviceMotionUpdates];
} else {
NSLog(#"Starting Motion Updates..");
[myMM startDeviceMotionUpdatesToQueue:theQ withHandler:motionHandler];
}
}
else {
NSLog(#"No motion available. Quit!");
}
This code works fine, however when I want to do any code except an NSLog (even something as simple as incrementing an integer) in place of the 'reference A', I get an EXEC Bad Access in the console.
I've looked around, and all I've found is that it's a memory leak of sorts. Does anyone know whats going on? If not, how can I figure it out? I'm pretty inexperienced with Instruments, but if I'm pointed in the right direction I'd be much appreciated.
EXC_BAD_ACCESS is an OS-level exception meaning that you are trying to access memory that doesn't belong to you. I think this has something to do with your block being local to the scope, so once it goes out of scope, it is destroyed. You need to create a copy of it on the heap.
Try this answer from the renowned Dave DeLong. Also, as with the normal Cocoa memory management rules, don't forget to release it if you've made a copy.
For example:
motionHandler = Block_copy(^ (CMDeviceMotion *motionData, NSError *error) {
if (motionData.rotationRate.z > 5.5 || motionData.rotationRate.z < -5.5) {
NSLog(#"Rotation of Z."); // Reference A
}
});
// and then later:
- (void) dealloc
{
[motionHandler release];
//and all others.
[super dealloc];
}

Resources