Swift SpriteKit:在GameScene中访问UIViewController的最佳实践

时间:2023-01-23 22:24:09

I wanted to see what the best practice(s) of accessing UIViewController methods from GameScene is/are. Right now I have been using NSNotificationCenter, but I don't want to use this due to specific functionality that I am trying to achieve.

我想看看从GameScene访问UIViewController方法的最佳实践是/are。现在我一直在使用NSNotificationCenter,但我不想使用它,因为我正在尝试实现特定的功能。

Also, if there are not any other ways of gaining access to UIViewController through GameScene, then really what I am wondering is a method of being able to present an UIAlertController within the GameScene without UIViewController.

另外,如果没有其他方法可以通过GameScene获得对UIViewController的访问,那么我真正想知道的是一种能够在GameScene中不使用UIViewController显示UIAlertController的方法。

I would just create a global variable to the UIViewController, but I heard this is bad practice.

我只需要为UIViewController创建一个全局变量,但我听说这是不好的做法。

Thanks!

谢谢!

3 个解决方案

#1


1  

You can show UIAlertControllers in SKScenes, simply show them on the rootViewController, which is probably the best place to show them anyway.

您可以在sk场景中显示uialertcontroller,只需在rootViewController中显示它们,这可能是显示它们的最佳位置。

self.view?.window?.rootViewController?.present...

I dont like referencing the GameViewController in SKScenes and I never actually got to a point where I was forced to do so. NSNotificationCenter, delegation or protocol extensions are the better way.

我不喜欢在skscene中引用GameViewController,我从来没有到*这样做的地步。NSNotificationCenter、委托或协议扩展是更好的方法。

I actually use a helper for Alerts I made using Swift 2's protocol extensions because I like clean, reusable and as little duplicate code as possible.

实际上,我使用了一个助手来帮助我使用Swift 2的协议扩展,因为我喜欢干净、可重用和尽可能少重复的代码。

Just make a new .swift file and add this code

只需新建一个.swift文件并添加此代码

import SpriteKit

protocol Alerts { }
extension Alerts where Self: SKScene {

func showAlert(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
}

func showAlertWithSettings(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    let settingsAction = UIAlertAction(title: "Settings", style: .Default) { _ in

        if let url = NSURL(string: UIApplicationOpenSettingsURLString) {
            UIApplication.sharedApplication().openURL(url)
        }
    }
    alertController.addAction(settingsAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
    }
}

Now in your scenes you need to show alerts you simply conform to the protocol

现在,在您的场景中,您需要显示警报,您只需遵循协议

class GameScene: SKScene, Alerts {

} 

and call the methods like

调用方法

showAlert(title: "Alert title", message: "Alert message")

as if they are part of the scene itself.

就好像他们是场景的一部分。

Enjoy

享受

#2


0  

This is a bit hacky, but to directly access functions from the view controller use this:

这有点粗糙,但是从视图控制器直接访问函数使用如下:

(view?.nextResponder() as? MyViewController)?.presentAlert()

This relies upon your SKView being the main view in your view controller. If it isn't then you'll need to add in .superview? after your view? call.

这依赖于SKView是视图控制器中的主视图。如果不是,那么需要添加。superview?在你的观点吗?调用。

#3


0  

An alternative to the previous answer I posted (and the more proper method) would be to create a property in your scene class to store a reference to the view controller and use that:

另一种替代方法是在scene类中创建一个属性来存储对视图控制器的引用并使用它:

class MyGameScene: SKScene {

    weak var viewController: MyViewController?

    func somethingHappened() {
        viewController?.presentAlert()
    }

}

And when you present the scene in your controller make sure to set a reference to your view controller:

当你在控制器中显示场景时一定要设置一个对你的视图控制器的引用:

if let scene = GameScene(fileNamed:"GameScene") {
    scene.viewController = self

    // other stuff
    skView.presentScene(scene)
}

#1


1  

You can show UIAlertControllers in SKScenes, simply show them on the rootViewController, which is probably the best place to show them anyway.

您可以在sk场景中显示uialertcontroller,只需在rootViewController中显示它们,这可能是显示它们的最佳位置。

self.view?.window?.rootViewController?.present...

I dont like referencing the GameViewController in SKScenes and I never actually got to a point where I was forced to do so. NSNotificationCenter, delegation or protocol extensions are the better way.

我不喜欢在skscene中引用GameViewController,我从来没有到*这样做的地步。NSNotificationCenter、委托或协议扩展是更好的方法。

I actually use a helper for Alerts I made using Swift 2's protocol extensions because I like clean, reusable and as little duplicate code as possible.

实际上,我使用了一个助手来帮助我使用Swift 2的协议扩展,因为我喜欢干净、可重用和尽可能少重复的代码。

Just make a new .swift file and add this code

只需新建一个.swift文件并添加此代码

import SpriteKit

protocol Alerts { }
extension Alerts where Self: SKScene {

func showAlert(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
}

func showAlertWithSettings(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    let settingsAction = UIAlertAction(title: "Settings", style: .Default) { _ in

        if let url = NSURL(string: UIApplicationOpenSettingsURLString) {
            UIApplication.sharedApplication().openURL(url)
        }
    }
    alertController.addAction(settingsAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
    }
}

Now in your scenes you need to show alerts you simply conform to the protocol

现在,在您的场景中,您需要显示警报,您只需遵循协议

class GameScene: SKScene, Alerts {

} 

and call the methods like

调用方法

showAlert(title: "Alert title", message: "Alert message")

as if they are part of the scene itself.

就好像他们是场景的一部分。

Enjoy

享受

#2


0  

This is a bit hacky, but to directly access functions from the view controller use this:

这有点粗糙,但是从视图控制器直接访问函数使用如下:

(view?.nextResponder() as? MyViewController)?.presentAlert()

This relies upon your SKView being the main view in your view controller. If it isn't then you'll need to add in .superview? after your view? call.

这依赖于SKView是视图控制器中的主视图。如果不是,那么需要添加。superview?在你的观点吗?调用。

#3


0  

An alternative to the previous answer I posted (and the more proper method) would be to create a property in your scene class to store a reference to the view controller and use that:

另一种替代方法是在scene类中创建一个属性来存储对视图控制器的引用并使用它:

class MyGameScene: SKScene {

    weak var viewController: MyViewController?

    func somethingHappened() {
        viewController?.presentAlert()
    }

}

And when you present the scene in your controller make sure to set a reference to your view controller:

当你在控制器中显示场景时一定要设置一个对你的视图控制器的引用:

if let scene = GameScene(fileNamed:"GameScene") {
    scene.viewController = self

    // other stuff
    skView.presentScene(scene)
}