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
Related
I have been looking everywhere on the web for tutorials on how to include iad banners in my spritekit game. For example I looked at this: Swift SpriteKit iAd but I got some errors, probaly due to the new swift 2 and swift 1. But could you explain what to do to include IAD in my spritekit game. Thank you in advance.
Make sure you have this code in your GameViewController. I just tested this out and it works for landscape and portrait mode.
class GameViewController: UIViewController, ADBannerViewDelegate {
//--------------------
//-----iAd Banner-----
//--------------------
var SH = UIScreen.mainScreen().bounds.height
let transition = SKTransition.fadeWithDuration(0)
var UIiAd: ADBannerView = ADBannerView()
override func viewWillAppear(animated: Bool) {
let BV = UIiAd.bounds.height
UIiAd.delegate = self
UIiAd.frame = CGRectMake(0, SH + BV, 0, 0)
self.view.addSubview(UIiAd)
}
override func viewWillDisappear(animated: Bool) {
UIiAd.delegate = nil
UIiAd.removeFromSuperview()
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.alpha = 1 // Fade in the animation
UIView.commitAnimations()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5)
UIiAd.alpha = 0
UIView.commitAnimations()
}
func showBannerAd() {
UIiAd.hidden = false
let BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH - BV, UIScreen.mainScreen().bounds.width, 0)
UIView.commitAnimations()
}
func hideBannerAd() {
UIiAd.hidden = true
let BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH + BV, UIScreen.mainScreen().bounds.width, 0) //Beginning position of the ad
UIView.commitAnimations()
}
//--------------------
//-----View Loads-----
//--------------------
override func viewDidLoad() {
super.viewDidLoad()
//iAd Control
self.UIiAd.hidden = true
self.UIiAd.alpha = 0
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.hideBannerAd), name: "hideadsID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.showBannerAd), name: "showadsID", object: nil)
}
Add the following outside your class declarations. It doesn't matter what class you go to, as long as it's global so you can access them from any game scene.
//-------------
//-----Ads-----
//-------------
func showAds() {
NSNotificationCenter.defaultCenter().postNotificationName("showadsID", object: nil)
}
func hideAds() {
NSNotificationCenter.defaultCenter().postNotificationName("hideadsID", object: nil)
}
And then whenever you want to show ads in the specific scene or whenever, just call the "showAds()" function or "hideAds()" to hide them.
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 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)")
}
}))
}
I Want that when the player is done with the level, he can click a button(shareButton) so an UIActivityviewcontroller pops up where the player can share its highscore with the social media.
But my problem is, the button is in the GameScene, but the UIActivityviewcontroller can only be called in the GameViewController.. how do I do this?
Game starts with GameMenuScene, when play is clicked it will move to GameScene:
class GameMenuScene: SKScene {
if nodeAtPoint.name == "play"{
NSUserDefaults.standardUserDefaults().setInteger(score+1, forKey: "currentLevel")
NSUserDefaults.standardUserDefaults().synchronize()
self.removeAllActions()
self.removeAllChildren()
var scene1:SKScene = GameScene(size: self.size) ##Updated : error: SKSCene does not have a member named "weakGameVC"
self.view?.presentScene(scene1)
}
}
GameScene:
Here is the GameViewController(as you can see, first scene is GameMenuScene:
import UIKit
import SpriteKit
import AVFoundation
import Social
class GameViewController: UIViewController, UITextFieldDelegate{
var player:SKSpriteNode = SKSpriteNode()
var scene:GameMenuScene!
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as SKView
skView.multipleTouchEnabled = false
scene = GameMenuScene(size: skView.bounds.size)
//scene.scaleMode = SKSceneScaleMode.ResizeFill
skView.showsFPS = true
skView.showsNodeCount = true
skView.presentScene(scene)
}
/*
func shareButton() {
var myShare = "aa"
let activityVC:UIActivityViewController = UIActivityViewController(activityItems: ["aa"], applicationActivities: nil)
presentViewController(activityVC, animated: true, completion: nil)
}
*/
override func prefersStatusBarHidden() -> Bool {
return true
}
}
And here the part of GameScene where the touch in the share button is detected:
import SpriteKit
import Social
class GameScene: SKScene, SKPhysicsContactDelegate {
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location: CGPoint! = touch.locationInNode(self)
let nodeAtPoint = self.nodeAtPoint(location)
if (nodeAtPoint.name != nil) {
if nodeAtPoint.name == "share"{
//shareButton()
}
}
}
}
}
This work for me:
if nodeAtPoint.name == "share"{
var myShare = "My best is \(highScoreText.text)"
let controller = self.view?.window?.rootViewController as GameViewController
let activityVC: UIActivityViewController = UIActivityViewController(activityItems: [myShare], applicationActivities: nil)
controller.presentViewController(activityVC, animated: true, completion: nil)
}