Active Filters: Game Center

Topics

#64: Turn Based Games 🎲

Topics

Game Center makes it simple to create a multiplayer, turn-based game. It handles matchmaking, turn expirations and much more. Let's take a look at how to use it. First, we'll authenticate the local player (shown in Bite #57), then register a listener on it:


GKLocalPlayer.localPlayer().registerListener(self)

We describe our game's player setup in a match request, then hand it to a new matchmaker view controller.

let r = GKMatchRequest()

r.minPlayers = 2; r.maxPlayers = 2
r.defaultNumberOfPlayers = 2

let vc = GKTurnBasedMatchmakerViewController(
  matchRequest: r
)

vc.turnBasedMatchmakerDelegate = self

presentViewController(vc, animated: true, completion: nil)

At the start of each turn, we download the latest match data from Game Center, and modify it as the player plays. Then at the end of each turn we send our modified match data object back up to Game Center, so other players can download it. We need to download updated match data when the match begins and when our *local player's *turn starts.

For this we implement two functions from two different protocols:

// GKTurnBasedMatchmakerViewControllerDelegate
func turnBasedMatchmakerViewController(viewController: GKTurnBasedMatchmakerViewController, didFindMatch match: GKTurnBasedMatch) {
  dismissViewControllerAnimated(true) { self.updateCurrentMatchData(match) }
}

// GKLocalPlayerListener
func player(player: GKPlayer, receivedTurnEventForMatch match: GKTurnBasedMatch, didBecomeActive: Bool) {
  updateCurrentMatchData(match)
}

When our local player completes their turn, we end the turn and tell Game Center which of the match's participants should go next (only 2 in our case, so we always send the other player):

updateMatchData(wordPlayed)

currentMatch?.endTurnWithNextParticipants(
  [opponent()],
  turnTimeout: GKTurnTimeoutDefault,
  matchData: matchData,
  completionHandler: nil
)

Finally, when someone wins, we set their matchOutcome to .Won and end the match:

let winner = decideWinner()

winner.matchOutcome = .Won

currentMatch?.endMatchInTurnWithMatchData(
  matchData,
  completionHandler: nil
)

Topics

#61: Game Center Achievements 🏆

Topics

Continuing where we left off with Game Center in Bite #57, let's add support for achievements to our game. We start by adding a couple of achievements in iTunes Connect. When viewing our app, we'll click Game Center, then Add Achievement.

Most of this process is self-explanatory, but one thing to note is that each achievement can have a point value of no more than 100. Additionally, the point values of all the achievements in our game added together can't be more than 1000.

Now all we need to do is tell Game Center when a player completes (or makes progress towards) an achievement. Every time our user scores a point, we'll update their progress.

if score <= 5 {
  let achievement = GKAchievement(identifier: "achievement.womprats.five")

  achievement.percentComplete = Double(score / 5)
  achievement.showsCompletionBanner = true  // use Game Center's UI

  GKAchievement.reportAchievements([achievement], withCompletionHandler: nil)
}

We can also load the user's current achievement progress anytime like this:

GKAchievement.loadAchievementsWithCompletionHandler() { achievements, error in
  guard let achievements = achievements else { return }

  print(achievements)
}

Remember that the local player will need to be authenticated (as shown in Bite #57) before you can load or report any achievements.

Topics

#57: Game Center Leaderboard Basics 🎮

Topics

Game Center is a great way to easily add things like leaderboards, multiplayer, challenges, etc. to your iOS or OS X game. Let's try it out by authenticating a user, then reporting a score to a leaderboard.

We start by grabbing the local player, and setting an authentication handler closure. This will be called automatically when it's first set. This will handle showing the login screen if necessary.

import GameKit

let leaderboardID = "com.magnus.beggarscanyon.womprats"

class GameViewController: UIViewController {
  func authenticateWithGameCenter() {
    // called inside viewDidLoad

    NSNotificationCenter.defaultCenter().addObserver(
      self, selector: Selector("authenticationDidChange:"),
      name: GKPlayerAuthenticationDidChangeNotificationName,
      object: nil
    )

      GKLocalPlayer.localPlayer().authenticateHandler = {
      viewController, error in

        guard let vc = viewController else { return }

        self.presentViewController(vc, animated: true, completion: nil)
    }
  }

    func authenticationDidChange(notification: NSNotification) {
    reportScore(1138) // report example score after user logs in
  }
}

After the user is logged in we call our reportScore function, which looks like this:

func reportScore(score: Int64) {
    let gkScore = GKScore(leaderboardIdentifier: leaderboardID)
    gkScore.value = score

    GKScore.reportScores([gkScore]) { error in
      guard error == nil  else { return }

    let vc = GKGameCenterViewController()
      vc.leaderboardIdentifier = leaderboardID
    vc.gameCenterDelegate = self
      vc.viewState = GKGameCenterViewControllerState.Leaderboards

      self.presentViewController(vc, animated: true, completion: nil)   }
}

We want to see this new score we've posted, so we finish off by creating a leaderboard view controller, and presenting it. Success!