如何从 UIViewController 移动到 SKView,反之亦然?

Posted

技术标签:

【中文标题】如何从 UIViewController 移动到 SKView,反之亦然?【英文标题】:How to move from UIViewController to SKView and vice versa? 【发布时间】:2019-02-15 00:42:36 【问题描述】:

我的想法是在移动到游戏场景之前显示几秒钟的地图,游戏屏幕层次结构是这样的:GameViewController(UIViewController) -> EntryToGameScene (SKView ) -> MapController (UIViewController) -> GamePlayGround (SKView)

我在从 MapController 移动到 GamePlayGround 时遇到了一个问题,为了能够从控制器移动到场景,我首先将控制器视图类从 Storyboard 更改为 SKView,然后我添加了以下代码 ⬇️。handleDelay() 方法之后运行,游戏场景didMove() 方法工作但屏幕卡在旧视图(MapController)上!?我确定游戏场景didMove() 方法有效,因为背景音乐开始播放。但是为什么屏幕没有变化?

我的代码是这样的:

override func viewDidLoad() 
    super.viewDidLoad()
    // Wait for three sec. then move to game scene
    self.perform(#selector(handleDelay), with: nil, afterDelay: 3.0)


@objc fileprivate func handleDelay() 

    view.layoutIfNeeded()

    if let view = self.view as! SKView? 
        // Load the SKScene
        let scene = GameScene(size: sceneSize)

        // Set the scale mode
        scene.scaleMode = .aspectFill
        scene.delegate = self
        // Present the scene
        view.presentScene(scene)

        view.ignoresSiblingOrder = true
        view.showsFPS = false
        view.showsNodeCount = false
        view.showsPhysics = false
    

所有答案都可以接受。

【问题讨论】:

我不认为我完全理解你的问题。您想在游戏中显示地牢/关卡地图几秒钟,然后再转到另一个视图?我假设英语不是您的第一语言,但如果您可以编辑您的问题以更好地说明您的问题,那将真正帮助我了解我需要帮助您的内容。 @E.Huckabee 谢谢你的建议,我已经更正了我的问题。 @E.Huckabee 是的,你没看错。 我建议学习如何使用你的故事板。您可以对此进行情节提要,而无需任何代码。 @Knight0fDragon 你能解释一下吗? 【参考方案1】:

从视图中删除所有子视图然后呈现 SKScene 的解决方案。

注意:我知道这不是最好的解决方案,但目前没有其他选择,所以我这样更改了代码:

override func viewDidLoad() 
    super.viewDidLoad()

    self.perform(#selector(handleDelay), with: nil, afterDelay: 3.0)



@objc fileprivate func handleDelay() 

    self.view.subviews.forEach $0.removeFromSuperview()

    if let view = self.view as! SKView? 
        // Load the SKScene from 'GameScene.swift' and should set it's size
        let scene = SecondGameScene(size: self.view.frame.size)
        // Set the scale mode to scale to fit the window
        scene.scaleMode = .aspectFill

        // Present the scene
        view.presentScene(scene)

        view.ignoresSiblingOrder = true

        view.showsFPS = false
        view.showsNodeCount = false
    


更新: 最后我找到了从 SKScene 和 UIView Controller 迁移的正确方法,反之亦然。

例如(从 SKScene 移动到 UIViewController):

fileprivate func moveToUIViewController(storyBoardId: String) 
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: storyBoardId)
    vc.view.frame = self.frame
    vc.view.layoutIfNeeded()        

    self.view?.window?.rootViewController?.present(vc, animated: true, completion: nil)

(从 UIViewController 移动到 SKScene):

fileprivate func returnToSKScene() 

    for element in self.view.subviews 
        element.removeFromSuperview()
    
    self.dismiss(animated: true) 
        if let view = self.view as! SKView? 
            // Load the SKScene
            var scene: SKScene
            scene = AboutScene(size: sceneSize)

            // Set the scale mode
            scene.scaleMode = .aspectFill
            let transition = SKTransition.moveIn(with: .up, duration: 0.2)

            // Present the scene
            view.presentScene(scene, transition: transition)

            view.ignoresSiblingOrder = true
            view.showsFPS = false
            view.showsNodeCount = false
            view.showsPhysics = false

        
    

别忘了用“SKView”改变 UIViewController view 类:

    从 Storyboard -> 身份检查器 -> 自定义类中选择视图。

    2.从类下拉列表中选择SKView

【讨论】:

找出自己的问题将帮助您培养成为开发人员所需的批判性思维。很好的答案和很好的自己解决问题的工作。【参考方案2】:

轻松修复。我将代码复制并粘贴到一个测试项目中,我发现你做错了什么。您没有引用要呈现的场景。您没有传入要呈现的特定 SKView 。您正在展示一个通用的 SKView 类。

这段代码:

override func viewDidLoad() 
    super.viewDidLoad()
    // Wait for three sec. then move to game scene
    self.perform(#selector(handleDelay), with: nil, afterDelay: 3.0)


@objc fileprivate func handleDelay() 

    view.layoutIfNeeded()

    if let view = self.view as! SKView? 
        // Load the SKScene
        let scene = GameScene(size: sceneSize)

        // Set the scale mode
        scene.scaleMode = .aspectFill
        scene.delegate = self
        // Present the scene
        view.presentScene(scene)

        view.ignoresSiblingOrder = true
        view.showsFPS = false
        view.showsNodeCount = false
        view.showsPhysics = false
    

应该是这样的:

override func viewDidLoad() 
    super.viewDidLoad()
    // Wait for three sec. then move to game scene
    self.perform(#selector(handleDelay), with: nil, afterDelay: 3.0)


@objc fileprivate func handleDelay() 

    view.layoutIfNeeded()

    // Load the view as an SKView to prepare for an SKScene
    if let view = self.view as! SKView? 
        // Load the SKScene from the GameScene file
        let scene = GameScene()
        // Set the scale mode to scale to fit the window
        scene.scaleMode = .aspectFill

        // Present the scene
        view.presentScene(scene)

        view.ignoresSiblingOrder = true

        view.showsFPS = true
        view.showsNodeCount = true
    

经过测试并且可以正常工作。

【讨论】:

但是我的 GameScene 是在没有 GameScene.sks 文件的情况下创建的,所以我怎样才能将它作为参考? 那段代码是错误的。我将使用您要求的正确代码编辑上面的答案。 我注意到但没关系我明白了,游戏场景应该使用名称调用。 如果我的回答帮助您解决了问题,您需要接受它为正确的。 (也许还会投赞成票)这样来这里的其他人就会知道哪个答案对您有帮助。 我知道,但您需要编辑您的答案,而且我必须尝试您的解决方案是否正确。

以上是关于如何从 UIViewController 移动到 SKView,反之亦然?的主要内容,如果未能解决你的问题,请参考以下文章

将 UIViewController 从一个 presentingViewController 移动到另一个没有动画

从 UIViewController 切换到另一个时如何保持 UILongPressGestureRecognizer 处于活动状态

快速获取以前的 UIViewController

如何从 SKScene 到 UIViewController?

如何从 UIView 导航到 UIViewController

如何将数据从 UITableViewCell 传输到另一个 UIViewController?