Since roguelikes are highly deterministic, global scoreboards are a great way to let players see who is the best.
This article explains how I implemented leaderboards using Swift and GameKit, along with some design decisions that worked well for this type of game.
Rocco Rogue has three difficulty levels:
Initially I considered using a single leaderboard with score multipliers. For example:
easy = 1x
normal = 10x
hard = 100x
However, this quickly leads to several problems:
Instead, I chose a much simpler design.
Each difficulty has its own leaderboard.
| Difficulty | Leaderboard |
|---|---|
| Easy | Rocco Rogue — Easy |
| Normal | Rocco Rogue — Normal |
| Hard | Rocco Rogue — Hard |
This keeps the competition fair and the system easy to understand.
Before writing any Swift code, the leaderboards must be created in App Store Connect.
Steps:
These leaderboard IDs are referenced by the game code, so they should never be changed after release.
Each difficulty corresponds to a leaderboard ID.
enum Difficulty {
case easy
case normal
case hard
var leaderboardID: String {
switch self {
case .easy: return "rocco_easy"
case .normal: return "rocco_normal"
case .hard: return "rocco_hard"
}
}
}This keeps the leaderboard logic simple and easy to maintain.
Scores are submitted when the player exits a session, wins, or loses.
func submitScore(_ score: Int,
difficulty: Difficulty,
cheated: Bool) {
guard GKLocalPlayer.local.isAuthenticated else { return }
guard !cheated else { return }
GKLeaderboard.submitScore(
score,
context: gameState.seed,
player: GKLocalPlayer.local,
leaderboardIDs: [difficulty.leaderboardID]
)
}You may notice the use of:
context: gameState.seed
Since it is not practical to create separate leaderboards for every seed, the seed value is stored in the leaderboard context field. This allows players to know which seed generated the score while still sharing the same leaderboard.
Besides Game Center rankings, I also display local best scores on the main menu.
Example:
Best Scores
Easy 12345
Normal 6789
Hard 98765
Players often enjoy trying to beat their own records, so showing local scores can be very motivating.
To sync best scores across devices, I used:
NSUbiquitousKeyValueStore
It requires enabling iCloud → Key-Value Storage in the Xcode project, but it does not require CloudKit code.
The game still keeps a local copy, while iCloud simply synchronizes the data across the user's devices.
Game Center leaderboards are surprisingly easy to add to an iOS game.
For Rocco Rogue, the key decisions were:
These small features significantly increase replayability for a roguelike game.
Players now have a global scoreboard to compete on while still tracking their own progress locally.
⬅️ Previous | 🏠 Index | Next ➡️