Swift 5.x iOS 14
Trying to Get GameKit Matchmaking, and almost there...but... my match seems to fail with this error message?
Run GameKit on two real devices logged into different IDs.
I get the gameKit matching interface up.
Find my peer, and invite? and get this error message ...
2021-08-26 16:29:01.361416+0200 Mutate[18060:12891141] [AXRuntimeCommon] Unknown client: FAQ
2021-08-26 16:29:01.705773+0200 FAQ[18060:12891041] [Match] Error sending dictionary {
bundleID = "ch.cqd.FAQ";
bundleVersion = 1;
isDevelopmentVersion = 1;
message = 0;
platform = 1;
shortBundleVersion = "1.0";
} to deviceID: 076731E70C32E9C1, error = Error Domain=GKDiscoveryManager Code=-1 "Peer does not exist" UserInfo={NSLocalizedDescription=Peer does not exist}
The invited one starts playing, but the one inviting get stuck waiting for a response? What am I missing?
class SimpleViewController: UIViewController {
and
extension SimpleViewController: GKMatchmakerViewControllerDelegate, GKMatchDelegate, UINavigationControllerDelegate, GKGameCenterControllerDelegate, GKLocalPlayerListener, GKInviteEventListener, GKTurnBasedEventListener {
Plus their methods...
Here is the code ...
class SimpleViewController: UIViewController {
let minPlayers = 2
let maxPlayers = 4
override func viewDidLoad() {
super.viewDidLoad()
GKLocalPlayer.local.authenticateHandler = { [self] gcAuthVC, error in
if GKLocalPlayer.local.isAuthenticated {
GKLocalPlayer.local.register(self)
print("Authenticated to Game Center!")
let request = GKMatchRequest()
request.minPlayers = minPlayers
request.maxPlayers = maxPlayers
request.inviteMessage = "Mutant Anyone?"
let vc = GKMatchmakerViewController(matchRequest: request)
vc!.delegate = self
present(vc!, animated: true)
This bit I am sure works... but
extension SimpleViewController: GKMatchmakerViewControllerDelegate, GKMatchDelegate, UINavigationControllerDelegate, GKGameCenterControllerDelegate, GKLocalPlayerListener, GKInviteEventListener, GKTurnBasedEventListener {
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
self.dismiss(animated: true)
match.delegate = self
print("matchmakerViewController ")
}
func player(_ player: GKPlayer, didAccept invite: GKInvite) {
self.dismiss(animated: true, completion: {
print("player ",invite)
})
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, hostedPlayerDidAccept player: GKPlayer) {
print("matchmakerViewController")
self.dismiss(animated: true, completion: {
print("player ",player)
})
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFindHostedPlayers players: [GKPlayer]) {
print("matchmakerViewController")
self.dismiss(animated: true, completion: {
print("player ",players)
})
}
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
self.dismiss(animated: true)
print("matchmakerViewControllerWasCancelled")
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
print("Matchmaker vc did fail with error: \(error.localizedDescription).")
}
}
I suspect the mistake is in here?
Related
I recently decided to build an application using the Maps SDK from Google, but the problem is, when I open the view controller, it only let me click for the first item.
I cant find the solution using only the google documentation.
Anyone has a fix for this?
import UIKit
import GoogleMaps
import GooglePlaces
import GooglePlacePicker
class PlacePickerVC: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate, GMSAutocompleteViewControllerDelegate, UITextFieldDelegate {
let currentLocationMarker = GMSMarker()
var locationManager = CLLocationManager()
var local = ""
var morada = ""
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Teste"
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
let config = GMSPlacePickerConfig(viewport: nil)
let placePicker = GMSPlacePickerViewController(config: config)
placePicker.delegate = self
present(placePicker, animated: true, completion: nil)
}
// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
//Display the places but only show
print("Place name: \(place.name)")
print("Place address: \(place.formattedAddress)")
print("Place attributions: \(place.attributions)")
dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// User canceled the operation.
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
dismiss(animated: true, completion: nil)
}
}
extension PlacePickerVC : GMSPlacePickerViewControllerDelegate {
func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) {
print("Place name \(place.name)")
}
func placePicker(_ viewController: GMSPlacePickerViewController,
didFailWithError error: Error) {
// In your own app you should handle this better, but for the demo we are just going to log
// a message.
NSLog("An error occurred while picking a place: \(error)")
}
func placePickerDidCancel(_ viewController: GMSPlacePickerViewController) {
// Dismiss the place picker, as it cannot dismiss itself.
//viewController.dismiss(animated: true, completion: nil)
print("No place selected")
}
}
Numbers 1 2 and 3 can't be clicked.
I'm trying to learn how to build a Game-Center based app. its a turn based extremely simple game that just basically logs what button you press and sends it to he other player. I am having a very hard time implementing all the game center features since Apple's documentation has not been updated for Swift. I've been guessing at everything and reading off Objective-C examples and hoping for the best (somehow I've managed to get a few things going, altough I'm not sure if they are correct)
Anyways, I made a new iCloud account for my Simulator and ran the app on my phone and the simulator simultaneously, trying to get them to match up in a game. However I always get a "match request is invalid" error:
EDIT I have registered the app in iTunesConnect, I've implemented leaderboards and tested them and they work (So I assume the iTunesConnect thing is properly working and set-up)
#IBAction func startTapped(_ sender: Any) {
let request = GKMatchRequest()
request.maxPlayers = 2
request.minPlayers = 1
let mmvc = GKMatchmakerViewController(matchRequest: request)
mmvc?.matchmakerDelegate = self
present(mmvc!, animated: true, completion: nil)
}
extension HomeVC: GKGameCenterControllerDelegate
{
func authenticatePlayer()
{
//CALLED ON VIEWDIDAPPEAR
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {
(view, error) in
if view != nil
{
self.present(view!, animated: true, completion: nil)
} else {
print("AUTHENTICATED!")
print(GKLocalPlayer.localPlayer().isAuthenticated)
}
}
}
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismiss(animated: true, completion: nil)
}
}
Here's the matchmaking code. Note I can get the Game Center screen to appear and tell me "how many players" and that its missing a player and gives the choice to invite friends and all that
extension HomeVC: GKMatchmakerViewControllerDelegate {
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
print("match was cancelled")
viewController.dismiss(animated: true, completion: nil)
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
print("didFailwithError: \(error.localizedDescription)")
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
print("Match found, ID: \(match.description)")
let gameScreenVC = self.storyboard?.instantiateViewController(withIdentifier: "mainGame") as! ViewController
gameScreenVC.providesPresentationContextTransitionStyle = true
gameScreenVC.definesPresentationContext = true
gameScreenVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
gameScreenVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
match.delegate = gameScreenVC
self.present(gameScreenVC, animated: true, completion: nil)
}
}
If anyone is having this issue I fixed it by just replacing the "minelayers and max-layers" with the same amount, so the code now looks like this:
#IBAction func startTapped(_ sender: Any) {
let request = GKMatchRequest()
request.maxPlayers = 2 //min and max should be the same
request.minPlayers = 2 //apparently they need to be the same
let mmvc = GKMatchmakerViewController(matchRequest: request)
mmvc?.matchmakerDelegate = self
present(mmvc!, animated: true, completion: nil)
}
apparently Game Center does not like a min.player count of 1, its invalid. but thats how I got it to stop giving me Invalid Match Request warnings
I am trying to add a send email button to a Sprite Kit game. I can get the email dialog to show up. But if I hit cancel, the app will crash or do nothing. If I hit send, the email will send, but the dialog stays. I cannot get the mailComposeController function to fire...please help!
Code:
import Foundation
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let systemVersion = UIDevice.currentDevice().systemVersion
let devicemodel = UIDevice.currentDevice().model
let appVersion = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as! String
let appBuild = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as! String
let myrootview2 = UIApplication.sharedApplication().keyWindow?.rootViewController
let mailComposerVC = MFMailComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
}
func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.view.window?.rootViewController = mailComposerVC
print("This is the rootview2: \(myrootview2)")
myrootview2!.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
var msgbody: String
mailComposerVC.mailComposeDelegate = self
msgbody = "\n\nDevice: \(devicemodel)\niOS Version: \(systemVersion)\nApp Version: \(appVersion)\nApp Build Number: \(appBuild)\n"
mailComposerVC.setToRecipients(["test1#test.com"])
mailComposerVC.setSubject("test subject")
mailComposerVC.setMessageBody(msgbody, isHTML: false)
//print(mailComposerVC)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// THIS DOESN'T GET CALLED WHEN SENDING OR CANCELLING EMAIL!
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
let test1 = result.rawValue
print(test1)
print(controller)
print(self)
print(myrootview2)
}
The issue is you are making the mailVC as the root view, you have to present it on your view like given below
#IBAction func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
I am having some extreme difficulties calling the achievements screen in game center. I have already set up the achievements in iTunes connect and it pops up fine if I access the achievements screen through the leaderboard first. However; I would like to be able to press a specific achievement button and be directed directly to the achievements screen. Can any one help? I have searched high and low on the internet ( and read through all of the documentation). I have found many resources for implementing leaderboards, but not many resources for implementing achievements in swift. My code is below. Any suggestions for my last two functions?
override func viewDidLoad() {
super.viewDidLoad()
login()
}
func login() {
println("Game Center Login Called")
let localPlayer = GKLocalPlayer.localPlayer()
// Handle the authentication
localPlayer.authenticateHandler = {(Home: UIViewController!, error: NSError!) -> Void in
if Home != nil {
println("Authentication is being processed.")
self.presentViewController(Home, animated: true, completion: nil)
} else {
println("Player has been successfully authenticated.")
}
}
}
func showLeaderboard() {
let gkScore = GKScore(leaderboardIdentifier: "high_Score_Leader_Board")
gkScore.value = Int64(highscore)
GKScore.reportScores([gkScore], withCompletionHandler: ( { (error: NSError!) -> Void in
if (error != nil) {
// handle error
println("Error: " + error.localizedDescription);
} else {
println("Score reported: \(gkScore.value)")
}
}))
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "high_Score_Leader_Board"
self.showViewController(gcViewController, sender: self)
self.presentViewController(gcViewController, animated: true, completion: nil)
}
#IBAction func gameCenterButtoPressed(sender: AnyObject) {
showLeaderboard()
}
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
func showAchievements() {
// show Achievements screen
}
#IBAction func achievementButtonPressed(sender: AnyObject) {
// Call show achievements function when button pressed
}
Instead of:
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
I think what you'll want is:
gcViewController.viewState = GKGameCenterViewControllerState.Achievements
And I found this information in this related tutorial.
I have used the code below to create my GameCenter page in my app. However, I haven't been able to connect the leaderboard that I created on iTunes Connect to my code, so the app just produces a blank leaderboard page. How do I connect my Itunes Connect leaderboard to my code, and how do I make the app such that it places your score on the leaderboard, as right now the leaderboard is empty.
Here is the code I used:
override func viewDidAppear(animated: Bool) {
//check user is logged into GameCenter
var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController : UIViewController!, error : NSError!) -> Void in
if ((viewController) != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
} else {
println((GKLocalPlayer.localPlayer().authenticated))
}
}
//display leaderboard
func showLeaderboard() {
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "MyLeaderboard"
self.showViewController(gcViewController, sender: self)
self.navigationController?.pushViewController(gcViewController, animated: true)
}
//take leaderboard away
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!) {
self.dismissViewControllerAnimated(true, completion: nil)
}
How do I connect my Itunes Connect leaderboard to the app, and what code do I use to upload one's score to the leaderboard?
Firstly add the GKGameCenterControllerDelegate to your class:
class viewController: UIViewController, GKGameCenterControllerDelegate {
...
}
This is the code you need to use to authenticate the player:
func login() {
println("Game Center Login Called")
let localPlayer = GKLocalPlayer.localPlayer()
// Handle the authentication
localPlayer.authenticateHandler = {(Home: UIViewController!, error: NSError!) -> Void in
if Home != nil {
println("Authentication is being processed.")
self.presentViewController(Home, animated: true, completion: nil)
} else {
println("Player has been successfully authenticated.")
}
}
}
This is the code you should use to show up the leaderboard:
func showLeaderboard() {
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "YOUR_LEADERBOARD_ID"
self.showViewController(gcViewController, sender: self)
self.presentViewController(gcViewController, animated: true, completion: nil)
}
This code is needed when the user taps on "Done".
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
You can call the authentication method login() in the viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
login()
...
}
Show up the leaderboard when the user taps on a button
#IBAction func button(sender: AnyObject) {
showLeaderboard()
}
If you want to submit the best score:
if GKLocalPlayer.localPlayer().authenticated {
println("I have submitted the score to Game Center")
let gkScore = GKScore(leaderboardIdentifier: "Best_Score")
gkScore.value = Int64(bestScore)
GKScore.reportScores([gkScore], withCompletionHandler: ( { (error: NSError!) -> Void in
if (error != nil) {
// handle error
println("Error: " + error.localizedDescription);
} else {
println("Score reported: \(gkScore.value)")
}
}))
}