Retrieve scores of two friends above GKLocalPlayer - iphone

I want to show a very small leaderboard snippet on my games front page, basically showing your score and the scores of two friends around you (above and below you're score). I have read through the apple documentation and cannot see a way to do this unless I specify all friends and specify a huge range to ensure I get all the friends, which I can then filter. It seems inefficient to retrieve this list especially as the user may be on mobile. How can I achieve what I want without downloading the entire list of friends and then filtering?
Here is what I currently have (without filtering)
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"HighScore";
leaderboardRequest.range = NSMakeRange(1,100);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
// Handle the error.
}
if (scores != nil)
{
GKScore* myScore = leaderboardRequest.localPlayerScore;
NSLog(#"Me: %#: %d",myScore.playerID, (int)myScore.value);
// Process the score information - here I would filter
for (GKScore* score in scores)
{
NSLog(#"%#: %d",score.playerID, (int)score.value);
}
}
}];
}

The following code may help you.
From Game Center Programming Guide:
GKLeaderboard range: You can pick scores within a specific range. For example, the range [1,10] returns the best ten scores found by the query.
GKScore rank: The position of the score in the results of a leaderboard search.
ps. I couldn't test it.
Best regards.
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
GKScore* myScore = leaderboardRequest.localPlayerScore;
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"HighScore";
leaderboardRequest.range = NSMakeRange(myScore.rank-1, myScore.rank+1);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
// Handle the error.
}
else
{
// ...
}
}];
}

Related

Wait until GameCenter score download id complete

I would like to download score from GameCenter, but I don't know how to wait, when score is downloaded. When I run this code, it returns null. I think, that method have to wait when [leaderboardRequest loadScoresWithCompletionHandler: ... will have score downloaded.
- (NSString*) getScore: (NSString*) leaderboardID
{
__block NSString *score = nil;
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.identifier = leaderboardID;
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil)
{
int64_t scoreInt = leaderboardRequest.localPlayerScore.value;
score = [NSString stringWithFormat:#"%lld", scoreInt];
}
}];
}
return score;
}
The code from the completion handler will be called when the operation is complete (on another thread).
You have several options there, you can store the score somewhere and post a notification to notify the main thread that the operation is completed.

iOS Gamecenter Programmatic Matchmaking

I'm trying to implement a real-time multiplayer game with a custom UI (no GKMatchMakerViewController). I'm using startBrowsingForNearbyPlayersWithReachableHandler:
^(NSString *playerID, BOOL reachable) to find a local player, and then initiating a match request with the GKMatchmaker singleton (which I have already initiated).
Here's where I'm having trouble. When I send a request, the completion handler fires almost immediately, without an error, and the match it returns has an expected player count of zero. Meanwhile, the other player definitely has not responded to the request.
Relevant code:
- (void) findMatch
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = NUM_PLAYERS_PER_MATCH; //2
request.maxPlayers = NUM_PLAYERS_PER_MATCH; //2
if (nil != self.playersToInvite)
{
// we always successfully get in this if-statement
request.playersToInvite = self.playersToInvite;
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse
response)
{
[self.delegate updateUIForPlayer: playerID accepted: (response ==
GKInviteeResponseAccepted)];
};
}
request.inviteMessage = #"Let's Play!";
[self.matchmaker findMatchForRequest:request
withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error) {
// Print the error
NSLog(#"%#", error.localizedDescription);
}
else if (match != nil)
{
self.currentMatch = match;
self.currentMatch.delegate = self;
// All players are connected
if (match.expectedPlayerCount == 0)
{
// start match
[self startMatch];
}
[self stopLookingForPlayers];
}
}];
}
Figured it out! I needed to call - (void)matchForInvite:(GKInvite *)invite completionHandler:(void (^)(GKMatch *match, NSError *error))completionHandler in my invitation handler so that both players have the same match data.

Gamer Center leaderboard shows no scores, and each user only has access to their own score

