3

我对 Swift 很陌生,最近开始开发自己的应用程序。我一直在尝试实现 Game Center 多人游戏。我项目的当前结构是(标准游戏中心结构):

  • GameViewController - UIViewController, GKGameCenterControllerDelegate
  • GameKitHelper - NSObject、GKGameCenterControllerDelegate、GKMatchmakerViewControllerDelegate、GKMatchDelegate
  • GameKitHelperDelegate - 协议(matchStarted、matchEnded、match)
  • MultiplayerNetwork - GameKitHelperDelegate(用于发送和处理消息)

我面临的问题是在多人游戏的早期阶段。在 GameViewController 上,我有以下代码来触发多人游戏:

    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)        

}

上面触发的 findMatchWithMinPlayers 方法如下:

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)
}

上面的方法在 GameKitHelper 中,它有以下方法:

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)
}

一旦两个用户配对并且游戏准备好开始,只要 GKMatchmakerViewController 被关闭,应用程序就会在执行此操作的 matchmakerViewController 方法中崩溃:

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()
    }
}

通过异常断点,我发现导致上述问题的确切行如下:

    _match.delegate = self

我得到的错误如下:

2017-07-12 19:15:47.472473+0100 xxx[2653:492023] -[xxx.GameKitHelper match:didReceiveData:fromPlayer:]: 无法识别的选择器发送到实例 0x17047a600 2017-07-12 19:15:47.507642+0100 xxx [2653:492023] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[xxx.GameKitHelper 匹配:didReceiveData:fromPlayer:]:无法识别的选择器发送到实例 0x17047a600”

任何想法可能导致此问题?我什么都试过了。

4

0 回答 0