How to make High Score of game to be saved on Leaderboard, with Swift?

 ̄綄美尐妖づ 提交于 2019-12-21 20:47:07

问题


I made a game using SpriteKit and Xcode 7 beta. I tried to put GameCenter and Leaderboard but the problem is that the score in leaderboard won't change it stay all the time 0 (High Score of game won't save in Leaderboard) and I don't know how to fix it. I'm using 3 different files: GameScene.swift, GameViewController.swift, and PointsLabel.swift.

GameScene.swift

func addPointsLabels() {
    let pointsLabel = PointsLabel(num: 0)
    pointsLabel.position = CGPointMake(30.0, view!.frame.size.height - 40)
    pointsLabel.name = "pointsLabel"
    addChild(pointsLabel)


    //High Score
    let highscoreLabel = PointsLabel(num: 0)
    highscoreLabel.name = "highscoreLabel"
    highscoreLabel.position = CGPointMake(view!.frame.size.width - 35, view!.frame.size.height - 40)
    addChild(highscoreLabel)
}


func loadHighscore() {
    let defaults = NSUserDefaults.standardUserDefaults()

    let highscoreLabel = childNodeWithName("highscoreLabel") as! PointsLabel
    highscoreLabel.setTo(defaults.integerForKey("highscore"))
}

GameViewController.swift:

import GameKit

class GameViewController: UIViewController,UIGestureRecognizerDelegate, GKGameCenterControllerDelegate {

var scoreManager = PointsLabel(num: 0)

override func viewDidLoad() {
    super.viewDidLoad()

    //initiate gamecenter
func authenticateLocalPlayer(){

    let localPlayer = GKLocalPlayer.localPlayer()

    localPlayer.authenticateHandler = {(GameViewController, error) -> Void in

        if (GameViewController != nil) {
            self.presentViewController(GameViewController!, animated: true, completion: nil)
        }

        else {
            print((GKLocalPlayer.localPlayer().authenticated))
        }
     }
  }
}

@IBAction func leaderboard(sender: UIButton) {

    saveHighscore(scoreManager.score)

    scoreManager.increment()

    showLeader()

}



//send high score to leaderboard
func saveHighscore(score:Int) {

    //check if user is signed in
    if GKLocalPlayer.localPlayer().authenticated {

        let scoreReporter = GKScore(leaderboardIdentifier: "Leaderboard_01")

        scoreReporter.value = Int64(score)

        let scoreArray: [GKScore] = [scoreReporter]

        GKScore.reportScores(scoreArray, withCompletionHandler: {error -> Void in
            if error != nil {
                print("error")
            }
        })
    }
}


    //shows leaderboard screen
    func showLeader() {
        let vc = self.view?.window?.rootViewController
        let gc = GKGameCenterViewController()
        gc.gameCenterDelegate = self
        vc?.presentViewController(gc, animated: true, completion: nil)
    }
}

//hides leaderboard screen
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController)
{
    gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)

}

PointsLabel.swift:

import Foundation
import UIKit
import SpriteKit

class PointsLabel: SKLabelNode {

var score:Int = 0

init(num: Int) {
    super.init()

    fontColor = UIColor.blackColor()
    fontSize = 30.0

    score = num
    text = "\(num)"
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func increment() {
    score++
    text = "\(score)"
}

func setTo(num: Int) {
    self.score = num
    text = "\(self.score)"
 }
}

I think the problem is in file GameViewController.swift in code:

@IBAction func leaderboard(sender: UIButton) {

    saveHighscore(scoreManager.score)

    scoreManager.increment() //<-- Here

    showLeader()

}

Maybe I didn't put it in right place

    scoreManager.increment()

回答1:


Well I see a couple things that can contribute to the issue. First is this method...

func loadHighscore() {
    let defaults = NSUserDefaults.standardUserDefaults()

    let highscoreLabel = childNodeWithName("highscoreLabel") as! PointsLabel
    highscoreLabel.setTo(defaults.integerForKey("highscore"))
}

I don't see anywhere you are setting that so pulling it out won't help much. I added the saving to defaults in the saveHighscore: function bellow.

Second is...

saveHighscore(scoreManager.score)

scoreManager.increment() //<-- Here

showLeader()

You should increment before you save your score.

I would try adding these logs to see if this helps...

func saveHighscore(score:Int) {

    let defaults = NSUserDefaults.standardUserDefaults()
    defaults.setInteger(score, forKey: "highscore")
    defaults.synchronize()

    //check if user is signed in
    if GKLocalPlayer.localPlayer().authenticated {

        println("authenticated")

        let scoreReporter = GKScore(leaderboardIdentifier: "Leaderboard_01")
        println("ScoreReporter: \(scoreReporter)")

        scoreReporter.value = Int64(score)

        let scoreArray: [GKScore] = [scoreReporter]

        GKScore.reportScores(scoreArray, withCompletionHandler: {error -> Void in
            if error != nil {
                print("error")
            }
            else{
                println("reported correctly")
            }
        })
    }
}

Hopefully what does or don't print out in the logs plus actually saving your defaults will help. Good luck.

Edit

So it appears the root of the problem is that you have scoreManager (which is a PointsLabel) in your VC but you also have one that is in your Scene. The one in your scene you are updating the score and life is good. When you hit the button you are actually getting the score from the label in your VC that isn't getting updated. So what you really need is to get to that label in your scene to pull out the score.

So the easiest way I can think of getting it to work properly with as little changes to your code is this…

Remove this line completely…

var scoreManager = PointsLabel(num: 0)

and change your action to this...

@IBAction func leaderboard(sender: UIButton) {

    let skView = self.view as! SKView
    let scene = skView.scene
    let scoreManager = scene.childNodeWithName("pointsLabel") as! PointsLabel

    saveHighscore(scoreManager.score)

    showLeader()

}

Hopefully that fixes everything =)




回答2:


In your game, you need to increment the score AND send the score to Game Center whenever the user scores a point. I'm not sure how your game works, but whenever they should be awarded a point you need to update the score and send that score to game center and update the label. You just can't update the score when the leaderboard button is tapped. I'm not sure if I was clear so ask if you need clarification or help.




回答3:


It sounds like you need to use core data, it is what you use to save data in an app. I don't know to much about it so I can only point you to a few recourses that might help:

Apple Docs

Core Data relationships (swift)

Swift - Core Data Seeding Class

Check if property is set in Core Data?

How do I access and use an entity using Core Data



来源:https://stackoverflow.com/questions/32145090/how-to-make-high-score-of-game-to-be-saved-on-leaderboard-with-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!