You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift基于GameKit开发多人游戏无法接收对方数据问题求助

问题原因与解决方案

核心原因1:未设置GKMatch的代理

你已经实现了GKMatchDelegate协议,但如果没有给获取到的GKMatch实例设置delegate = self,所有接收数据的回调方法都不会触发,这是第二名玩家收不到数据的最常见原因。

核心原因2:逻辑时序存在缺陷

  1. 你在viewDidLoad中直接启动定时器检测,没有确认GKMatch中的玩家已经全部处于connected连接状态,可能出现玩家还未连接成功就发送数据,导致数据发送失败。
  2. 第二名玩家初始本地gameModel.players为空时,setupPlayers的else分支判断条件为gameModel.players.count == 1,此时还未收到第一名玩家发送的数据,条件不满足,不会执行任何操作。

核心原因3:线程安全问题

GKMatchDelegate的回调默认运行在后台队列,你直接在后台线程修改gameModel,而定时器在主线程读取该属性,跨线程读写可能出现取值异常,无法读到最新的玩家计数。

修复步骤

  1. 拿到GKMatch实例后立刻设置代理:
// 你创建/获取到match的地方加这行代码
match.delegate = self
  1. 补全连接状态监听,确认玩家全部连接后再执行业务逻辑:
func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) {
    DispatchQueue.main.async {
        if match.players.allSatisfy({ $0.connectionState == .connected }) {
            // 所有玩家连接成功后再启动定时器或者触发初始化逻辑
            self.startCheckTimer()
        }
    }
}
  1. 优化数据接收逻辑,收到数据后直接触发状态检测,不需要等定时器轮询:
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
        }
    }
}
  1. 给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 13:36:03