因此,例如,在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) } } }
要特别注意
29:
let my_leaderboard_id = "YOUR_LEADERBOARD_ID"
我在那里放了一些愚蠢的ASCII艺术,以确保你不会错过它.您必须从GameCenter设置中输入您的实际排行榜ID.
您还必须添加GameCenter库,然后执行iTunes连接以在弹出窗口中实际查看您的高分.
我认为你最初的问题是没有理解SpriteKit甚至iOS视图如何工作的后端(这完全没问题,因为Apple让人很容易进入并且很容易).但是,如您所见,遵循指南/教程可能很困难,因为您的实施会有所不同.
以下是一些很好的信息:
SK中每个帧发生的情况图:
所以你看,SKScene是一个包含节点和动作等所有有趣内容的类,并且是一切(对你很重要)发生的地方.您可以通过编辑器生成这些场景,但是您可能需要创建一个新的.swift文件(因为每个场景都有自己的逻辑).
编辑器只是初始化一堆东西的“捷径”,老实说,你可以用很少的代码制作完整的游戏(但你很快发现你想要更多)
所以在这段代码中,你声明了GameScene或PauseScreen(它们基本上只是类声明,继承自SKScene),你很快就会发现这一行谈论ISNT场景:
override func didMoveToView(view: SKView)
.. it’s calling a SKView… what is that,and where did it come from?(Read about SKView here,and look at its inheritance):
07002
我们在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中声明,基本上就是这样:
class GameViewController:UIViewController
那么所有这些与iOS应用和SpriteKit有什么关系呢?好吧,他们都被捣碎在彼此之上:
IOS app解剖:
基本上,从右到左,你有一个Window,它是(如果错误的话,我是错误的)AppDelegate,然后是ViewController,然后是你的View,里面有所有很酷的东西(Storyboards就在View里面,就像SKScenes位于View ….标签,节点或按钮内,都位于各自的类中((视图)))
这都是继承的三明治.
查看Apple网站了解更多信息.
https://developer.apple.com/spritekit/
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SpriteKitFramework_Ref/
基本上,一切都是继承自类继承的类的类,依此类推……它可能会变得混乱.你也可以通过CMD点击它们在Xcode中看到这些遗产,这会将你跳转到源文件.
Goodluck与你在SpriteKit的学习和冒险:)