spritekit gamecenter leaderboard - how to show leaderboard from scene? - swift

How can I call my showLeader() function from GameViewController.swift in GameScene.swift ?
this is my showLeader function
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}

You make use of NSNotificationCenter to present the viewController from an SKScene. Remember to add the observer and then post the notification. Don't forget to deinit the NSNotification when you no longer need it or your app will crash.

Related

How to show a specific UIViewController when GKGameCenterViewController is dismissed?

I am presenting a GKGameCenterViewController in an SKScene that inherits from the following protocol.
protocol GameCenter {}
extension GameCenter where Self: SKScene {
func goToLeaderboard() {
let vc = GKGameCenterViewController()
vc.gameCenterDelegate = GameViewController()
vc.viewState = .leaderboards
vc.leaderboardIdentifier = "leaderboard"
view?.window?.rootViewController?.present(vc, animated: true, completion: nil)
}
}
While the GKGameCenterViewController shows up perfect, when I try to dismiss by clicking the X in the top right corner, nothing happens. I assume this is because the reference to my original GameViewController has been deallocated. How can I get this dismissal to work?
According to Apple's Documentation:
Your delegate should dismiss the Game Center view controller. If your game paused any gameplay or other activities, it can restart those services in this method.
This means you need to implement the gameCenterViewControllerDidFinish method in your delegate and dismiss the gameCenterViewController yourself.
You should have something like this in your GameViewController()
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismiss(animated: true, completion: nil)
}
In order to present the GKGameCenterViewController on a SKScene, I needed to find the currently displayed UIViewController reference and set this as the delegate. Here is the code I used and it works:
protocol GameCenter {}
extension GameCenter where Self: SKScene {
func goToLeaderboard() {
var currentViewController:UIViewController=UIApplication.shared.keyWindow!.rootViewController!
let vc = GKGameCenterViewController()
vc.gameCenterDelegate = currentViewController as! GKGameCenterControllerDelegate
vc.viewState = .leaderboards
vc.leaderboardIdentifier = "leaderboard"
currentViewController.present(vc, animated: true, completion: nil)
}
}

RealityKit – Can't deallocate ARView

I'm using a ARView to show AR content in my app, but on dismissing the view controller, the memory is not completely deallocated.
I found this question, but I had no luck with the answer.
The memory consumption looks like this:
The entire codebase is very simple:
I've got a button that on pressing it, executes this:
let vc = SecondViewController()
self.present(vc, animated: true, completion: {
print("done")
})
and SecondViewController is a simple as this:
class SecondViewController: UIViewController {
var arView: ARView?
override func viewDidLoad() {
super.viewDidLoad()
self.arView = ARView(frame: self.view.frame)
self.view.addSubview(arView!)
arView!.automaticallyConfigureSession = true
}
deinit {
self.arView?.session.pause()
self.arView?.session.delegate = nil
self.arView?.scene.anchors.removeAll()
self.arView?.removeFromSuperview()
self.arView?.window?.resignKey()
self.arView = nil
}
}
But on dismissing, as can be seen in the memory graph, the memory is not deallocated fully.

Switching from a Spritekit Scene back to the storyboard

Simply put, I want to go from a spritekit Scene to a view in the Main Storyboard. It's easy to go from the main storyboard to a spritekit scene in swift. But I can't figure out how to go back to the storyboard. Thanks for the help. Cheers.
Initial viewController: an empty viewController with a button to present the GameViewController
GameViewController: the typical GameViewController of the "Hello World" Sprite-kit template. (This is a simplified version of the two scripts as of course you will have more code in yours, however, for the purpose of sharing what I did, this is easier)
My Goal: I wanted to present the first viewController from my SKScene game with the correct deallocation of my scene.
Description: To obtain the result I've extended the SKSceneDelegate class to build a custom protocol/delegate that make the transition from the GameViewController to the first initial controller (main menu). This method could be extended to other viewControllers of your game. This delegate is made use of in the return to main menu function. Make sure to put this function before you call the class for your spritekit script.
The two scripts are shown below. Hope this helps anybody else who had my question.
UIViewController:
import UIKit
import SpriteKit
class GameViewController: UIViewController,TransitionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
scene.delegate = self as TransitionDelegate
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
func returnToMainMenu(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
guard let storyboard = appDelegate.window?.rootViewController?.storyboard else { return }
if let vc = storyboard.instantiateInitialViewController() {
print("go to main menu")
self.present(vc, animated: true, completion: nil)
}
}
}
Game Script:
import SpriteKit
protocol TransitionDelegate: SKSceneDelegate {
func returnToMainMenu()
}
class GameScene: SKScene {
override func didMove(to view: SKView) {
self.run(SKAction.wait(forDuration: 2),completion:{[unowned self] in
guard let delegate = self.delegate else { return }
self.view?.presentScene(nil)
(delegate as! TransitionDelegate).returnToMainMenu()
})
}
deinit {
print("\n THE SCENE \((type(of: self))) WAS REMOVED FROM MEMORY (DEINIT) \n")
}
}

Displaying a Game Center Leaderboard in SpriteKit

I'm working on a game, and I'm looking for help or the code to display a GameCenter leaderboard in my app when a user clicks a button. I have no clue where to start as all of the other answers seem to be for Obj-C, thanks!
EDIT:
The Below answer worked perfectly, but for those wondering how to do this within SpriteKit, simply add the below methods to the GameViewController and add a Notification Center Observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showLeaderboard", name: "showLeaderboard", object: nil)
In your SKScene Class, simply call to that observer.
NSNotificationCenter.defaultCenter().postNotificationName("showLeaderboard", object: nil)
Just to help out those wondering!
Include the GKGameCenterControllerDelegate protocol within your class.
class ViewController: UIViewController, GKGameCenterControllerDelegate
This method dismisses the Game Center view when "Done" is tapped:
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!) {
self.dismissViewControllerAnimated(true, completion: nil)
}
This function includes the code that is needed to display the leaderboard:
func showLeaderboard() {
// declare the Game Center viewController
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
// Remember to replace "Best Score" with your Leaderboard ID (which you have created in iTunes Connect)
gcViewController.leaderboardIdentifier = "Best_Score"
// Finally present the Game Center ViewController
self.showViewController(gcViewController, sender: self)
self.navigationController?.pushViewController(gcViewController, animated: true)
self.presentViewController(gcViewController, animated: true, completion: nil)
}
You can now trigger the function showLeaderboard by pressing a UIButton:
#IBAction func buttonShowLeaderboard(sender: AnyObject) {
showLeaderboard()
}
You can do it like CeceXX showed, or you can use Easy-Game-Center by DaRkD0G to make it easier. https://github.com/DaRkD0G/Easy-Game-Center-Swift

Swift - FirstViewController and GKGameCenterControllerDelegate

I want to include a GameCenter Leaderboard in my app but I have one problem.
When I want to show LeaderBoard, I use this code :
//shows leaderboard screen
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
For that, I must had GKGameCenterControllerDelegate in my class like that :
class FirstViewController: UIViewController, GKGameCenterControllerDelegate {
When I do that, I have an error : 'type FirstViewController' does not to conform to protocol 'GKGameCenterControllerDelegate'.
Any solution ?
You need to include the following method:
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!)
{
// By tapping on Done, the Game Center window will be dismissed.
self.dismissViewControllerAnimated(true, completion: nil)
}
More info here: https://developer.apple.com/library/mac/documentation/GameKit/Reference/GKGameCenterViewControllerDelegate_Ref/