1

I have followed a great tutorial online on how to use Game Center in your iOS apps. It can be found here: http://code.tutsplus.com/tutorials/ios-sdk-game-center-achievements-and-leaderboards-part-2--mobile-5801

However the code for submitting an achievement seems to unlock achievements which have already been unlocked and I don't understand why. Here is my method which deals with a achievements:

-(void)submitAchievement:(NSString*)identifier percentComplete:(double)percentComplete {

if (self.earnedAchievementCache == NULL) {

    [GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error) {

        if (error == NULL) {
            NSMutableDictionary *tempCache = [NSMutableDictionary dictionaryWithCapacity: [scores count]];

            for (GKAchievement *score in tempCache) {
                [tempCache setObject: score forKey: score.identifier];
            }

            self.earnedAchievementCache = tempCache;
            [self submitAchievement:identifier percentComplete: percentComplete];
        }

        else {
            // Something broke loading the achievement list. Error out, and we'll try again the next time achievements submit.
            [self callDelegateOnMainThread: @selector(achievementSubmitted:error:) withArg: NULL error: error];
        }
    }];
}

else {
    // Search the list for the ID we're using...
    GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier];

    if (achievement != NULL) {

        if ((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete)) {
            // Achievement has already been earned so we're done.
            achievement = NULL;
        }

        achievement.percentComplete = percentComplete;
    }

    else {
        achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
        achievement.percentComplete = percentComplete;
        // Add achievement to achievement cache...
        [self.earnedAchievementCache setObject:achievement forKey:achievement.identifier];
    }

    if (achievement != NULL) {
        // Submit the Achievement...
        [achievement reportAchievementWithCompletionHandler: ^(NSError *error) {
            [self callDelegateOnMainThread:@selector(achievementSubmitted:error:) withArg:achievement error:error];
        }];
    }
}
}

Thanks for your time, Dan.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Supertecnoboff
  • 6,406
  • 11
  • 57
  • 98
  • I am not sure if this is causing the issue but i think you have to use nil not NULL in your if statements – Yan May 19 '14 at 17:23
  • I see that the tutorial also has NULL but i read some of the comments and a lot of people posting that they are having issues posting to game center. – Yan May 19 '14 at 17:35
  • @Yan I tried changing them to nil but still doesn't work hmmm :( – Supertecnoboff May 19 '14 at 17:39
  • That means that [achievement reportAchievementWithCompletionHandler ... is called when achievement is already completed? – Yan May 19 '14 at 17:50
  • @Yan Yeah so I that method gets called anyway.... Its weird. It should NOT call is the achievement has already been done as it shouldn't go into the last if statement.. – Supertecnoboff May 19 '14 at 17:53
  • @Supertecnoboff : I might be coming to the party little late. But have you checked about achivements. While I was creating I saw something "Can unlock multiple times". if you have found the answer please post it. thx – Alok C Aug 28 '15 at 13:55
  • @Alix Just read Yans answer and the comments below it. It worked for me. – Supertecnoboff Aug 28 '15 at 17:59

1 Answers1

1

Can you try this code and see the log. I added NSLog statements to see if the code detects achievement is completed and sets the achievement to nil. Also delete NULL from the code. Let me know how it works out.

-(void)submitAchievement:(NSString*)identifier percentComplete:(double)percentComplete {

if (!self.earnedAchievementCache) {

    [GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error) {

        if (!error) {
            NSMutableDictionary *tempCache = [NSMutableDictionary dictionaryWithCapacity: [scores count]];

            for (GKAchievement *score in scores) { // the error is here
                [tempCache setObject: score forKey: score.identifier];
            }

            self.earnedAchievementCache = tempCache;
            [self submitAchievement:identifier percentComplete: percentComplete];
        }

        else {
            // Something broke loading the achievement list. Error out, and we'll try again the next time achievements submit.
            [self callDelegateOnMainThread: @selector(achievementSubmitted:error:) withArg: NULL error: error];
        }
    }];
}else {
    // Search the list for the ID we're using...
    GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier];
    NSLog(@"achievement %f",achievement.percentComplete);
    if (achievement) {

        if ((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete)) {
            NSLog(@"Achievement has already been earned so we're done.");
            achievement = nil;
        }else{
                achievement.percentComplete = percentComplete;
        }


    }else {
        achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
        achievement.percentComplete = percentComplete;
        // Add achievement to achievement cache...
        [self.earnedAchievementCache setObject:achievement forKey:achievement.identifier];
    }

    if (achievement) {
        NSLog(@"Submit the Achievement...");
        [achievement reportAchievementWithCompletionHandler: ^(NSError *error) {
            [self callDelegateOnMainThread:@selector(achievementSubmitted:error:) withArg:achievement error:error];
        }];
    }
}
}
Yan
  • 3,533
  • 4
  • 24
  • 45
  • Hey @Yan - Thanks for your help, but it still doesn't seem to work. Here is the NSLog Outputs: "Submit the Achievement.." and "beg02" (beg02 is the game centre identifier I set in iTunes connect. – Supertecnoboff May 19 '14 at 20:06
  • i added one more NSLog to see if actually achievement is not nil after you do GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier]; possibly u are actually not getting the achievement – Yan May 19 '14 at 20:09
  • Yes I do now. But if I re build and run the game, it shows the a achievement again even though it has already been done. – Supertecnoboff May 19 '14 at 20:09
  • so does submit achievement works? Does it try to resubmit it? maybe there is an issue in getting achievement in the game? – Yan May 19 '14 at 20:11
  • Oh this is interesting, for the achievement NSLog I get: "achievement 0.000000" even though I am passing a double to (100.0). – Supertecnoboff May 19 '14 at 20:13
  • Thats the problem for some reason GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier]; is not returning the achievement – Yan May 19 '14 at 20:15
  • I think i got it you are iterating through tempCache to get scores not through the scores array thats why you are not getting achievements – Yan May 19 '14 at 20:19
  • You sir, are a genius. I cannot thank you enough for your help :) – Supertecnoboff May 19 '14 at 20:21
  • 1
    Haha. Well you saved me from hours of not understanding what was wrong. I certainly give your answer the green tick :D – Supertecnoboff May 19 '14 at 20:24