xcode - 如何使用SwiftUI显示Game Center排行榜

标签 xcode swiftui game-center gamekit game-center-leaderboard

我创建了一个测试器应用,以测试将GameCenter排行榜添加到我正在创建的简单SwiftUI游戏中。我一直无法弄清楚如何显示所有分数的Game Center排行榜。

我创建了一个类,其中包含所有Game Center功能(身份验证和向排行榜添加分数。从主ContentView View 中调用该类。我不知道如何使它显示排行榜(甚至在Gamecenter登录屏幕中显示)。播放器尚未登录。)

这是我的GameCenterManager类:

class GameCenterManager {
        var gcEnabled = Bool() // Check if the user has Game Center enabled
        var gcDefaultLeaderBoard = String() // Check the default leaderboardID
        var score = 0
        let LEADERBOARD_ID = "grp.colorMatcherLeaderBoard_1" //Leaderboard ID from Itunes Connect

       // MARK: - AUTHENTICATE LOCAL PLAYER
       func authenticateLocalPlayer() {
        let localPlayer: GKLocalPlayer = GKLocalPlayer.local

           localPlayer.authenticateHandler = {(ViewController, error) -> Void in
               if((ViewController) != nil) {
                   print("User is not logged into game center")
               } else if (localPlayer.isAuthenticated) {
                   // 2. Player is already authenticated & logged in, load game center
                   self.gcEnabled = true

                   // Get the default leaderboard ID
                   localPlayer.loadDefaultLeaderboardIdentifier(completionHandler: { (leaderboardIdentifer, error) in
                    if error != nil { print(error ?? "error1")
                       } else { self.gcDefaultLeaderBoard = leaderboardIdentifer! }
                   })
                    print("Adding GameCenter user was a success")
               } else {
                   // 3. Game center is not enabled on the users device
                   self.gcEnabled = false
                   print("Local player could not be authenticated!")
                print(error ?? "error2")
               }
           }
       } //authenticateLocalPlayer()

        func submitScoreToGC(_ score: Int){
            let bestScoreInt = GKScore(leaderboardIdentifier: LEADERBOARD_ID)
            bestScoreInt.value = Int64(score)
            GKScore.report([bestScoreInt]) { (error) in
                if error != nil {
                    print(error!.localizedDescription)
                } else {
                    print("Best Score submitted to your Leaderboard!")
                }
            }
        }//submitScoreToGc()
    }

这是ContentView结构:
    struct ContentView: View {

        //GameCenter
        init() {
            self.gameCenter = GameCenterManager()
            self.gameCenter.authenticateLocalPlayer()
        }

        @State var score = 0
        var gcEnabled = Bool() //Checks if the user had enabled GameCenter
        var gcDefaultLeaderboard = String() //Checks the default leaderboard ID
        let gameCenter: GameCenterManager

        /*End GameCenter Variables */



        var body: some View {

            HStack {
                Text("Hello, world!")
                Button(action: {
                    self.score += 1
                    print("Score increased by 10. It is now \(self.score)")
                    self.gameCenter.submitScoreToGC(self.score)

                }) {
                    Text("Increase Score")

                }
            }
        }
    }

非常感谢您解决此问题的任何帮助。

最佳答案

我有个解决办法。

我在SwiftUI应用程序Sound Matcher中成功使用了Game Center。遵循的代码片段。

该代码并不完全遵循SwiftUI声明性原理,但是可以完美地工作。我将片段添加到SceneDelegate和ContentView中,并使用GameKitHelper类,类似于Thomas为他的测试应用创建的类。我的版本基于在raywenderlich.com上找到的代码。

我实际上尝试了使用符合UIViewControllerRepresentable的结构,这是我的第一次尝试,遵循与bg2b相同的思路,但是它一直提示游戏中心 View Controller 需要模态呈现。最终,我放弃了尝试并尝试了当前更成功的方法。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    let contentView = ContentView()
        .environmentObject(GameKitHelper.sharedInstance) // publish enabled state

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, 
            options connectionOptions: UIScene.ConnectionOptions) {

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)

        window.rootViewController = UIHostingController(rootView: contentView)
        // new code to create listeners for the messages
        // you will be sending later
        PopupControllerMessage.PresentAuthentication
             .addHandlerForNotification(
                 self, 
                 handler: #selector(SceneDelegate
                     .showAuthenticationViewController))

        PopupControllerMessage.GameCenter
            .addHandlerForNotification(
                self, 
                handler: #selector(SceneDelegate
                   .showGameCenterViewController))

        // now we are back to the standard template
        // generated when your project was created
        self.window = window
        window.makeKeyAndVisible()
    }
}
// pop's up the leaderboard and achievement screen
@objc func showGameCenterViewController() {
         if let gameCenterViewController =
             GameKitHelper.sharedInstance.gameCenterViewController {
                    self.window?.rootViewController?.present(
                         gameCenterViewController,
                         animated: true,
                         completion: nil)
         }

}
// pop's up the authentication screen
@objc func showAuthenticationViewController() {
    if let authenticationViewController =
        GameKitHelper.sharedInstance.authenticationViewController {

           self.window?.rootViewController?.present(
                authenticationViewController, animated: true)
                { GameKitHelper.sharedInstance.enabled  = 
                  GameKitHelper.sharedInstance.gameCenterEnabled }
    }
  }
}

