HelloGameKit WatchKit Extension/GameModel.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
This is }a simple game model that records points generated by gestures for the player who has the current turn |
*/ |
import Foundation |
import WatchKit |
import GameKit |
class GameModel: NSObject, NSCoding { |
// MARK: Types |
private struct PlayerIdentifiers { |
static let automatch = "automatchID" |
static let local = "localID" |
} |
// MARK: Properties |
private(set) var moves = [Move]() |
private var players = [String]() |
private var currentPlayerID: String |
private var match: GKTurnBasedMatch? |
var currentMove: Move? { |
return moves.last |
} |
// MARK: Initialization |
override init() { |
if let playerID = GKLocalPlayer.localPlayer().playerID { |
currentPlayerID = playerID |
} |
else { |
currentPlayerID = PlayerIdentifiers.local |
} |
players = [currentPlayerID] |
super.init() |
} |
// MARK: NSCoding |
required init?(coder aDecoder: NSCoder) { |
moves = aDecoder.decodeObject(forKey: "moves") as! [Move] |
players = aDecoder.decodeObject(forKey: "players") as! [String] |
currentPlayerID = aDecoder.decodeObject(forKey: "currentPlayerID") as! String |
} |
func encode(with aCoder: NSCoder) { |
aCoder.encode(moves as NSArray, forKey: "moves") |
aCoder.encode(players as NSArray, forKey: "players") |
aCoder.encode(currentPlayerID as NSString, forKey: "currentPlayerID") |
} |
// MARK: Factory methods |
class func loadGameModel(match: GKTurnBasedMatch, completionHandler: @escaping (GameModel?, Error?) -> Void) { |
print("***** loading matchData") |
match.loadMatchData { (data, error) in |
if error == nil { |
print("***** matchData load succeeded") |
var model: GameModel? = nil |
// If we have data use it otherwise make a new model. |
if let data = data, data.count > 0 { |
model = NSKeyedUnarchiver.unarchiveObject(with: data) as? GameModel |
if let model = model { |
model.gameModelDidLoad(match: match) |
} |
else { |
print("***** matchData unarchive failed") |
} |
} |
else { // this is a new match so make a model |
model = GameModel() |
} |
model?.match = match |
completionHandler(model, nil) |
} |
else { |
print("***** matchData load failed") |
completionHandler(nil, error) |
} |
} |
} |
// MARK: Match updating |
func gameModelDidLoad(match: GKTurnBasedMatch) { |
if let playerID = match.currentParticipant?.player?.playerID { |
currentPlayerID = playerID |
} |
else { |
currentPlayerID = PlayerIdentifiers.automatch |
} |
// Remove previously initialized players. |
players.removeAll() |
guard let participants = match.participants else { return } |
for participant in participants { |
if let playerID = participant.player?.playerID { |
players.append(playerID) |
} |
else { |
players.append(PlayerIdentifiers.automatch) |
} |
} |
} |
func save() { |
let data = NSKeyedArchiver.archivedData(withRootObject: self) |
guard let match = match else { |
print("***** Error: no match to save to") |
return |
} |
print("***** saving matchData") |
match.saveCurrentTurn(withMatch: data) { error in |
if let error = error { |
print("***** save failed for matchData with error: \(error)") |
} |
else { |
print("***** save complete for matchData") |
} |
} |
} |
// MARK: Making Moves and turns |
func addMove() -> Move { |
let move = Move(playerID: currentPlayerID) |
moves.append(move) |
save() |
return move |
} |
func endTurn(for match: GKTurnBasedMatch, completionHandler: @escaping () -> Void) { |
guard let participants = match.participants else { fatalError("No participants.") } |
// Compute the index of the participant to whom we wish to pass the turn to. |
var nextIndex = 0 |
if let index = players.index(of: currentPlayerID) { |
nextIndex = index + 1 % players.count |
} |
/* |
Build next participants list including all participants starting with |
the new turn holder. The current turn holder will be included at the |
end so if the non of the players take their turn the turn will eventually |
return to the current turn holder. |
*/ |
var nextParticipants = participants[nextIndex..<participants.count] |
nextParticipants += participants[0..<nextIndex] |
let nextParticipant = nextParticipants.first |
// Automatch participants do not have a player identifier so we will use a placeholder. |
var nextPlayerID = PlayerIdentifiers.automatch |
if let playerID = nextParticipant?.player?.playerID { |
nextPlayerID = playerID |
} |
// Now that we have figured our our next player we update our currentPlayerID to be that player and then end the turn. |
currentPlayerID = nextPlayerID |
let data = NSKeyedArchiver.archivedData(withRootObject: self) |
match.endTurn(withNextParticipants: Array(nextParticipants), turnTimeout: 600, match: data) { error in |
completionHandler() |
} |
} |
} |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-10-27