在特定场景中构建 SpriteKit/GameKit 排行榜
Building a SpriteKit/GameKit leaderboard within a specific scene
我是 Swift 的新手,在我的游戏中实现排行榜时遇到了一些问题。我刚刚看了一个教程:'Game Center Leaderboards! (Swift 2 in Xcode)',里面的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)
}
任何关于我如何解决这个问题的建议都很好,我认为我可能会混淆整个 scene/view 控制器并导致问题。谢谢!
我不久前写的 Swift 2.2 和部分 Xcode 7.1 游戏中仍然有效的详细答案。详细的答案,但只是跳到底部。要基本上回答你的问题,只要你想调用它,就会调用 showLeaderboard() ,只需将特定函数放在正确的 SKScene class.
iTunes 连接:
1) 登录您的 iTunes Connect account。转到“我的应用程序”,然后 select 您想要排行榜的应用程序。
2) Go to Features, and then Game Center。单击加号创建排行榜。如果你想做一组排行榜(分组排行榜,那就往右边点"More".
3) 点击加号后,按照您想要的排行榜类型的说明进行操作。首先,如果您不确定,请做一个排行榜。您分配给它的 "Leaderboard ID" 将在您的代码中用作访问它时的字符串,因此请确保您输入的内容不错。
现在 xCode:
1) Include the GameKit.framework library by choosing the "+" sign.
2) Add the string "GameKit" into your info.plist
3a) 使用其他导入代码在 GameViewController.swift 文件顶部添加以下内容。
import GameKit
3b) 在同一个 swift 文件的 class 中添加以下函数。
func authenticateLocalPlayer() {
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
4) 从 viewDidLoad() 函数内部调用 "authenticateLocalPlayer" 函数。
5a) 现在,转到 GameScene.swift 文件(或将执行的位置)。并在顶部添加以下内容。
import GameKit
5b) 在 class 函数中添加以下代码。
//shows leaderboard screen
func showLeader() {
let viewControllerVar = self.view?.window?.rootViewController
let gKGCViewController = GKGameCenterViewController()
gKGCViewController.gameCenterDelegate = self
viewControllerVar?.presentViewController(gKGCViewController, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
在我的游戏中,我有一个显示排行榜的按钮,所以无论它在哪里,只需调用 "showLeader" 函数来显示排行榜。
6) 您必须具有将分数发送到排行榜的功能。在整个 class 声明之外,我有以下函数接受用户的游戏分数作为参数并将其发送到排行榜。它显示 "YOUR_LEADERBOARD_ID" 的地方就是我之前提到的排行榜 ID 所在的位置。As pictured here.
//sends the highest score to leaderboard
func saveHighscore(gameScore: Int) {
print("Player has been authenticated.")
if GKLocalPlayer.localPlayer().authenticated {
let scoreReporter = GKScore(leaderboardIdentifier: "YOUR_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: \(error)")
}
})
}
}
7) 这是我在游戏结束时调用的函数。它决定分数是否大于先前的最高分数,如果是,它将发送到排行榜。 此代码完全由您决定,但请确保它调用将数据发送到排行榜的 saveHighscore 函数。
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)
}
}
注意最后调用了函数 "saveHighscore"。
8) 最后,在 game over 函数(或任何你调用的函数)中,调用函数 "overrideHighestScore" 以便它可以检查分数是否足够好以保存。
完成这两项操作后,等待几分钟,直到排行榜连接到您的应用程序(或加载)。它适用于我的游戏。 希望我没有忘记任何用于制作本教程的步骤。 Screenshot of my game leaderboards。
由于您没有 post 您的整个代码,所以这个答案部分延续了我们在评论中留下的地方连同单独的指南(它与您 post 的代码版本略有不同):
大部分代码的作者:
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!, animated: true, 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, animated: true, 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 才能在弹出窗口中实际看到您的高分 window。
我认为您最初的问题是不了解 SpriteKit 甚至 iOS 视图如何工作的一些后端(这完全没问题,因为 Apple 使介入并使事情变得非常容易)。但是,如您所见,遵循指南/教程可能很困难,因为您的实施会有所不同。
这里有一些很好的信息可以作为开始:
SK 中每一帧发生的情况图:
所以你看,SKScene 是 class 具有所有有趣的东西,如节点和动作,并且是一切(对你很重要)发生的地方。您可以通过编辑器生成这些场景,但是您可能需要制作一个新的 .swift 文件来配合它(因为每个场景都可以有自己的逻辑)。
编辑器只是'shortcut'初始化一堆东西,老实说,你可以用很少的代码制作完整的游戏(但你很快就会发现你想要更多)
因此,在这段代码中,您声明 GameScene 或 PauseScreen(基本上只是 class 声明,继承自 SKScene),您很快就会发现这行代码谈论的不是场景:
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):
我们在 GameViewController
文件中找到这个 SKView 声明(它只是一个 class),请注意它与常规 iOS 应用程序大部分相同,因为它继承了用户界面ViewController:
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 应用剖析:
基本上,从右到左,您有 Window,这是(如果错误请纠正我)AppDelegate,然后是 ViewController,然后是您的视图,它具有所有很酷的功能其中的东西(情节提要位于视图内部,就像 SKScenes 位于视图内部一样......标签、节点或按钮都位于各自的 classes((视图)))
都是继承的大夹心。
查看 Apple 网站了解更多信息。
https://developer.apple.com/spritekit/
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SpriteKitFramework_Ref/
基本上,一切都是 Class 继承自 class 继承自 class 等等,等等......它会变得混乱。您还可以通过 CMD + 单击它们在 Xcode 中查看这些继承,这将跳转到源文件。
祝你在 SpriteKit 中的学习和冒险顺利:)
我是 Swift 的新手,在我的游戏中实现排行榜时遇到了一些问题。我刚刚看了一个教程:'Game Center Leaderboards! (Swift 2 in Xcode)',里面的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)
}
任何关于我如何解决这个问题的建议都很好,我认为我可能会混淆整个 scene/view 控制器并导致问题。谢谢!
我不久前写的 Swift 2.2 和部分 Xcode 7.1 游戏中仍然有效的详细答案。详细的答案,但只是跳到底部。要基本上回答你的问题,只要你想调用它,就会调用 showLeaderboard() ,只需将特定函数放在正确的 SKScene class.
iTunes 连接:
1) 登录您的 iTunes Connect account。转到“我的应用程序”,然后 select 您想要排行榜的应用程序。
2) Go to Features, and then Game Center。单击加号创建排行榜。如果你想做一组排行榜(分组排行榜,那就往右边点"More".
3) 点击加号后,按照您想要的排行榜类型的说明进行操作。首先,如果您不确定,请做一个排行榜。您分配给它的 "Leaderboard ID" 将在您的代码中用作访问它时的字符串,因此请确保您输入的内容不错。
现在 xCode:
1) Include the GameKit.framework library by choosing the "+" sign.
2) Add the string "GameKit" into your info.plist
3a) 使用其他导入代码在 GameViewController.swift 文件顶部添加以下内容。
import GameKit
3b) 在同一个 swift 文件的 class 中添加以下函数。
func authenticateLocalPlayer() {
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
4) 从 viewDidLoad() 函数内部调用 "authenticateLocalPlayer" 函数。
5a) 现在,转到 GameScene.swift 文件(或将执行的位置)。并在顶部添加以下内容。
import GameKit
5b) 在 class 函数中添加以下代码。
//shows leaderboard screen
func showLeader() {
let viewControllerVar = self.view?.window?.rootViewController
let gKGCViewController = GKGameCenterViewController()
gKGCViewController.gameCenterDelegate = self
viewControllerVar?.presentViewController(gKGCViewController, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
在我的游戏中,我有一个显示排行榜的按钮,所以无论它在哪里,只需调用 "showLeader" 函数来显示排行榜。
6) 您必须具有将分数发送到排行榜的功能。在整个 class 声明之外,我有以下函数接受用户的游戏分数作为参数并将其发送到排行榜。它显示 "YOUR_LEADERBOARD_ID" 的地方就是我之前提到的排行榜 ID 所在的位置。As pictured here.
//sends the highest score to leaderboard
func saveHighscore(gameScore: Int) {
print("Player has been authenticated.")
if GKLocalPlayer.localPlayer().authenticated {
let scoreReporter = GKScore(leaderboardIdentifier: "YOUR_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: \(error)")
}
})
}
}
7) 这是我在游戏结束时调用的函数。它决定分数是否大于先前的最高分数,如果是,它将发送到排行榜。 此代码完全由您决定,但请确保它调用将数据发送到排行榜的 saveHighscore 函数。
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)
}
}
注意最后调用了函数 "saveHighscore"。
8) 最后,在 game over 函数(或任何你调用的函数)中,调用函数 "overrideHighestScore" 以便它可以检查分数是否足够好以保存。
完成这两项操作后,等待几分钟,直到排行榜连接到您的应用程序(或加载)。它适用于我的游戏。 希望我没有忘记任何用于制作本教程的步骤。 Screenshot of my game leaderboards。
由于您没有 post 您的整个代码,所以这个答案部分延续了我们在评论中留下的地方连同单独的指南(它与您 post 的代码版本略有不同):
大部分代码的作者:
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!, animated: true, 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, animated: true, 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 才能在弹出窗口中实际看到您的高分 window。
我认为您最初的问题是不了解 SpriteKit 甚至 iOS 视图如何工作的一些后端(这完全没问题,因为 Apple 使介入并使事情变得非常容易)。但是,如您所见,遵循指南/教程可能很困难,因为您的实施会有所不同。
这里有一些很好的信息可以作为开始:
SK 中每一帧发生的情况图:
所以你看,SKScene 是 class 具有所有有趣的东西,如节点和动作,并且是一切(对你很重要)发生的地方。您可以通过编辑器生成这些场景,但是您可能需要制作一个新的 .swift 文件来配合它(因为每个场景都可以有自己的逻辑)。
编辑器只是'shortcut'初始化一堆东西,老实说,你可以用很少的代码制作完整的游戏(但你很快就会发现你想要更多)
因此,在这段代码中,您声明 GameScene 或 PauseScreen(基本上只是 class 声明,继承自 SKScene),您很快就会发现这行代码谈论的不是场景:
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):
我们在 GameViewController
文件中找到这个 SKView 声明(它只是一个 class),请注意它与常规 iOS 应用程序大部分相同,因为它继承了用户界面ViewController:
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 应用剖析:
基本上,从右到左,您有 Window,这是(如果错误请纠正我)AppDelegate,然后是 ViewController,然后是您的视图,它具有所有很酷的功能其中的东西(情节提要位于视图内部,就像 SKScenes 位于视图内部一样......标签、节点或按钮都位于各自的 classes((视图)))
都是继承的大夹心。
查看 Apple 网站了解更多信息。
https://developer.apple.com/spritekit/
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SpriteKitFramework_Ref/
基本上,一切都是 Class 继承自 class 继承自 class 等等,等等......它会变得混乱。您还可以通过 CMD + 单击它们在 Xcode 中查看这些继承,这将跳转到源文件。
祝你在 SpriteKit 中的学习和冒险顺利:)