Robust Game Center Achievement code

2019-03-21 13:46发布

问题:

In just about every example of submitting achievements to Game Center, I see this code

[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
    if (error != nil)
    {
         // Retain the achievement object and try again later (not shown).
    }
}];

Problem is, that one little comment is about 99% of the work. I've spent the last few hours trying to figure this out and it seems to be an endless set of edge cases of sending and resending and save and loading data.

Does anyone know of a nice tutorial (or sample code) on this that actually explains the hard part?

It's not as simple as just saving them to a file and loading them later. You get into trouble when you start having to retain multiple achievements and submit them later and then they all come back failed (in blocks!) and you have to save them again... quickly/safely... because the App might quit and you don't want to loose them.

I'm pulling my hair out.

回答1:

I don't think you need to pull your hair out.

I think the basic model is this:

(a) Independent of Game Center, your game has a saved state (which you always need anyway, to restore the player to where he was when your game is quit/backgrounded). This state should include all the normal stuff you need to restore your game state, plus it should include flags for all of the achievements in your game.

(b) Game Center also stores all of the achievements in your game. When you connect to Game Center, you download the signed-in player's achievements. (Complications arise as to who the signed-in player is, but your question is not about that, so let's assume the "one true player" is always the signed-in Game Center player.)

(c) Whenever the player makes an achievement, first update the appropriate achievement flag in your game's saved state data. Second, try to tell Game Center about that achievement. If it works, update your copy of Game Centers achievements with the new data.

(d) If it doesn't work, you have an achievement marked in your persistent state that is not marked in your copy of the Game Center state. At various convenient times (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) check if there are any discrepancies between what is in your own state vs. what is in the Game Center state. A discrepancy is an update that you need to re-send to Game Center. Try to send, but if it fails again, just wait until the next opportunity (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) to try again. You will never lose the data because it's in your local, true picture of the user's state. (The only way you'd lose it is if the user uninstalls your app before you've been able to successfully get it to Game Center, but then, what can you do?)