3

I'm trying to implement Game Center in my Swift game. I have a menu view controller, where the user can press a "SCORES" button, which should take them to the Game Center view controller.

This is the code that runs in the menu vc, when the button is pressed:

var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self

gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "VHS"

self.presentViewController(gcViewController, animated: true, completion: nil)

I have code in the Game Center vc, but I don't think it gets a chance to run. The app stops execution after this code (no breakpoints or errors, just won't let me tap anything) and displays a pop up message that reads:

Game Center Unavailable
Player is not signed in

The only other response I get is in Xcode, where the following line is printed to the log:

2014-08-29 14:10:33.157 Valley[2291:304785] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize=13.000000

I have no idea what this means or why Game Center is not working. Can anybody help??

user2397282
  • 3,798
  • 15
  • 48
  • 94

3 Answers3

7

Assuming that you've enabled Game Center in your app and also added a leaderboard in iTunes Connect then you need to authenticate your player before you can show GC. Also, be sure that you've created a test user in iTunes Connect that you can use to log in to Game Center when the prompt appears.

Your MenuViewController should authenticate the local player in viewDidLoad like so:

class MenuViewController: UIViewController,
            GKGameCenterControllerDelegate
{
    var leaderboardIdentifier: String? = nil
    var gameCenterEnabled: Bool = false

    override func viewDidLoad()
    {
        super.viewDidLoad()

        //Your code that sets up your scene or other set up code

        //HERE IS WHERE YOU AUTHENTICATE
        authenticateLocalPlayer()
    }

    func authenticateLocalPlayer()
    {
        var localPlayer = getLocalPlayer() // see GKLocalPlayerHack.h
        localPlayer.authenticateHandler =
            { (viewController : UIViewController!, error : NSError!) -> Void in
                if viewController != nil
                {
                    self.presentViewController(viewController, animated:true, completion: nil)
                }
                else
                {
                    if localPlayer.authenticated
                    {
                        self.gameCenterEnabled = true
                        localPlayer.loadDefaultLeaderboardIdentifierWithCompletionHandler
                        { (leaderboardIdentifier, error) -> Void in
                            if error != nil
                            {
                                print("error")
                            }
                            else
                            {
                                self.leaderboardIdentifier = leaderboardIdentifier
                                print("\(self.leaderboardIdentifier)") //in your example "VHS" should be returned
                            }
                        }
                    }
                    else
                    {
                        print("not able to authenticate fail")
                        self.gameCenterEnabled = false

                        if error
                        {
                            print("\(error.description)")
                        }
                        else
                        {
                            print(    "error is nil")
                        }
                    }
                }
        }
    }


    func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
    {
        gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
    }    
}

After you've successfully authenticated then you should be able to present Game Center.

Note the line: var localPlayer = getLocalPlayer() // see GKLocalPlayerHack.h

To get that to work you need to do a little hack to get GKLocalPlayer to instantiate correctly in Swift.

Create a new class in Objective-C and name the file GKLocalPlayerHack.h/m

In the header put:

//  GKLocalPlayerHack.h
// Issue with GameKit and Swift
// https://stackoverflow.com/questions/24045244/game-center-not-authenticating-using-swift

#import <GameKit/GameKit.h>

@interface GKLocalPlayerHack : NSObject

GKLocalPlayer *getLocalPlayer(void);

@end

In the implementation file put:

// GKLocalPlayerHack.m
// Issue with GameKit and Swift
// https://stackoverflow.com/questions/24045244/game-center-not-authenticating-using-swift

#import "GKLocalPlayerHack.h"

@implementation GKLocalPlayerHack

GKLocalPlayer *getLocalPlayer(void)
{
    return [GKLocalPlayer localPlayer];
}

@end

Be sure to add:

#import "GKLocalPlayerHack.h"

To your bridging header. Credit to @marmph for his answer in this question: Game Center not authenticating using Swift

Community
  • 1
  • 1
