swift – 在特定场景中构建SpriteKit / GameKit排行榜
我对
Swift很陌生,而且我在游戏中实现排行榜时遇到了一些麻烦.我刚看了一个教程:’游戏中心排行榜! (Xcode中的Swift 2)’其中GameCenter信息都通过应用程序的一个视图.在我的游戏中,我希望用户能够玩游戏,然后只有当他们使用特定的SKScene时,他们才能访问GameCenter.
因此,例如,在GameOverScene上,他们将进行用户身份验证,并且还可以上传他们的高分.我想我也错过了GameViewController(所有教程逻辑所在的位置)和我制作的众多场景之间的一些差异. 这是我的代码,我尝试在GameOverScene上使用GKGameCenterControllerDelegate并创建各种功能以到达GameCenter.当用户在视图中点击某个标签时进行调用:(这显然不起作用,因为我正在尝试访问这样的行上的场景:self.presentViewController(view!,animated:true,completion:nil) class GameOverScene: SKScene,GKGameCenterControllerDelegate { init(size: CGSize,theScore:Int) { score = theScore super.init(size: size) } ... override func didMoveToView(view: SKView) { authPlayer() leaderboardLabel.text = "Tap for Leaderboard" leaderboardLabel.fontSize = 12 leaderboardLabel.fontColor = SKColor.redColor() leaderboardLabel.position = CGPoint(x: size.width*0.85,y: size.height*0.1) addChild(leaderboardLabel) ... override func touchesBegan(touches: Set<UITouch>,withEvent event: UIEvent?) { for touch : AnyObject in touches { let location = touch.locationInNode(self) if(CGRectContainsPoint(leaderBoardLabel.frame,location)){ saveHighScore(score) showLeaderBoard() } } } func authPlayer(){ //Create a play let localPlayer = GKLocalPlayer.localPlayer() //See if signed in or not localPlayer.authenticateHandler = { //A view controller and an error handler (view,error) in //If there is a view to work with if view != nil { self.presentViewController(view!,animated:true,completion: nil) //we dont want a completion handler } else{ print(GKLocalPlayer.localPlayer().authenticated) } } } //Call this when ur highscore should be saved func saveHighScore(number:Int){ if(GKLocalPlayer.localPlayer().authenticated){ let scoreReporter = GKScore(leaderboardIdentifier: "scoreBoard") scoreReporter.value = Int64(number) let scoreArray: [GKScore] = [scoreReporter] GKScore.reportScores(scoreArray,withCompletionHandler: nil) } } func showLeaderBoard(){ let viewController = self.view.window?.rootViewController let gcvc = GKGameCenterViewController() gcvc.gameCenterDelegate = self viewController?.presentViewController(gcvc,animated: true,completion: nil) } func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) { gameCenterViewController.dismissViewControllerAnimated(true,completion: nil) } 关于如何进行此操作的任何建议都会很棒,我认为我可能会让整个场景/视图控制器混乱并导致问题.谢谢!
这个答案部分地延续了我们在评论中所停留的位置,因为你没有发布你的整个代码,我无法确切地知道你的挂断在哪里,但这是我和一个单独的指南放在一起的(这是一个稍微的您发布的不同版本的代码):
大部分代码的作者: https://www.reddit.com/r/swift/comments/3q5owv/how_to_add_a_leaderboard_in_spritekit_and_swift_20/ GameViewController.swift: import UIKit import SpriteKit import GameKit class GameViewController: UIViewController { func authenticateLocalPlayer() { let localPlayer = GKLocalPlayer.localPlayer() localPlayer.authenticateHandler = {(viewController,error) -> Void in if (viewController != nil) { self.presentViewController(viewController!,completion: nil) } else { print((GKLocalPlayer.localPlayer().authenticated)) } } } override func viewDidLoad() { super.viewDidLoad() /////authentication////// authenticateLocalPlayer() //... The rest of the default code } //... The rest of the default code } GameScene.swift(或任何你想使用GC的场景): import SpriteKit import GameKit import UIKit // Global scope (I generally put these in a new file called Global.swift) var score = 0 //sends the highest score to leaderboard func saveHighscore(gameScore: Int) { print ("You have a high score!") print("n Attempting to authenticating with GC...") if GKLocalPlayer.localPlayer().authenticated { print("n Success! Sending highscore of (score) to leaderboard") //---------PUT YOUR ID HERE: // | // | // V let my_leaderboard_id = "YOUR_LEADERBOARD_ID" let scoreReporter = GKScore(leaderboardIdentifier: my_leaderboard_id) scoreReporter.value = Int64(gameScore) let scoreArray: [GKScore] = [scoreReporter] GKScore.reportScores(scoreArray,withCompletionHandler: {error -> Void in if error != nil { print("An error has occured:") print("n (error) n") } }) } } // Your scene: class GameScene: SKScene,GKGameCenterControllerDelegate { // Local scope variables (for this scene): // Declare a new node,then initialize it let call_gc_node = SKLabelNode(fontNamed:"Chalkduster") let add_score_node = SKLabelNode(fontNamed: "Helvetica") override func didMoveToView(view: SKView) { // Give our GameCenter node some stuff initGCNode: do { // Set the name of the node (we will reference this later) call_gc_node.name = "callGC" // Default inits call_gc_node.text = "Send your HighScore of (score) into Game Center" call_gc_node.fontSize = 25 call_gc_node.position = CGPoint( x:CGRectGetMidX(self.frame),y:CGRectGetMidY(self.frame)) // Self here is the instance (object) of our class,GameScene // This adds it to our view self.addChild(call_gc_node) } // Give our Add label some stuff initADDLabel: do { // Set the name of the node (we will reference this later) add_score_node.name = "addGC" // Basic inits add_score_node.text = "ADD TO SCORE!" add_score_node.fontSize = 25 add_score_node.position = call_gc_node.position // Align our label some add_score_node.runAction(SKAction.moveByX(0,y: 50,duration: 0.01)) // Add it to the view self.addChild(add_score_node) } } override func touchesBegan(touches: Set<UITouch>,withEvent event: UIEvent?) { for touch in touches { // Get the position of our click let TPOINT = touch.locationInNode(self) // Get the name (string) of the node that was touched let node_that_was_touched: String? = nodeAtPoint(TPOINT).name // Prepare for switch statement,when we unwrap the optional,we don't want nil guard (node_that_was_touched != nil) else { print("-> before switch: found nil--not entering Switch"); return } // Find out which node we clicked based on node.name?,then do stuff: switch node_that_was_touched! { case "callGC": // We clicked the GC label: GameOver: do { print("GAME OVER!") // If we have a high-score,send it to leaderboard: overrideHighestScore(score) // Reset our score (for the next playthrough) score = 0 // Show us our stuff! showLeader() } case "addGC": // we clicked the Add label: // Update our *current score* score += 1 default: print("no matches found") } } } override func update(currentTime: CFTimeInterval) { /* Called before each frame is rendered */ call_gc_node.text = "Send your HighScore of (score) into Game Center" } // Gamecenter func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) { gameCenterViewController.dismissViewControllerAnimated(true,completion: nil) } //shows leaderboard screen func showLeader() { let viewControllerVar = self.view?.window?.rootViewController let gKGCViewController = GKGameCenterViewController() gKGCViewController.gameCenterDelegate = self viewControllerVar?.presentViewController(gKGCViewController,completion: nil) } // Your "game over" function call func overrideHighestScore(gameScore: Int) { NSUserDefaults.standardUserDefaults().integerForKey("highscore") if gameScore > NSUserDefaults.standardUserDefaults().integerForKey("highscore") { NSUserDefaults.standardUserDefaults().setInteger(gameScore,forKey: "highscore") NSUserDefaults.standardUserDefaults().synchronize() saveHighscore(gameScore) } } } 要特别注意
我在那里放了一些愚蠢的ASCII艺术,以确保你不会错过它.您必须从GameCenter设置中输入您的实际排行榜ID. 您还必须添加GameCenter库,然后执行iTunes连接以在弹出窗口中实际查看您的高分. 我认为你最初的问题是没有理解SpriteKit甚至iOS视图如何工作的后端(这完全没问题,因为Apple让人很容易进入并且很容易).但是,如您所见,遵循指南/教程可能很困难,因为您的实施会有所不同. 以下是一些很好的信息: SK中每个帧发生的情况图: 所以你看,SKScene是一个包含节点和动作等所有有趣内容的类,并且是一切(对你很重要)发生的地方.您可以通过编辑器生成这些场景,但是您可能需要创建一个新的.swift文件(因为每个场景都有自己的逻辑). 编辑器只是初始化一堆东西的“捷径”,老实说,你可以用很少的代码制作完整的游戏(但你很快发现你想要更多) 所以在这段代码中,你声明了GameScene或PauseScreen(它们基本上只是类声明,继承自SKScene),你很快就会发现这一行谈论ISNT场景:
我们在GameViewController文件中找到这个SKView声明(这只是一个类),注意它与普通的iOS应用程序大致相同,因为它继承了UIViewController: override func viewDidLoad() { super.viewDidLoad() if let scene = GameScene(fileNamed:"GameScene") { // Configure the view. let skView = self.view as! SKView skView.showsFPS = true skView.showsNodeCount = true /* Sprite Kit applies additional optimizations to improve rendering performance */ skView.ignoresSiblingOrder = true /* Set the scale mode to scale to fit the window */ scene.scaleMode = .AspectFill skView.presentScene(scene) } 同样,该方法在GameViewController.swift中声明,基本上就是这样: 那么所有这些与iOS应用和SpriteKit有什么关系呢?好吧,他们都被捣碎在彼此之上: IOS app解剖: 基本上,从右到左,你有一个Window,它是(如果错误的话,我是错误的)AppDelegate,然后是ViewController,然后是你的View,里面有所有很酷的东西(Storyboards就在View里面,就像SKScenes位于View ….标签,节点或按钮内,都位于各自的类中((视图))) 这都是继承的三明治. 查看Apple网站了解更多信息. https://developer.apple.com/library/safari/documentation/UserExperience/Conceptual/MobileHIG/ContentViews.html#//apple_ref/doc/uid/TP40006556-CH13-SW1 https://developer.apple.com/spritekit/ https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SpriteKitFramework_Ref/ https://developer.apple.com/library/safari/documentation/UserExperience/Conceptual/MobileHIG/Anatomy.html 基本上,一切都是继承自类继承的类的类,依此类推……它可能会变得混乱.你也可以通过CMD点击它们在Xcode中看到这些遗产,这会将你跳转到源文件. Goodluck与你在SpriteKit的学习和冒险:) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |