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)")
}
}))
}
Related
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?
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 did everything right regarding itunes connect, but when I start the app it doesn't authenticate, and when I press my Gamecenter button it gives me a message "Gamecenter is not available, user not signed in"
Code:
ViewController:
import UIKit
import SpriteKit
import GameKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
authenticateLocalPlayer()
}
//initiate gamecenter
func authenticateLocalPlayer(){
print("Starting..1")
let localPlayer = GKLocalPlayer.localPlayer()
print("Starting..2")
localPlayer.authenticateHandler = {(viewController, error) -> Void in
print("Starting..3")
if (viewController != nil) {
print("Not signed in. Authenticating now")
var vc = self.view?.window?.rootViewController
vc?.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
GameScene:
import SpriteKit
import iAd
import GameKit
class GameScene: SKScene, SKPhysicsContactDelegate, ADBannerViewDelegate, GKGameCenterControllerDelegate {
func saveHighscore(score:Int) {
//check if user is signed in
if GKLocalPlayer.localPlayer().authenticated {
let scoreReporter = GKScore(leaderboardIdentifier: "CC_Leaderboard_1") //leaderboard id here
scoreReporter.value = Int64(score) //score variable here (same as above)
let scoreArray: [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: {(error : NSError?) -> Void in
if error != nil {
print("error") }
})
}
}
//shows leaderboard screen
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
//hides leaderboard screen
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
}
I also tried authenticating inside GameScene but that didn't work either.
Edit:
//initiate gamecenter
func authenticateLocalPlayer(){
print("Gamecenter..1")
let localPlayer = GKLocalPlayer.localPlayer()
print("Gamecenter..2")
localPlayer.authenticateHandler = {(viewController, error) -> Void in
print("Gamecenter..3")
if (viewController != nil) {
print("Not signed in. Authenticating now")
var vc = self.view?.window?.rootViewController
vc?.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
Take a look at the print statements at the function above, "Gamecenter..3" never get printed.
Edit 2:
The problem solved itself when I signed out of Gamecenter. (How stupid this kind of stuff)
One possibility: In your authentication handler, you never check the error code. You only check if the viewController is set or not. If the error code is set, though, the viewController will (usually) be nil, so you could be interpreting a login error as a successful login.
I would change the code to:
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (error != nil)
{
//add some stuff to report the error
}
else if (viewController != nil){
print("Not signed in. Authenticating now")
var vc = self.view?.window?.rootViewController
vc?.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
to confirm you're not getting an error on login. If you are getting an error, that will provide a clue as to what to look at next.
Edit
Some folks are reporting authentication problems until they add at least 1 leaderboard or achievement in iTunesConnect. In those reports, they're actually getting a login error that the game isn't recognized. But, given the inherent flakiness in game center, I would add a placeholder achievement or leaderboard to rule that issue out. (iOS9 “This game is not recognized by game center.”)
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 recently tried to add Game Center to my Sprite Kit Game, but it's not working properly.
When the game starts in the simulator, the Game Center login page does show up. When I start the game on my phone it does not. Can someone tell me what I am doing wrong.
//GameViewController.Swift
import GameKit
class GameViewController: UIViewController, ADBannerViewDelegate, GKGameCenterControllerDelegate {
var bannerView:ADBannerView?
override func viewDidLoad() {
super.viewDidLoad()
// Presenting scene without using GameScene.sks
let skView = view as! SKView
let myScene = GameScene(size: skView.frame.size)
myScene.scaleMode = .ResizeFill
skView.presentScene(myScene)
authenticateLocalPlayer()
}
//initiate gamecenter
func authenticateLocalPlayer(){
var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
}
else {
println((GKLocalPlayer.localPlayer().authenticated))
}
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
//GameScene.Swift
import GameKit
class GameScene: SKScene, SKPhysicsContactDelegate{
var playerScore = 0
func playerScoreUpdate() {
playerScorelabel.text = "\(playerScore)"
}
func saveHighScore(high:Int) {
NSUserDefaults.standardUserDefaults().setInteger(high, forKey: "highscore")
//check if user is signed in
if GKLocalPlayer.localPlayer().authenticated {
var scoreReporter = GKScore(leaderboardIdentifier: "TF1G002ID") //leaderboard id here
scoreReporter.value = Int64(playerScore) //score variable here (same as above)
var scoreArray: [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: {(error : NSError!) -> Void in
if error != nil {
println("error")
}
})
}
}
//GameOver.Swift
import GameKit
class GameOverScene: SKScene, GKGameCenterControllerDelegate {
//shows leaderboard screen
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
// Press Finger
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "replay" {
playSound(sound)
}
if node.name == "leaderboard" {
showLeader()
}
}
}
//hides leaderboard screen
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
Did you import the GameKit framework into your app?
Go to your project -> General -> scroll until you see linked frameworks -> click the plus sign -> add GameKit framework by searching