How do I inject GKMatch into SwiftUI view similar to this example https://www.hackingwithswift.com/books/ios-swiftui/using-coordinators-to-manage-swiftui-view-controllers ? I am building a multiplayer game in SwiftUI and I had to use UIViewControllerRepresentable to wrap the GKMatchMakerViewController into SwiftUI, however, I face a little problem where GKMatchDelegate methods are not being called. I have detected that it is happening because I dismiss the viewcontroller on didFindMatch method. I have tried to follow the above linked example, but I am not sure how I can put the GKMatch into a SwiftUI view as twoStraws did with the image in the example like so
func loadImage() {
guard let inputImage = inputImage else { return }
image = Image(uiImage: inputImage)
}
Can someone tell me what I can do? I tried my version like below.
func loadMatch() {
guard let uImultiPlayerMatch = uImultiPlayerMatch else { return }
multiPlayerMatch = uImultiPlayerMatch
}
This is the code I have to load the GKMatch: multiPlayerMatch into my view but it doesn't solve my problem. Which view can take in the GKMatch type?
Below is how my wrapper struct looks like.
struct FinalMatchMaker: UIViewControllerRepresentable {
@Binding var multiPlayerMatch: GKMatch?
@Binding var dataModel: DataModel!
let settings = AppSettings.sharedSettings
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> GKMatchmakerViewController {
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.inviteMessage = "Would you like to play Rock Paper Scissors?"
let viewController = GKMatchmakerViewController(matchRequest: request)
viewController?.matchmakerDelegate = context.coordinator
return viewController!
}
func updateUIViewController(_ uiViewController: GKMatchmakerViewController, context: Context) {
print("updateUIViewController")
}
func savePlayers() {
guard let player2Name = multiPlayerMatch?.players.first?.displayName else { return }
let playerOne = Player(displayName: GKLocalPlayer.local.displayName)
let playerTwo = Player(displayName: player2Name)
dataModel.players = [playerOne, playerTwo]
dataModel.players.sort { (playerOne, playerTwo) -> Bool in
playerOne.displayName < playerTwo.displayName
}
settings.playerOneDisplayName = playerOne.displayName
settings.playerTwoDisplayName = playerTwo.displayName
sendData()
}
func sendData() {
guard let match = multiPlayerMatch else { return }
do {
guard let data = dataModel.encode() else { return }
try match.sendData(toAllPlayers: data, with: .reliable)
} catch {
print("Send data failed")
}
}
class Coordinator: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate, GKLocalPlayerListener, GKGameCenterControllerDelegate {
var parent: FinalMatchMaker
init(_ parent: FinalMatchMaker) {
self.parent = parent
parent.dataModel = DataModel()
}
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
viewController.dismiss(animated: true, completion: nil)
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
print("Personal Error: MatchMaker failed with error \(error.localizedDescription)")
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
viewController.dismiss(animated: true, completion: nil)
parent.multiPlayerMatch = match
match.delegate = self
parent.savePlayers()
if (
parent.multiPlayerMatch?.expectedPlayerCount == 0)
{
print("Ready To Start our Match\n\n")
}
}
// GKMatchDelegate methods
func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {
if parent.multiPlayerMatch != match {
print("multiplayerMatch is nil ........")
return
}
guard let model = DataModel.decode(data: data) else {return }
parent.dataModel = model
}
func match(_ match: GKMatch, didFailWithError error: Error?) {
if parent.multiPlayerMatch != match {
return
}
}
}
}