Austen Chongpison
  • 3,966
  • 1
  • 20
  • 17
  • This looks good, although I'm getting errors on the lines using the `scene` variable, because it hasn't been declared. How do I do this? – user2397282 Aug 31 '14 at 16:01
  • Edited the answer to include scene var. – Austen Chongpison Aug 31 '14 at 16:33
  • Okay, the app seems to keep crashing when trying to execute those 4 lines. I commented them out, and I get some errors saying it hasn't been able to authenticate, but my score got added to Game Center and i can view it. Why is this? – user2397282 Aug 31 '14 at 17:36
  • Are you running Xcode beta 6? There is a known issue with authentication in earlier betas with GC and Swift. – Austen Chongpison Aug 31 '14 at 18:17
  • So can you clarify again what's now happening in your app? Do you get a GC prompt to log in? Does the GC view controller show? When you say view the score do you mean that you are able to see the score in GC? – Austen Chongpison Aug 31 '14 at 18:22
  • Okay, first I build and run the app from Xcode to my device. It displays the launch image, and then stops executing. On Xcode, it has no error, just a `Thread 1: EXC_BREAKPOINT`. – user2397282 Aug 31 '14 at 18:29
  • Can you add an "All Exceptions" breakpoint and see what the error is: http://blog.manbolo.com/2012/01/23/xcode-tips-1-break-on-exceptions – Austen Chongpison Sep 03 '14 at 15:07
  • It still doesn't come out with an actual error. It just crashes on `let skView = self.view as SKView`. – user2397282 Sep 04 '14 at 10:37
  • What do I need those 4 lines for anyway? – user2397282 Sep 04 '14 at 10:42
  • All you really need is the `authenticateLocalPlayer()` call and the `authenticateLocalPlayer()` function. Those four lines set up the game scene for you. You should have already set up the scene yourself in your own code already. – Austen Chongpison Sep 04 '14 at 13:39
  • I've edited the sample code to avoid confusion. But please note that you will need to set up your scene yourself with your own code. – Austen Chongpison Sep 04 '14 at 13:41
  • Okay, I think I may have confused you a little bit :/ When I started the project for my game, I didn't choose the game template, I just create one with a single view. Also, I'm still unsure about the code. When I test it, it tells that it was unable to authenticate and that the error is nil, however, it seems to still post my score, and I can view the leaderboards. Why is this?? – user2397282 Sep 04 '14 at 13:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60623/discussion-between-workingdev-and-user2397282). – Austen Chongpison Sep 04 '14 at 13:52
  • Edited answer with info on GKLocalPlayerHack.h/m. Note you'll need to change the line `var localPlayer = GKLocalPlayer()` to `var localPlayer = getLocalPlayer()` and also add the GKLocalPlayer.h/m files. – Austen Chongpison Sep 04 '14 at 14:20
  • :O Yes!! That works a treat!! Thank you so much for all the effort you've put into this!! – user2397282 Sep 04 '14 at 15:25
0

I solved this problem for TEST MODE in this way:

Go to Game Center App Tab "Friends" click Setting at the end of the screen: SANDBOX and LOGGING MUST BE ON MODE

I hope that it works for everyone

0

You can use that, I create a Easy Game Center for iOS game center in github https://github.com/DaRkD0G/Easy-Game-Center-Swift

Message from France, Merry Christmas

Begin

(1) Add FrameWork GameKit.framework

(2) Create two files :

GKLocalPlayerHack.h

#import <GameKit/GameKit.h>
@interface GKLocalPlayerHack : NSObject
GKLocalPlayer *getLocalPlayer(void);
@end

GKLocalPlayerHack.m

#import "GKLocalPlayerHack.h"
@implementation GKLocalPlayerHack
GKLocalPlayer *getLocalPlayer(void) {
    return [GKLocalPlayer localPlayer];
}
@end

(3) In your Swift Bridging Header.h (Objectic-c import)

#import "GKLocalPlayerHack.h"

Next

