如何让游戏的高分保存在排行榜上,Swift?

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

我使用 SpriteKit 和 Xcode 7 beta 制作了一款游戏。我尝试放置 GameCenter 和 Leaderboard,但问题是排行榜中的分数不会改变它一直保持 0(游戏的高分不会保存在 Leaderboard 中)而且我不知道如何解决它。我正在使用 3 个不同的文件:GameScene.swiftGameViewController.swiftPointsLabel.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)"
 }
}

我认为问题出在文件 GameViewController.swift 的代码中:

@IBAction func leaderboard(sender: UIButton) {

    saveHighscore(scoreManager.score)

    scoreManager.increment() //<-- Here

    showLeader()

}

可能是我没放对地方

    scoreManager.increment()

听起来您需要使用核心数据,它是您在应用程序中用来保存数据的。我对此了解不多,所以我只能向您指出一些可能有帮助的资源:

Apple Docs

Core Data relationships (swift)

Check if property is set in Core Data?

在您的游戏中,您需要增加分数并在用户得分时将分数发送到 Game Center。我不确定你的游戏是如何运作的,但每当他们应该获得一分时,你需要更新分数并将该分数发送到游戏中心并更新标签。点击排行榜按钮时,您无法更新分数。我不确定我是否清楚,所以询问您是否需要澄清或帮助。

好吧,我看到有几件事可以促成这个问题。首先是这个方法...

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

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

我没有看到您设置的任何地方,因此将其拉出也无济于事。我在下面的 saveHighscore: 函数中添加了保存到默认值。

第二个是...

saveHighscore(scoreManager.score)

scoreManager.increment() //<-- Here

showLeader()

您应该在保存分数之前递增。

我会尝试添加这些日志,看看是否有帮助...

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")
            }
        })
    }
}

希望日志中打印出或不打印出的内容加上实际保存您的默认设置会有所帮助。祝你好运。

编辑

所以问题的根源似乎是您的 VC 中有 scoreManager(这是一个 PointsLabel),但您的场景中也有一个。在你的场景中,你正在更新分数并且生活是美好的。当您点击按钮时,您实际上是从 VC 中的标签中获取分数,该分数没有得到更新。所以你真正需要的是在你的场景中找到那个标签来提取分数。

因此,我能想到的最简单的方法是在对您的代码进行少量更改的情况下使其正常工作……

完全删除此行...

var scoreManager = PointsLabel(num: 0)

并将您的操作更改为...

@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()

}

希望这能解决所有问题 =)