Swift多人游戏多次调用当前游戏



我正在为《九骑士》编写几款基于Ray Wenderlich教程的Swift多人游戏。(https://www.raywenderlich.com/7544-game-center-for-ios-building-a-turn-based-game)

我使用了几乎相同的GameCenterHelper文件,只是我改为segue而不是当前场景,因为我使用的是UIKit而不是Sprite Kit,其中包含以下重要部分:

现在的火柴制造商:

func presentMatchmaker() {
guard GKLocalPlayer.local.isAuthenticated else {return}
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.inviteMessage = "Would you like to play?"
let vc = GKTurnBasedMatchmakerViewController(matchRequest: request)
vc.turnBasedMatchmakerDelegate = self
currentMatchmakerVC = vc
print(vc)
viewController?.present(vc, animated: true)
}

播放器侦听器功能:

extension GameCenterHelper: GKLocalPlayerListener {
func player(_ player: GKPlayer, receivedTurnEventFor match: GKTurnBasedMatch, didBecomeActive: Bool) {
if let vc = currentMatchmakerVC {
currentMatchmakerVC = nil
vc.dismiss(animated: true)
}
guard didBecomeActive else {return}
NotificationCenter.default.post(name: .presentGame, object: match)
}
}

通知中心的以下扩展:

extension Notification.Name {
static let presentGame = Notification.Name(rawValue: "presentGame")
static let authenticationChanged = Notification.Name(rawValue: "authenticationChanged")
}

在菜单的视图加载中,我调用以下命令:

override func viewDidLoad() {
super.viewDidLoad()
createTitleLabel()
createGameImage()
createButtons()

GameCenterHelper.helper.viewController = self
GameCenterHelper.helper.currentMatch = nil

NotificationCenter.default.addObserver(self, selector: #selector(authenticationChanged(_:)), name: .authenticationChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(presentGame(_:)), name: .presentGame, object: nil)
}

点击多设备按钮调用以下命令:

@objc func startMultiDeviceGame() {
multiPlayer = true
GameCenterHelper.helper.presentMatchmaker()
}

通知调用以下内容:

@objc func presentGame(_ notification: Notification) {
// 1
print("present game")
guard let match = notification.object as? GKTurnBasedMatch else {return}

loadAndDisplay(match: match)
}
// MARK: - Helpers
private func loadAndDisplay(match: GKTurnBasedMatch) {
match.loadMatchData { [self] data, error in
if let data = data {
do {
gameModel = try JSONDecoder().decode(GameModel.self, from: data)
} catch {gameModel = GameModel()}
} else {gameModel = GameModel()}

GameCenterHelper.helper.currentMatch = match
print("load and display")
performSegue(withIdentifier: "gameSegue", sender: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare to segue")
if let vc = segue.destination as? GameVC {vc.gameModel = gameModel}
}

这很容易理解。

  1. 游戏开始,菜单场景为当前游戏添加观察员
  2. 玩家点击多设备,这会显示媒人
  3. 玩家从游戏制作者那里选择他们的游戏,我认为这会激活玩家监听器功能
  4. 这将发布到当前游戏的通知中心
  5. 通知中心观察员调用当前游戏,该游戏调用加载和显示,并得到prepare segue的一些帮助

我的问题是,我第一次这样做时效果很好,根据教程中的框架,我不知道在玩家轮到他们之后如何改变(我认为这是一个不同问题的问题(,他们会被返回菜单。第二次他们进入当前红娘并选择游戏时,当前游戏功能被调用两次,第三次他们在不关闭应用程序的情况下轮流调用,被调用三次,等等。(我在当前游戏以及加载和显示功能中都有打印语句,它们在第二次到第三次被背靠背调用等等,即使它们在第一次从匹配器中选择游戏时只被调用一次(

控制台消息

present matchmaker true
<GKTurnBasedMatchmakerViewController: 0x104810000>
present game
present game
present game
load and display
prepare to segue
load and display
prepare to segue
load and display
prepare to segue
2021-03-20 22:32:26.838680-0600 STAX[4997:435032] [Presentation] Attempt to present <STAX.GameVC: 0x103894c00> on <Game.MenuVC: 0x103814800> (from < Game.MenuVC: 0x103814800>) whose view is not in the window hierarchy.
(419.60100000000006, 39.0)
2021-03-20 22:32:26.877943-0600 STAX[4997:435032] [Presentation] Attempt to present <STAX.GameVC: 0x103898e00> on < Game.MenuVC: 0x10501c800> (from < Game.MenuVC: 0x10501c800>) whose view is not in the window hierarchy.

我原以为这是因为我没有删除通知中心的观察员,但我尝试了以下视图中的菜单屏幕加载(就在我添加.prosentGame观察员之前(:

NotificationCenter.default.removeObserver(self, name: .presentGame, object: nil)

这并没有解决问题,所以我尝试了以下方法(代替上述方法(:

NotificationCenter.default.removeObserver(self)

但这不起作用,所以我尝试了每一个,一次一个,在游戏视图控制器的视图中确实消失了(我认为这不会起作用,因为self指的是菜单vc,但我越来越绝望了(,这也不起作用。

我开始想,也许我不会添加多次调用当前游戏的多个观察者,因为以下第二次根本不起作用(我只是使用一个全局变量来跟踪第一次添加观察者的运行,然后第二次不添加(:

if addObservers {
NotificationCenter.default.addObserver(self, selector: #selector(authenticationChanged(_:)), name: .authenticationChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(presentGame(_:)), name: .presentGame, object: nil)
addObservers = false
}

因为它试图添加不在视图层次结构中的视图。(尽管该屏幕的背景音乐开始播放,但菜单仍保留,游戏板未显示…(

我不确定我是否错误地删除了通知中心观察员,或者他们是否真的不是问题的根源,所以我决定寻求帮助:(

谢谢!

我想明白了。我正试图根据以下链接从视图控制器的已解除分配实例中删除通知(最下面的答案(:

如何避免添加多个NSNotification观察员?

删除通知的正确方法是在视图中将消失的功能如下:

override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: Notification.Name.presentGame, object: nil)
NotificationCenter.default.removeObserver(self, name: Notification.Name.authenticationChanged, object: nil)
}

在实现后,我停止了多次呼叫通知中心。

相关内容

最新更新