Hello. I am using MultipeerConnectivity framework in my SpriteKit game.
I have two scenarios when a peer leaves the game. First, when the peer leaves temporarily: connection is lost but all the nodes for this peer remain in the scene. And second: when the peer decides to leave for good. S/he selects an option "Exit the game" and sends the message to all other players saying that s/he is leaving. When the message is received by others, this peer's nodes should be removed from the scene.
This code is for exiting the game:
@objcfunc exitGame()
{
// Show an alert whether the player wants to exit the game
let alert = UIAlertController(title: "", message: "Do you want to leave the game?", preferredStyle: UIAlertController.Style.alert)
// If the player wants to leave the game
let acceptAction: UIAlertAction = UIAlertAction(title: "Leave", style: UIAlertAction.Style.default)
{ _ in
// Send a message to other players that you are exiting
// Create data to send: the current deck is sent to the peers
let messageToSend = self.makeMessageExit() // A message is sent to inform others that I left
self.appDelegate.connectionManager.sendData(dictionaryWithData: messageToSend,
toPeer: self.appDelegate.connectionManager.session.connectedPeers)
DispatchQueue.main.async
{
// Here goes the code to Remove the Menu with the Button Exit
if self.btnExitGame != nil && self.blurEffectView != nil && self.viewMenu != nil
{
self.btnExitGame.removeFromSuperview()
self.btnExitGame = nil
self.blurEffectView.removeFromSuperview()
self.blurEffectView = nil
self.viewMenu.removeFromSuperview()
self.viewMenu = nil
}
// This closes the game scene
self.closeSceneToFindPlayers()
// Deinitialize Connection Manager
self.appDelegate.connectionManager = nil
}
}
// If the player declines to leave the game
let declineAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel)
{ _ in
}
alert.addAction(acceptAction)
alert.addAction(declineAction)
OperationQueue.main.addOperation
{ () -> Void in
self.view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
This code is for losing the peer:
func lostPeer(peerID: MCPeerID)
{
print("I AM LOSING PEER.............")
// If the peer temporarily left the game, change the status
for (index, player) in self.appDelegate.players.enumerated()
{
if player.peerID?.displayName == peerID.displayName //&& player.status == "in" TODO: THIS IS REMOVED NEEDED??
{
self.appDelegate.players[index].status = "out_temp"
}
}
// Display an alert message that the peer left
let alert = UIAlertController(title: "Player Left",
message: "\(peerID.displayName) left the game.",
preferredStyle: UIAlertController.Style.alert)
// Add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
OperationQueue.main.addOperation
{ () -> Void in
self.view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
// Then I mark the leaving peer's nodes indicating that s/he left, but the nodes are still in the scene....
drawFields()
}
Here is the method to deal with the peer when s/he left for good when I receive the exit message from him/her:
func updateSceneExit(sender: MCPeerID?)
{
print("SCENE EXIT UPDATING............")
// Remove peer from the list of players
for player in appDelegate.players
{
if player.peerID?.displayName == sender?.displayName
{
appDelegate.players = appDelegate.players.filter(){$0 != player}
}
}
// Redraw fields
drawFields()
print("SCENE EXIT UPDATED............",appDelegate.players)
}
Now. In 80%-90% of cases, everything works fine. However when I have more than 2 players connected, sometimes what happens is that the connection with the peer is lost BEFORE I receive his/her Exit message. This results in the situation when the peer said that s/he had left, but I still have his/her nodes in the scene. Meanwhile, another player would still receive the message in advance resulting in no error.
Can someone please help me resolve the problem? Would be greatly appreciated!!!