Tho*_*aun 10 xcode gamekit game-center game-center-leaderboard swiftui
我创建了一个测试应用程序来测试将 GameCenter 排行榜添加到我正在创建的简单 SwiftUI 游戏中。我一直无法弄清楚如何显示所有分数的游戏中心排行榜。
我创建了一个包含所有游戏中心功能的类(身份验证和向排行榜添加分数。这是从主 ContentView 视图调用的。我不知道如何让它显示排行榜(甚至游戏中心登录屏幕,如果玩家尚未登录。)
这是我的 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()
}
Run Code Online (Sandbox Code Playgroud)
这是 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")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将不胜感激任何帮助解决问题。
我有办法。
我在我的 SwiftUI App Sound Matcher 中成功使用了 Game Center 。要遵循的代码片段。
该代码并不完全遵循 SwiftUI 声明式哲学,但它运行良好。我向 SceneDelegate 和 ContentView 添加了片段,并使用了一个 GameKitHelper 类,类似于 Thomas 为他的测试应用程序创建的类。我的版本基于我在 raywenderlich.com 上找到的代码。
我实际上尝试使用符合 UIViewControllerRepresentable 的结构作为我的第一次尝试,遵循与 bg2b 相同的思路,但是它一直抱怨游戏中心视图控制器需要以模态呈现。最终我放弃了并尝试了我目前更成功的方法。
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)
}
}
Run Code Online (Sandbox Code Playgroud)
在这里为您提供部分答案。如果设备(或模拟器)已登录 iCloud 并且已在设置中启用 GameCenter,我就可以下载排行榜分数并将其显示在 SwiftUI 列表中。如果不是这种情况,我还没有尝试使游戏中心身份验证视图控制器出现。
感谢您提供问题中的代码。我使用了你的 GameCenterManager() 但把它放在我的 AppDelegate 中:
let gameCenter = GameCenterManager()
Run Code Online (Sandbox Code Playgroud)
下面是我的 ShowRankings.swift SwiftUI 视图。我能够成功进行身份验证并获得分数。但我仍然有“异常”。我第一次运行这个(在模拟器中)时,我得到了预期的“用户未登录到游戏中心”错误,表明您的 GameCenterManager 中的 ViewController 不是零(我什至从未尝试显示它)。但是后来我能够成功获得分数并将它们显示在列表中。
import SwiftUI
import GameKit
struct ShowRankings: View {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let leaderBoard = GKLeaderboard()
@State var scores: [GKScore] = []
var body: some View {
VStack {
Button(action: {
self.updateLeader()
}) {
Text("Refresh leaderboard")
}
List(scores, id: \.self) { score in
Text("\(score.player.alias) \(score.value)")
}
}.onAppear() {
self.appDelegate.gameCenter.authenticateLocalPlayer()
self.updateLeader()
}
}
func updateLeader() {
let leaderBoard: GKLeaderboard = GKLeaderboard()
leaderBoard.identifier = "YOUR_LEADERBOARD_ID_HERE"
leaderBoard.timeScope = .allTime
leaderBoard.loadScores { (scores, error) in
if let error = error {
debugPrint("leaderboard loadScores error \(error)")
} else {
guard let scores = scores else { return }
self.scores = scores
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2595 次 |
| 最近记录: |