// // MatchmakingHelper.swift // GoldWars // // Created by Chauntalle Schüle, Ömer Özel, Eray Kör on 03.05.20. // Copyright © 2020 SP2. All rights reserved. // import GameKit protocol GameKitHelperDelegate { func matchStarted() func matchEnded() func matchReceivedData(match: GKMatch, data: NSData, fromPlayer player: String) } /* Diese Klasse wird für das Matchmaking über das Gamecenter gebraucht @param: delegate: erhält alle Multiplayerevents @param: mpMatch: repräsentiert das Netzwerk, alle Mitspieler besitzen ein gemeinsames Spiel @param: viewController: ist nicht der ViewController des Gamecenters, sondern des Spiels @param: mpMatchStarted: gibt an, ob ein Match schon gestartet wurde @param: isServer: gibt an, ob der local player, als der Server fungiert @param: spieler1: ist immer der Spieler, der der Server ist @param: spieler2: ist immer der Spieler, der der Client ist @param: sharedInstance: ist eine geteilte Instanz für alle Spieler */ class MatchmakingHelper: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate { var delegate: GameKitHelperDelegate? var mpMatch: GKMatch? var viewController: UIViewController? var mpMatchStarted: Bool var isServer: Bool var menusc: MenuScene? let localPlayer: GKLocalPlayer = GKLocalPlayer.local static let sharedInstance = MatchmakingHelper() static var isAuthenticated: Bool{ return GKLocalPlayer.local.isAuthenticated } override init() { mpMatchStarted = false isServer = false super.init() } /* Diese Methode wechselt von der MenuScene zum GameCenter ViewController. Die Spieler werden hier gesucht und gematcht. Mit minplayers/maxplayers kann bestimmt werden, wie viele Spieler insgesamt zusammen miteinander spielen. */ func presentMatchmaker(scene: MenuScene) { menusc = scene guard GKLocalPlayer.local.isAuthenticated else { return } let request = GKMatchRequest() request.minPlayers = 2 request.maxPlayers = 2 request.inviteMessage = "Willst du GoldWars spielen?" let matchmakerVC = GKMatchmakerViewController.init(matchRequest: request) matchmakerVC!.matchmakerDelegate = self viewController?.present(matchmakerVC!, animated: true, completion: nil) } /* Der User hat die Verbindung mit "Abbrechen" unterbrochen. GameCenter MatchMaking wird beendet. */ func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) { viewController.dismiss(animated: true, completion: nil) delegate?.matchEnded() } /* Wenn GameCenter kein match erstellen kann, wird der viewcontroller dismissed. */ func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) { viewController.dismiss(animated: true, completion: nil) print("Error finding match", error.localizedDescription) delegate?.matchEnded() } /* Gamecenter hat erfolgreich ein Match gefunden, das Spiel kann gestartet werden. expectedPlayerCount: Die verbleibende Anzahl von Spielern, die sich noch nicht mit dem Spiel verbunden haben z.B 0 gibt an, dass keine weiteren Spieler benötigt werden um das Match zu starten */ func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) { viewController.dismiss(animated: true, completion: nil) mpMatch = match match.delegate = self if !mpMatchStarted && match.expectedPlayerCount == 0 { startMatch() } } /* Vom match erhaltene Spielerdaten */ private func match(match: GKMatch!, didReceiveData data: NSData!,fromPlayer playerID: String!) { if mpMatch != match { return } delegate?.matchReceivedData(match: match, data: data, fromPlayer: playerID) } /* Verbindung/Matchmaking ist fehlgeschlagen */ private func match(match: GKMatch!, didFailWithError error: NSError!) { if mpMatch != match { return } mpMatchStarted = false delegate?.matchEnded() } /* Wird beim ändern des States/Zustands des Spielers aufgerufen udn gibt dessen Zustand zurück. */ func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) { if mpMatch != match { return } switch (state) { case GKPlayerConnectionState.connected: if (!mpMatchStarted && match.expectedPlayerCount == 0) { startMatch() } case GKPlayerConnectionState.disconnected: mpMatchStarted = false delegate?.matchEnded() default: delegate?.matchEnded() } } /* Ein Spieler wird als Host für das Match gewählt. Dieser ist Spieler 1. Im Anschluss wird die GameScene geladen. */ func startMatch() { mpMatch!.chooseBestHostingPlayer(completionHandler: { (player) in self.mpMatchStarted = true if player == GKLocalPlayer.local { self.isServer = true } else { self.isServer = false } self.delegate?.matchStarted() self.menusc!.loadScene(scene: GameScene(size: self.menusc!.size)) }) } /* Trennt die Verbindung vom Match */ func disconnect() { if mpMatch != nil { mpMatch?.disconnect() } } }