Achievements
An achievement represents a quantitative goal that the player can accomplish in your game. As the local player plays your game, he or she makes progress towards completing the achievement. When the player meets or exceeds the goal, the achievement is considered earned, and the player is rewarded. Your game defines the goal and the game mechanics that describe how a player earns the achievement. In practice, Game Center does not need to know anything about your game design; it only knows what progress the player has made towards an achievement. Achievements are a great way to track what a player has done in your game and to give the player more incentive to keep playing your game.
When you add an achievement to your game, you decide what it looks like and how it is described to the player. You also design the game mechanics that allow the player to make progress towards completing the achievement.
Checklist for Supporting Achievements
To add achievements to your game, you need to take the following steps:
Before you add achievements, add code to authenticate the local player. See “Working with Players in Game Center.”
Design your game’s achievements. See “Designing an Achievement”
Go to iTunes Connect and configure the achievements for your game. You provide all of the data needed to display achievements to the player. See “Configuring Achievements in iTunes Connect.”
Add code to report the local player’s progress to Game Center. By storing the progress on Game Center, you also make the player’s progress visible in the Game Center app. See “Reporting Achievement Progress to Game Center.”
Add code to load the local player’s previous progress on achievements from Game Center. The local player’s progress should be loaded shortly after the player is successfully authenticated. See “Loading Achievement Progress.”
Add code to display the player’s progress towards achievements. See “Displaying the Standard Achievement Interface (iOS 6)” to see how your game can display the standard achievements screen.
Optionally, you can retrieve achievement data from Game Center and use it to create your own custom achievement user interface. See “Creating a Custom Achievement User Interface.”
Designing an Achievement
The design of an achievement starts with a simple statement of the achievement’s goal. Here are some example goals you might define in a game:
Capture 10 pirates.
Defeat 1 boss.
Find 1000 gold coins.
Earn first place in 5 races.
Earn first place on 5 different race tracks.
A goal statement usually describes a triggering condition (“Earn first place on a different race track”) and a quantity (5). The triggering condition is essential because it defines something your game logic needs to track. In the racing example, your game must check the victory conditions at the end of each race, but it also needs to record which tracks a player has defeated.
The quantity usually defines how granular the task is for the player. With some achievements, quantity is irrelevant; the achievement is either earned or not. For example, “Defeat the end-game boss” is not a goal that the player generally earns partial credit towards completing. By contrast, a goal of “Capture 10 pirates” is a more granular task. Your game can track the number of pirates captured and use this count to report progress to Game Center.
When you design an achievement, consider a few other characteristics: value, visibility, and repeatability. These characteristics affect more than the design of your game; later, when you define your achievement in iTunes Connect, you’ll set attributes based on these characteristics:
The value of an achievement is a measure of how difficult you believe it will be for a player to earn the achievement. Some achievements are easily earned in a few minutes of play. Difficult achievements might require hours of focused gameplay or require the player to develop advanced playing skills or strategies to earn the achievement.
In Game Center, an achievement earns a player achievement points. When you define an achievement, you decide how many points it is worth. A player can see the total number of points that can potentially be earned in your game as well as how many points he or she has presently earned. The Game Center app allows players to compare their achievements with those of friends; this comparison screen includes the total points earned.
The visibility of an achievement determines whether a player can see the achievement at the start of play or whether the achievement must be discovered during play. By default, achievements are visible to the player. This is helpful, because a player can scan the list of available achievements and see what actions earn rewards. However, some achievements can be more useful if hidden. For example, if your game includes a story or plot, listing all of the achievements at the start of play may reveal too much of the story to the player. Achievements critical to the story can be marked as hidden so that you can choose when the player sees them.
An achievement is normally not repeatable. Once earned, the player sees no further messages about that achievement. If an achievement is marked repeatable, then each time your game reports that the player has completed the achievement, the player sees the appropriate reward banner.
You have a lot of room to be creative with the kinds of achievements you create. Here are some common strategies for designing achievements that can guide you through the process.
Create Achievements that Show the Different Things Players Can Do In Your Game
When experienced players purchase new games, they examine the list of achievements to see what’s possible in those games. Your list of achievements should strongly communicate what you want players to think about or do while playing your game. You want achievements to provide a variety of different goals a player can strive towards. When you provide a variety of goals and achievements, players continue to play your game.
Create Achievements That Require Different Levels of Skill or Dedication
Provide achievements for both new players and experienced players—and the players in between. Achievements are a reward to the player for playing your game. If all of your game’s achievements are too easy to beat, the rewards will seem cheap and the player won’t feel challenged. On the other hand, if all the achievements are too difficulty to earn, then players may not be rewarded often enough to continue playing your game. Strive to include achievements earned when learning how to play the game and also achievements for learning how to play your game well.
Another reason for requiring more difficult challenges is that they encourage players to use them when challenging other players. See “Challenges.”
Create Achievements for Different Sections Or Modes Present in Your Game
For various reasons, you might choose to partition the gameplay into smaller games or game modes. Some reasons include:
Distinct sets of game rules or rules variants (capture the flag, survival).
Distinct game levels or maps.
Your game might have an underlying story separated into distinct acts or story arcs.
If your game does partition its gameplay into smaller mini-games, define achievements for each, because it encourages players to try each of the game modes or to complete your game.
Use Hidden Achievements to Delight and Reward the Player
Hidden achievements should be used sparingly. Usually, you want players to know what’s expected of them in your game, so that they can actively set goals for themselves. And hidden achievements cannot be used to create new challenges. However, a hidden achievement can be a great opportunity to surprise a player with something unexpected. For example, any of the following might be places where a hidden achievement could be helpful:
An unexpected element in the plot or a story.
The player succeeds at a crazy stunt.
You can flip the convention from an achievement being something the player tries hard to earn into something more ignoble, earned when they fail spectacularly. The achievement then represents a way to inject humor into the situation.
Save Some of Your Budget For Later Versions of Your Game
There are limits to how many achievements you can create in your game and how many points you can reward to the player:
Each game can have up to 100 achievements.
Each game can award up to 1000 points.
No individual achievement can reward more than 100 points.
Avoid spending all of your budget on the initial version of your game. Save some of your budget to support updates and new content.
Configuring Achievements in iTunes Connect
When you are ready to add achievements, you define them first in iTunes Connect. For each achievement, you provide values for all of the properties listed in Table 5-1. Further, for each language you plan to localize the achievement into, you provide data for all of the properties listed in Table 5-2.
Property | Description |
|---|---|
Achievement Reference Name | An internal name that you must provide for each achievement, used only in iTunes Connect. This is the name you will use if you search for the achievement in iTunes Connect. |
Achievement ID | A chosen alphanumeric identifier for your Achievement. This ID is limited to 100 characters. Your Achievement ID is a permanent setting therefore cannot be edited at a later date. The achievement ID is used inside your game to refer to this achievement. |
Point Value | The points that your achievement is worth. |
Hidden | Achievements marked as Hidden remain hidden to a player on Game Center until after the first time you report progress for that achievement. |
Achievable More Than Once | Indicates whether the user can earn the achievement multiple times. |
Property | Description |
|---|---|
Language | The language in which you would like this achievement to appear. |
Title | The localized title of this achievement as you would like it to appear in Game Center. |
Pre-earned Description | The description of your achievement as it appears to a Game Center player before he or she earns it. |
Earned Description | The description of your achievement as it appears to a Game Center player after he or she earns it. |
Image | A localized image that represents the achievement. The image must be a |
For more information on setting up your leaderboards in iTunes Connect, see “Game Center”.
Adding Achievement Support to Your Game
When you are ready to implement achievements in your game, you do so using the classes listed in Table 5-3.
Class Name | Description |
|---|---|
Holds information about the player’s progress towards completing an achievement. Your game creates | |
Holds the localized text and images for an achievement. The data for achievement descriptions is retrieved from Game Center at runtime and is based on the data you provided to iTunes Connect when you created your achievement there. | |
Provides a standard user interface to display Game Center content to the player. This content includes an achievements page. | |
Provides a standard user interface to display an achievements page. If the |
Reporting Achievement Progress to Game Center
Your game should report progress to Game Center whenever the player makes progress towards completing an achievement. By storing progress information in Game Center, you gain a few benefits:
The Game Center app can display the player’s progress towards the achievement.
If a player has multiple devices, your game on another device can retrieve the player’s progress towards achievements.
Your game reports the player’s progress by using a floating-point percentage, from 0.0 to 100.0, that represents how much of the achievement the player has completed. You decide how that percentage is calculated and when it changes. For example, if the player earns an achievement simply for discovering a location in your game, then you would simply report the achievement as 100 percent complete the first time you report progress to Game Center. On the other hand, for an achievement like “Capture 10 pirates”, your reporting mechanism increments by 10 percent each time the player captures a pirate.
When you report progress to Game Center, two things happen:
If the achievement was previously hidden, it is revealed to the player. The achievement is revealed even if your player has made no actual progress on the achievement (a percentage of
0.0).If the reported value is higher than the previous value reported for the achievement, the value on Game Center is updated to the new value. Players never lose progress on achievements.
When the progress reaches 100 percent, the achievement is marked completed, and both the image and completed description appear when the player views the achievements screen.
Listing 5-1 shows how to report progress to Game Center. First, a new achievement object is initialized using an identifier string for an achievement. Next, the object’s percentComplete property is set to reflect the player’s progress. Finally, the object’s reportAchievementWithCompletionHandler: method is called, passing in a block to be notified when the report is sent.
Listing 5-1 Reporting progress on an achievement
- (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent |
{ |
GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier: identifier]; |
if (achievement) |
{ |
achievement.percentComplete = percent; |
[achievement reportAchievementWithCompletionHandler:^(NSError *error) |
{ |
if (error != nil) |
{ |
NSLog(@"Error in reporting achievements: %@", error); |
} |
}]; |
} |
} |
To report progress on multiple achievements at once, use the reportAchievements:withCompletionHandler: class method instead. Listing 5-2 shows a possible implementation. This example creates three achievement objects representing three achievements the player has just completed. It then bundles the achievement objects into an array and reports them all with a call to the class method.
Listing 5-2 Reporting progress on multiple achievements
- (void) completeMultipleAchievements |
{ |
GKAchievement *achievement1 = [[GKAchievement alloc] initWithIdentifier: @"DefeatedFinalBoss"]; |
GKAchievement *achievement2 = [[GKAchievement alloc] initWithIdentifier: @"FinishedTheGame"]; |
GKAchievement *achievement3 = [[GKAchievement alloc] initWithIdentifier: @"PlayerIsAwesome"]; |
achievement1.percentComplete = 100.0; |
achievement2.percentComplete = 100.0; |
achievement3.percentComplete = 100.0; |
NSArray *achievementsToComplete = [NSArray arrayWithObjects:achievement1,achievement2,achievement3, nil]; |
[GKAchievement reportAchievements: achievementsToComplete withCompletionHandler:^(NSError *error) |
{ |
if (error != nil) |
{ |
NSLog(@"Error in reporting achievements: %@", error); |
} |
}]; |
} |
} |
Whether reporting achievement progress on a single achievement or multiple achievements at once, your game rarely needs to do anything specific when an error occurs. If an error occurs, such as when a network is not available, Game Kit automatically resends the data at an appropriate time.
Loading Achievement Progress
You load the local player’s current progress information from Game Center by calling the loadAchievementsWithCompletionHandler: method. If the operation completes successfully, it returns an array of GKAchievement objects, one object for each achievement your game previously reported progress for.
Listing 5-3 shows how your game might implement this.
Listing 5-3 Loading achievement progress
- (void) loadAchievements |
{ [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) { |
if (error != nil) |
{ |
// Handle the error. |
} |
if (achievements != nil) |
{ |
// Process the array of achievements. |
} |
}]; |
} |
A logical time to load the local player’s progress is immediately after the player is authenticated.
As the player makes progress through your game, you want to update their progress on Game Center. If your game has previously reported progress towards this achievement, your game should first load the player’s progress from Game Center so that you know what progress the player has already made. If the player made progress on an achievement that the player has never made progress on before, your game should create a new achievement object. An easy way to manage these achievement objects in your game is by using a mutable dictionary, using the identifier property as a dictionary key, and the achievement object as the contents for that key. Here’s how to modify Listing 5-1 and Listing 5-3 to use a dictionary:
Add a mutable dictionary property to your class that report achievements; this dictionary stores the collection of achievement objects:
@property(nonatomic, retain) NSMutableDictionary *achievementsDictionary;
Initialize the achievements dictionary:
achievementsDictionary = [[NSMutableDictionary alloc] init];
When your game loads achievement data, add the achievement objects to the dictionary:
- (void) loadAchievements
{[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{if (error == nil)
{for (GKAchievement* achievement in achievements)
[achievementsDictionary setObject: achievement forKey: achievement.identifier];
}
}];
}
Implement a method that tests the dictionary for a particular achievement identifier. If the identifier does not exist as a key in the dictionary, create a new achievement object and add it to the dictionary:
- (GKAchievement*) getAchievementForIdentifier: (NSString*) identifier
{GKAchievement *achievement = [achievementsDictionary objectForKey:identifier];
if (achievement == nil)
{achievement = [[GKAchievement alloc] initWithIdentifier:identifier];
[achievementsDictionary setObject:achievement forKey:achievement.identifier];
}
return achievement;
}
Modify the code in Listing 5-1 to call
getAchievementForIdentifier:to retrieve the achievement object:- (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
if (achievement)
{achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{if (error != nil)
{// Log the error.
}
}];
}
}
Best Practices For Reporting Achievement Progress
When designing a game that uses Game Center achievements, you need to balance the need to be responsive to the player with using as few device resources as possible. With those two concepts in mind, consider the following practices:
Report progress on an achievement as soon as the player makes progress. Don’t delay reporting until a later time; if a player earns an achievement, the banner should be displayed immediately!
Report progress only when the player has actually made further progress. Do not report changes to Game Center if the player has not made progress, because it consumes network resources without actually changing the state of the data on Game Center.
If the player makes progress on multiple achievements simultaneously, use the technique shown in Listing 5-2 to report the progress. Using this class method is more efficient.
If your game displays a custom banner or indicator when a player earns an achievement, set the
showsCompletionBannerproperty toNObefore reporting the achievement to Game Center.
Resetting Achievement Progress
You may want to allow the player to reset their progress on achievements in your game. Listing 5-4 demonstrates how to do this. First, this method clears any locally cached achievement objects created by the previous example. Then, it calls Game Kit to reset the player’s progress stored on Game Center.
Listing 5-4 Resetting achievement progress
- (void) resetAchievements |
{ |
// Clear all locally saved achievement objects. |
achievementsDictionary = [[NSMutableDictionary alloc] init]; |
// Clear all progress saved on Game Center. |
[GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error) |
{ |
if (error != nil) |
// handle the error. |
}]; |
} |
When your game resets a player’s progress on achievements, all progress information is lost. Hidden achievements, if previously shown, are hidden again until your game reports progress on them. For example, if the only reason those achievements were originally hidden was because they were associated with an In-App Purchase, then you would reveal those achievements again.
Displaying the Standard Achievement Interface (iOS 6)
In addition to sending achievement progress to Game Center, you should also allow players to view their progress from within your game. The simplest way to do this is with a GKGameCenterViewController object. You can adjust the behavior of a Game Center view controller so that it shows the achievements page when presented. Listing 5-5 shows how to accomplish this. It instantiates a new view controller and sets its gameCenterDelegate property to point to the presenting view controller. It then configures the controller’s view state to show the achievements page. Finally, it presents the leaderboard and waits for the delegate to be called. On OS X, you use the GKDialogController to display the view controller, as described in “Displaying Game Center User Interface Elements.”
Listing 5-5 Displaying the achievement page of the Game Center user interface.
- (void) showLeaderboard: (NSString*) leaderboardID |
{ |
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init]; |
if (gameCenterController != nil) |
{ |
gameCenterController.gameCenterDelegate = self; |
gameCenterController.viewState = GKGameCenterViewControllerStateAchievements; |
[self presentViewController: gameCenterController animated: YES completion:nil]; |
} |
} |
When the player finishes looking at the leaderboard, the delegate is called. Listing 5-6 shows a typical implementation, which simply dismisses the presented view controller.
Listing 5-6 Responding when the player dismisses the Game Center content
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController |
{ |
[self dismissViewControllerAnimated:YES completion:nil]; |
} |
Displaying the Standard Achievement Interface (iOS 5)
On earlier versions of iOS, you use an achievement view controller to display the achievement screen. Listing 5-7 shows how to have your view controller present an achievements screen. It creates a new achievement view controller, sets the achievement delegate to point to itself, and then presents the view controller.
Listing 5-7 Presenting the standard achievement view to the player
- (void) showAchievements |
{ |
GKAchievementViewController *achievements = [[GKAchievementViewController alloc] init]; |
if (achievements != nil) |
{ |
achievements.achievementDelegate = self; |
[self presentViewController: achievements animated: YES completion:nil]; |
} |
[achievements release]; |
} |
Your view controller must also implement the GKAchievementViewControllerDelegate protocol so that it can be notified when the user dismisses the achievements screen. Listing 5-8 shows an implementation of the delegate that removes the modal view from the screen.
Listing 5-8 Responding when the player dismisses the achievements content
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController |
{ |
[self dismissViewControllerAnimated:YES completion:nil]; |
} |
Creating a Custom Achievement User Interface
If you want to create your own custom achievements user interface, you can explicitly load the data you provided to iTunes Connect. The data is returned to your game using GKAchievementDescription objects.
Loading achievement descriptions is a two-step process. First, your game loads the text descriptions for all achievements in your game. Then, when an achievement is completed and you want to display the completed image, you explicitly load that image. This allows your game to load only images you need, which reduces its memory footprint.
Listing 5-9 shows how to load the achievement descriptions using the loadAchievementDescriptionsWithCompletionHandler: method.
Listing 5-9 Retrieving achievement metadata from Game Center
- (void) retrieveAchievmentMetadata |
{ |
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler: |
^(NSArray *descriptions, NSError *error) { |
if (error != nil) |
{ |
// Process the error. |
} |
if (descriptions != nil) |
{ |
// use the achievement descriptions. |
} |
}]; |
} |
Although the properties are self-explanatory, one critical property worth noting is the identifier property. This corresponds to the achievement identifier used in iTunes Connect and on a GKAchievement object. When you design your custom user interface, you use the identifier property to match each GKAchievementDescription object to the corresponding GKAchievement object that records the player’s progress on that achievement.
The value of the image property is nil until you tell the object to load its image data. Listing 5-10 shows how your game tells an achievement description to load the image.
Listing 5-10 Loading a completed achievement image
[achievementDescription loadImageWithCompletionHandler:^(UIImage *image, NSError *error) { |
if (error == nil) |
{ |
// Use the loaded image. The image property also holds the same image. |
} |
}]; |
The GKAchievementDescription class also provides two default images your game can use. The incompleteAchievementImage class method returns an image that should be used for any achievement that has not been completed. If your game is unable to load an image for a completed achievement (or wants to display an image while the custom image is loading), the placeholderCompletedAchievementImage class method provides a generic image for a completed achievement.
© 2012 Apple Inc. All Rights Reserved. (Last updated: 2012-09-19)