class GameCenter {

// Game Center

let gameCenterPlayer=GKLocalPlayer.localPlayer()
var canUseGameCenter:Bool = false {
    didSet{if canUseGameCenter == true {// load prev. achievments form Game Center
        gameCenterLoadAchievements()}
    }}
var gameCenterAchievements=[String:GKAchievement]()

/**
    builder
*/
init(uiControlNow : UIViewController) {


    // Do any additional setup after loading the view.
    self.gameCenterPlayer.authenticateHandler={(var gameCenterVC:UIViewController!, var gameCenterError:NSError!) -> Void in

        if gameCenterVC != nil {
            //showAuthenticationDialogWhenReasonable: is an example method name. Create your own method that displays an authentication view when appropriate for your app.
            //showAuthenticationDialogWhenReasonable(gameCenterVC!)
            uiControlNow.presentViewController(gameCenterVC, animated: true, completion: { () -> Void in
                // no idea
            })
        }
        else if self.self.gameCenterPlayer.authenticated == true {
            self.self.canUseGameCenter = true
        } else  {
            self.canUseGameCenter = false
        }

        if gameCenterError != nil
        { println("Game Center error: \(gameCenterError)")}
    }


}


/**
    Load prev achievement granted to the player
*/
func gameCenterLoadAchievements(){
    // load all prev. achievements for GameCenter for the user to progress can be added
    var allAchievements=[GKAchievement]()

    GKAchievement.loadAchievementsWithCompletionHandler({ (allAchievements, error:NSError!) -> Void in
        if error != nil{
            println("Game Center: could not load achievements, error: \(error)")
        } else {
            for anAchievement in allAchievements  {
                if let oneAchievement = anAchievement as? GKAchievement {
                    self.gameCenterAchievements[oneAchievement.identifier]=oneAchievement}
            }
        }
    })
}


/**
    Add progress to an achievement

    :param: Progress achievement Double
    :param: ID Achievement
*/
func gameCenterAddProgressToAnAchievement(progress:Double,achievementID:String) {
    if canUseGameCenter == true { // only update progress if user opt-in to use Game Center
        // lookup if prev progress is logged for this achievement = achievement is already know (and loaded) form Game Center for this user
        var lookupAchievement:GKAchievement? = gameCenterAchievements[achievementID]

        if let achievement = lookupAchievement {
            // found the achievement with the given achievementID, check if it already 100% done
            if achievement.percentComplete != 100 {
                // set new progress
                achievement.percentComplete = progress
                if progress == 100.0  {achievement.showsCompletionBanner=true}  // show banner only if achievement is fully granted (progress is 100%)

                // try to report the progress to the Game Center
                GKAchievement.reportAchievements([achievement], withCompletionHandler:  {(var error:NSError!) -> Void in
                    if error != nil {
                        println("Couldn't save achievement (\(achievementID)) progress to \(progress) %")
                    }
                })
            }
            else {// achievemnt already granted, nothing to do
                println("DEBUG: Achievement (\(achievementID)) already granted")}
        } else { // never added  progress for this achievement, create achievement now, recall to add progress
            println("No achievement with ID (\(achievementID)) was found, no progress for this one was recoreded yet. Create achievement now.")
            gameCenterAchievements[achievementID] = GKAchievement(identifier: achievementID)
            // recursive recall this func now that the achievement exist
            gameCenterAddProgressToAnAchievement(progress, achievementID: achievementID)
        }
    }
}
/**
    Remove One Achievements

    :param: ID Achievement
*/
func resetAchievements(achievementID:String) {

    var lookupAchievement:GKAchievement? = gameCenterAchievements[achievementID]

    if let achievement = lookupAchievement {
        GKAchievement.resetAchievementsWithCompletionHandler({ (var error:NSError!) -> Void in
            if error != nil {
                ToolKit.log("Couldn't Reset achievement (\(achievementID))")
            } else {
                ToolKit.log("Reset achievement (\(achievementID))")
            }
        })

    } else {
        println("No achievement with ID (\(achievementID)) was found, no progress for this one was recoreded yet. Create achievement now.")

        gameCenterAchievements[achievementID] = GKAchievement(identifier: achievementID)
        // recursive recall this func now that the achievement exist
        self.resetAchievements(achievementID)
    }
}

}

YanSte
  • 10,661
  • 3
  • 57
  • 53