// content you want your app to display goes here
struct ContentView: View {


@EnvironmentObject var gameCenter : GameKitHelper
@State private var isShowingGameCenter = false { didSet { 
                        PopupControllerMessage
                           .GameCenter
                           .postNotification() }}

var body: some View { 
    VStack {
        if self.gameCenter.enabled
             { 
            Button(action:{ self.isShowingGameCenter.toggle()})
                { Text(
                  "Press to show leaderboards and achievements")}
             } 
        // The authentication popup will appear when you first enter
        // the view            
        }.onAppear() {GameKitHelper.sharedInstance
                               .authenticateLocalPlayer()}
    }
}

import GameKit
import UIKit

// Messages sent using the Notification Center to trigger 
// Game Center's Popup screen
public enum PopupControllerMessage : String
{
 case PresentAuthentication = "PresentAuthenticationViewController"
 case GameCenter = "GameCenterViewController"
}

extension PopupControllerMessage
{
  public func postNotification() {
     NotificationCenter.default.post(
        name: Notification.Name(rawValue: self.rawValue),
        object: self)
  }

  public func addHandlerForNotification(_ observer: Any, 
                                        handler: Selector) {
     NotificationCenter.default .
          addObserver(observer, selector: handler, name:
            NSNotification.Name(rawValue: self.rawValue), object: nil)
  }

}

// based on code from raywenderlich.com
// helper class to make interacting with the Game Center easier

open class GameKitHelper: NSObject,  ObservableObject,  GKGameCenterControllerDelegate  {
    public var authenticationViewController: UIViewController?
    public var lastError: Error?


private static let _singleton = GameKitHelper()
public class var sharedInstance: GameKitHelper {
    return GameKitHelper._singleton
}

private override init() {
    super.init()
}
@Published public var enabled :Bool = false

public var  gameCenterEnabled : Bool { 
                     return GKLocalPlayer.local.isAuthenticated }

    public func authenticateLocalPlayer () {
        let localPlayer = GKLocalPlayer.local
        localPlayer.authenticateHandler = {(viewController, error) in

            self.lastError = error as NSError?
             self.enabled = GKLocalPlayer.local.isAuthenticated
            if viewController != nil {
                self.authenticationViewController = viewController                  
                PopupControllerMessage
                   .PresentAuthentication
                   .postNotification()
            }
        }
    }

    public var gameCenterViewController : GKGameCenterViewController? { get {

         guard gameCenterEnabled else {  
                  print("Local player is not authenticated")
                  return nil }

         let gameCenterViewController = GKGameCenterViewController()

         gameCenterViewController.gameCenterDelegate = self

         gameCenterViewController.viewState = .achievements

         return gameCenterViewController
        }}

    open func gameCenterViewControllerDidFinish(_ 
                gameCenterViewController: GKGameCenterViewController) {

        gameCenterViewController.dismiss(
                      animated: true, completion: nil)
    }

}

关于xcode - 如何使用SwiftUI显示Game Center排行榜,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58722084/

相关文章:

iphone - 如何解决我希望提交到应用商店的 iOS 项目中的错误?

json - 使用本地 json 文件中的数据更新 swift UI 中的列表

iOS 游戏中心邀请在 SANDBOX 中根本不起作用

android - 在 Android/iOS 上模拟多人游戏技术

c++ - Apple Mach-O Linker (Id) 在 C++ 中创建运算符友元函数时出错

xml - xcode, iOS, XML文档解析

swiftui - 根据窗口高度扩展 NSViewRepresentable (NSTextView) 高度

c# - MonoMac - 游戏中心

ios - 抑制 Xcode 中已弃用的警告

swift - 侧边栏导航中的默认选择