如何使用 Swift 将游戏的高分保存在排行榜上?

Posted

技术标签:

【中文标题】如何使用 Swift 将游戏的高分保存在排行榜上?【英文标题】:How to make High Score of game to be saved on Leaderboard, with Swift? 【发布时间】:2015-08-21 16:20:54 【问题描述】:

我使用 SpriteKit 和 Xcode 7 beta 制作了一款游戏。我试图把 GameCenter 和排行榜,但问题是排行榜中的分数不会改变它一直保持 0 (游戏的高分不会保存在排行榜中),我不知道如何修复它。我正在使用 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()

【问题讨论】:

【参考方案1】:

嗯,我看到了一些可能导致该问题的事情。首先是这个方法……

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


希望能解决所有问题 =)

【讨论】:

我按照你说的做了,但是没有用。第一个高分不会保存它回到 1(奇怪为什么要 1)它在我这样做之前运行良好,所以这又产生了一个问题。第二高分没有像以前那样保存到排行榜。 @EminEmini 正如我之前所说,您需要查看您的日志。您是否获得“身份验证”您是否正确打印出“ScoreReporter”?是否“报告正确退出”? authenticated ScoreReporter: player:playerID:G:8359742824 alias:EminEmini98 rank:0 date:2015-09-01 12:50:57 +0000 value:0 formattedValue:(null )上下文:0x0排行榜:Leaderboard_01.1组:(null)正确报告了9月1日14:51:16 MyApp [6735] :14:51:16.853313 [NSLog]:插件com.apple.GameCenterUI.GameCenterDashboardExtension无效 @EminEmini 据我所知,您正在报告分数。但是您可能报告的分数为 1,因为您没有加载以前的分数。还有什么最后注销该错误?鉴于它似乎与可能是您问题的一部分的游戏中心有关。 你能告诉我如何修复它们吗,因为我想给某人这些 100 声望。【参考方案2】:

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

【讨论】:

是的,我知道了,关于分数、高分和排行榜的一切都是有问题的。【参考方案3】:

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

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

【讨论】:

这里不需要使用CoreData,因为OP已经使用NSUserDefaults来实现持久化了。

以上是关于如何使用 Swift 将游戏的高分保存在排行榜上?的主要内容,如果未能解决你的问题,请参考以下文章

如何用swift在游戏中心报告高分

PHP中游戏的排行榜/高分

在 Swift 2 中为 Game Center 保存高分

如何使用 swift 对本地玩家进行身份验证?

游戏中心排行榜得分移除

使用 Swift 在 Sprite Kit 游戏中重置高分