I am quite new to Swift, started developing my own app recently. I've been trying to implement the Game Center multiplayer. The current structure of my project is (standard game center structure):
- GameViewController - UIViewController, GKGameCenterControllerDelegate
- GameKitHelper - NSObject, GKGameCenterControllerDelegate, GKMatchmakerViewControllerDelegate, GKMatchDelegate
- GameKitHelperDelegate - protocol (matchStarted, matchEnded, match)
- MultiplayerNetwork - GameKitHelperDelegate (used to send and process messages)
The issue I am facing it's at the very early stages of the multiplayer game generation. On the GameViewController, I have the following code to trigger the multiplayer game:
func playMultiGame(){
var gameScene = GameSceneMultiPlayer(size:CGSize(width: 2048, height: 1536))
let networkingEngine = MultiplayerNetworking()
networkingEngine.delegate = gameScene
gameScene.networkingEngine = networkingEngine
GameKitHelper.SharedGameKitHelperInstance.findMatchWithMinPlayers(minPlayers: 2, maxPlayers: 2, viewController: self, delegate: networkingEngine)
let skView = self.view as! SKView
gameScene.scaleMode = .fill
skView.presentScene(gameScene)
}
The findMatchWithMinPlayers method triggered above is as follows:
func findMatchWithMinPlayers(minPlayers:Int, maxPlayers:Int, viewController:UIViewController, delegate:GameKitHelperDelegate) {
if(!_enableGameCenter) {
return;
}
_matchStarted = false
self._match = nil
_delegate = delegate
viewController.dismiss(animated: false, completion: nil)
//GKmatch request
let request = GKMatchRequest()
request.minPlayers = minPlayers
request.maxPlayers = maxPlayers
let mmvc = GKMatchmakerViewController(matchRequest: request)
mmvc?.matchmakerDelegate = self
viewController.present(mmvc!, animated: true, completion: nil)
}
The method above is in the GameKitHelper which has the following methods:
class GameKitHelper : NSObject, GKGameCenterControllerDelegate, GKMatchmakerViewControllerDelegate, GKMatchDelegate {
var _enableGameCenter : Bool
var _matchStarted : Bool
var _match : GKMatch!
var _delegate : GameKitHelperDelegate?
var authenticationViewController: UIViewController?
var lastError : NSError?
var playersDict : NSMutableDictionary?
class var SharedGameKitHelperIntance:GameKitHelper {
return _GameKitHelperSharedInstace
}
override init() {
self._enableGameCenter = true
self._matchStarted = false
super.init()
}
func authenticateLocalPlayer() {
[...]
}
func setAuthenticationViewController(authViewController:UIViewController!) {
[...]
}
func findMatchWithMinPlayers(minPlayers:Int, maxPlayers:Int, viewController:UIViewController, delegate:GameKitHelperDelegate) {
[...]
}
func lookupPlayers() {
[...]
}
/* Implementing delegate GKMatchmakerViewControllerDelegate methods */
func matchmakerViewControllerWasCancelled(_ viewController:GKMatchmakerViewController) {
viewController.dismiss(animated: true, completion: nil)
print("canceling multiplayer view")
_delegate?.matchEnded()
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController,
didFailWithError error: Error) {
viewController.dismiss(animated: true, completion: nil)
NSLog("Error finding match: %@", error.localizedDescription)
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController,
didFind match: GKMatch!) {
viewController.dismiss(animated: true, completion: nil)
match.delegate = self
_match = match
if(!_matchStarted && match.expectedPlayerCount==0) {
NSLog("Ready to start match")
self.lookupPlayers()
}
}
/* Implementing delegate GKMatchDelegate methods */
func match(match: GKMatch!, didReceiveData data: NSData!, fromPlayer playerID: NSString!) {
if(_match != match) {
return
}
_delegate?.match(match: match, didReceiveData: data, fromPlayer: playerID)
}
func match(match: GKMatch!, player: String!, didChangeState state: GKPlayerConnectionState) {
if(_match != match) {
return
}
switch(state) {
case GKPlayerConnectionState.stateConnected:
if(!_matchStarted && match.expectedPlayerCount == 0) {
NSLog("Ready to start match!")
self.lookupPlayers()
}
case GKPlayerConnectionState.stateDisconnected:
NSLog("Player disconnected!")
_matchStarted = false
_delegate?.matchEnded()
default:
break
}
}
func match(match: GKMatch!, connectionWithPlayerFailed:String!, withError error:NSError!) {
if(_match != match) {
return
}
NSLog("Failed to connect to player with error: %@", error.localizedDescription)
_matchStarted = false
_delegate?.matchEnded()
}
func match(match: GKMatch!, didFailWithError error: NSError!) {
if(_match != match) {
return
}
NSLog("Match failed with error: %@", error.localizedDescription)
_matchStarted = false
_delegate?.matchEnded()
}
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController)
{
gameCenterViewController.dismiss(animated: true, completion: nil)
}
Once the two users have been paired and the game is ready to start, as soon as the GKMatchmakerViewController is dismissed, the app crashes in the matchmakerViewController method that does this action:
func matchmakerViewController(_ viewController: GKMatchmakerViewController,
didFind match: GKMatch!) {
viewController.dismiss(animated: true, completion: nil)
_match.delegate = self
_match = match
if(!_matchStarted && match.expectedPlayerCount==0) {
NSLog("Ready to start match")
self.lookupPlayers()
}
}
Through the exception breakpoint, I spotted that the exact line that is causing the problem above is the following:
_match.delegate = self
The error that I am getting is the following:
2017-07-12 19:15:47.472473+0100 xxx[2653:492023] -[xxx.GameKitHelper match:didReceiveData:fromPlayer:]: unrecognized selector sent to instance 0x17047a600 2017-07-12 19:15:47.507642+0100 xxx[2653:492023] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[xxx.GameKitHelper match:didReceiveData:fromPlayer:]: unrecognized selector sent to instance 0x17047a600'
Any ideas what could be causing this issue? I've tried everything.