I'm trying to make a leaderboard in my game with Game Center. I post the high score like so:
GKScore *myScoreValue = [[[GKScore alloc] initWithCategory:#"grp.high_scores"] autorelease];
myScoreValue.value = self.game.scoreMeter.score;
NSLog(#"Attemping to submit score: %#", myScoreValue);
[myScoreValue reportScoreWithCompletionHandler:^(NSError *error){
if(error != nil){
NSLog(#"Score Submission Failed");
} else {
NSLog(#"Score Submitted");
id appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate displayLeaderBoard:nil];
}
}];
I see "Score Submitted" as expecting, and it brings up the Game Center leaderboard view, but it just reads "No Scores"
I know other people have said you need at least two accounts, but I've tried with three already.
For each account, the game shows up for them in the Game Center App, and when I query for the top ten scores:
- (void) retrieveTopTenScores
{
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.range = NSMakeRange(1,10);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
NSLog(#"Error grabbing top ten: %#", error);
}
if (scores != nil)
{
NSLog(#"Top ten scores: %#", scores);
}
}];
}
}
each user only sees their own score.
So why is the leaderboard empty, and why is each user only seeing their own score?
Sandbox can be messy sometimes, but let me ask you this. Is your self.game.scoreMeter.score an int?
If so, try doing this:
myScoreValue.value = [[NSNumber numberWithInt:self.game.scoreMeter.score] longLongValue];
for setting the value of the GKScore object. Let me know if it changes anything.
Well, it turns out you need to be signed in to game center with a developer sandbox account for it to work correctly

Showing Game Center high scores in UILabels

I'm making a turn based iPhone game with a maximum of 2 players, in my game You can get a score which will be put in a Game center leaderboard. The next time you start the game up your highest score will be retrieved and you can make it even higher because the app counts on from that previous highscore. I found some code to get the authenticated players score But I also wanna show the score of the opponent you are playing and I was wondering how?
This is the code I found for the authenticated player (yourself)
if([GKLocalPlayer localPlayer].authenticated) {
NSArray *arr = [[NSArray alloc] initWithObjects:[GKLocalPlayer localPlayer].playerID, nil];
GKLeaderboard *board = [[GKLeaderboard alloc] initWithPlayerIDs:arr];
if(board != nil) {
board.timeScope = GKLeaderboardTimeScopeAllTime;
board.range = NSMakeRange(1, 1);
board.category = #"MY_LEADERBOARD";
[board loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil) {
// handle the error.
NSLog(#"Error retrieving score.", nil);
}
if (scores != nil) {
NSLog(#"My Score: %i", ((GKScore*)[scores objectAtIndex:0]).value);
}
}];
}
[board release];
[arr release];
}
is there a way to modify this so it will show what I want?
Also I have a problem showing NSLog(#"My Score: %i", ((GKScore*)[scores objectAtIndex:0]).value);
in a UILabel :S
Hope someone can help me out
NSLog(#"My Score: %lld", ((GKScore*)[scores objectAtIndex:0]).value);
the score values are 64bit integers, not int's
intValue
longValue
longLongValue <<==

How to get authenticated player's high score form leaderboard ( Game Center )

I need to retrieve authenticated player's submited score from Game Center. I use this code to get the score, but it just gets the top score (best score of the leaderboard not the specified player's score). How can I retrieve the authenticated player's score?
- (void) retrievePlayersScore {
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil) {
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.range = NSMakeRange(1,1);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil) {
// handle the error. if (scores != nil)
}
if (scores != nil){
// process the score information.
CCLOG(#"My Score: %d", ((GKScore*)[scores objectAtIndex:0]).value);
}
}];
}
}
You can use the following code:
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
leaderboardRequest.identifier = _leaderboardIdentifier;
if (leaderboardRequest != nil) {
[leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error){
if (error != nil) {
//Handle error
}
else{
[delegate onLocalPlayerScoreReceived:leaderboardRequest.localPlayerScore];
}
}];
}
You just have to hit loadScoresWithCompletionHandler for a given GKLeaderboard, then automatically board.localPlayerScore will be filled out for that board.
So for example,
- (void) getLoadLeaderboardPositions
{
[GKLeaderboard loadLeaderboardsWithCompletionHandler:^(NSArray *leaderboards, NSError *nsError) {
if( nsError != nil )
{
error( nsError, "get leaderboard score" ) ;
return ;
}
for( GKLeaderboard* board in leaderboards )
{
// fetch score for minimum amt of data, b/c must call `loadScore..` to get MY score.
board.playerScope = GKLeaderboardPlayerScopeFriendsOnly ;
board.timeScope = GKLeaderboardTimeScopeAllTime ;
NSRange range = {.location = 1, .length = 1};
board.range = range ;
[board loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
printf( "YOUR SCORE ON BOARD %s WAS %lld\n", [board.title UTF8String], board.localPlayerScore.value ) ;
}] ;
}
}] ;
}
You may also try to initiate the leader board by using an array of player id(s) in order to narrow the number of players:
GKLeaderboard *board = [[[GKLeaderboard alloc] initWithPlayerIDs:[NSArray arrayWithObject:myGCPlayerID]] autorelease];
Updated version using Swift
let localPlayer = GKLocalPlayer.localPlayer()
if localPlayer.isAuthenticated {
let leaderboard = GKLeaderboard(players: [localPlayer])
leaderboard.identifier = LEADERBOARD_ID
leaderboard.timeScope = .allTime
leaderboard.loadScores(completionHandler: {
(scores, error) in
let bestScore = scores?.first?.value
if bestScore != nil {
// Do something with bestScore
}
})
}