Swift基于GameKit开发多人游戏无法接收对方数据问题求助
问题原因与解决方案
核心原因1:未设置GKMatch的代理
你已经实现了GKMatchDelegate协议,但如果没有给获取到的GKMatch实例设置delegate = self,所有接收数据的回调方法都不会触发,这是第二名玩家收不到数据的最常见原因。
核心原因2:逻辑时序存在缺陷
- 你在
viewDidLoad中直接启动定时器检测,没有确认GKMatch中的玩家已经全部处于connected连接状态,可能出现玩家还未连接成功就发送数据,导致数据发送失败。 - 第二名玩家初始本地
gameModel.players为空时,setupPlayers的else分支判断条件为gameModel.players.count == 1,此时还未收到第一名玩家发送的数据,条件不满足,不会执行任何操作。
核心原因3:线程安全问题
GKMatchDelegate的回调默认运行在后台队列,你直接在后台线程修改gameModel,而定时器在主线程读取该属性,跨线程读写可能出现取值异常,无法读到最新的玩家计数。
修复步骤
- 拿到
GKMatch实例后立刻设置代理:
// 你创建/获取到match的地方加这行代码 match.delegate = self
- 补全连接状态监听,确认玩家全部连接后再执行业务逻辑:
func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) { DispatchQueue.main.async { if match.players.allSatisfy({ $0.connectionState == .connected }) { // 所有玩家连接成功后再启动定时器或者触发初始化逻辑 self.startCheckTimer() } } }
- 优化数据接收逻辑,收到数据后直接触发状态检测,不需要等定时器轮询:
func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) { guard let model = GameModel.decode(data: data) else { print("解码失败,请检查GameModel的Codable实现") return } DispatchQueue.main.async { self.gameModel = model self.setupPlayers() self.checkIfShouldEnterGame() } } // 把原来定时器里的跳转逻辑抽成单独方法 private func checkIfShouldEnterGame() { guard self.gameModel.players.count == 2 else { return } if let view = self.view as! SKView? { if let scene = SKScene(fileNamed: "GameScene") as? GameScene { scene.match = self.match scene.gameModel = self.gameModel scene.localPlayer = self.localPlayer scene.size = view.bounds.size scene.scaleMode = .resizeFill view.presentScene(scene) view.ignoresSiblingOrder = true view.showsFPS = true view.showsNodeCount = true } } }
- 给
sendData方法增加打印,确认数据发送成功:
func sendData() { guard let match = match else { return } do { guard let data = gameModel.encode() else { print("编码失败") return } try match.sendData(toAllPlayers: data, with: .reliable) print("数据发送成功,玩家数:\(gameModel.players.count)") } catch { print("Send data failed: \(error.localizedDescription)") } }
内容的提问来源于stack exchange,提问作者Wattera
相关产品推荐
相关产品推荐

