swift - 使用 presentScene() 更改 SKScene

标签 swift sprite-kit skscene

在我使用的 SpriteKit 游戏中:

    self.scene!.removeFromParent()
    let skView = self.view! as SKView
    skView.ignoresSiblingOrder = true
    var scene: PlayScene!
    scene = PlayScene(size: skView.bounds.size)
    scene.scaleMode = .AspectFill
    skView.presentScene(scene, transition: SKTransition.fadeWithColor(SKColor(red: 25.0/255.0, green: 55.0/255.0, blue: 12.0/255.0, alpha: 1), duration: 1.0))

从一个场景移动到另一个场景。可是怎么才能回到原来的场景呢?使用相同的代码原则总是会导致严重的崩溃。

最佳答案

我举了一个例子,其中全局结构用于跟踪关于 previousScene 的信息.它也可以通过自定义属性来完成,或者通过使用每个节点都有的 userData 来完成。逻辑是一样的。此外,我还删除了调试代码(调试标签代码等),因为它对一切正常工作并不重要。

如果我添加几个按钮,每个按钮都链接到特定场景,示例可能会更好,但我只留下一个按钮以尽可能缩短所有内容。

关于此示例您需要了解的内容(您将根据您的游戏更改此规则,但逻辑是相同的 - 在实际转换之前设置 previousScene):

  • 共有三个场景,WelcomeScene(默认场景)、MenuScene 和 GameScene。
  • 点击黑色按钮会将您带到 GameScene。当当前场景是 GameScene 时,此规则有一个异常(exception)。在这种情况下,转换会将您带到上一个场景。
  • 点击黑色按钮周围的任何地方都会将您带到上一个场景。第一次加载 WelcomeScene(未设置 previousScene)时,此规则有一个异常(exception),在这种情况下,转换会将您带到 MenuScene。

-在您的 GameViewController 中,您应该将 WelcomeScene 设置为默认场景。否则,您应该稍微更改代码以处理未设置 previousScene 时发生的情况(就像我在 WelcomeScene 的 touchesBegan 中所做的那样)。

所以这些是我制定的规则,只是为了让所有这些转换更有意义......

这是代码(BaseScene.swift):

import SpriteKit

enum SceneType: Int {

    case WelcomeScene   = 0
    case MenuScene      //1
    case GameScene      //2  
}

struct GlobalData
{
    static var previousScene:SceneType?
    //Other global data...
}

class BaseScene:SKScene {

    let button = SKSpriteNode(color: SKColor.blackColor(), size: CGSize(width: 50, height: 50))

    override func didMoveToView(view: SKView) {
        setupButton()
    }

    private func setupButton(){

        if (button.parent  == nil){

            //Just setup button properties like position, zPosition and name

            button.name = "goToGameScene"
            button.zPosition = 1
            button.position = CGPoint(x: CGRectGetMidX(frame), y: 100)
            addChild(button)
        }
    }

    func goToScene(newScene: SceneType){

        var sceneToLoad:SKScene?

        switch newScene {

        case SceneType.GameScene:

            sceneToLoad = GameScene(fileNamed: "GameScene")

        case SceneType.MenuScene:

            sceneToLoad = MenuScene(fileNamed: "MenuScene")

        case SceneType.WelcomeScene:

            sceneToLoad = WelcomeScene(fileNamed:"WelcomeScene")

        }

        if let scene = sceneToLoad {

            scene.size = size
            scene.scaleMode = scaleMode
            let transition = SKTransition.fadeWithDuration(3)
            self.view?.presentScene(scene, transition: transition)
        }
    }
}

每个场景(WelcomeScene、MenuScene、GameScene)都继承自 BaseScene 类(它是 SKScene 的子类)。我想,没有必要对此进行解释,但如果有什么让您感到困惑,请随时询问。这里的重要方法(每个子类都使用)是 goToScene(scene:SceneType) 及其参数(SceneType 类型),它告诉我们方法应该加载什么类型的场景。

SceneType 只是一个包含整数的枚举...所以实际上我们在这里不使用对象,因此不用担心 strong reference cycles .

接下来还有其他场景(WelcomeScene.swift):

import SpriteKit


class WelcomeScene:BaseScene {


    override func didMoveToView(view: SKView) {

        super.didMoveToView(view)

        self.backgroundColor = SKColor.darkGrayColor() 
    }

    deinit {print ("WelcomeScene deinited")}

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        let touch = touches.first

        if let location = touch?.locationInNode(self){

            //Give a priority to a button - if button is tapped go to GameScene
            let node = nodeAtPoint(location)
            if node.name == "goToGameScene"{
                GlobalData.previousScene = SceneType.MenuScene
                goToScene(SceneType.GameScene)
            }else{
                //Otherwise, do a transition to the previous scene

                //Get the previous scene
                if let previousScene = GlobalData.previousScene {

                    GlobalData.previousScene = SceneType.WelcomeScene
                    goToScene(previousScene)

                }else{

                    // There is no previousScene set yet? Go to MenuScene then...
                    GlobalData.previousScene = SceneType.WelcomeScene
                    goToScene(SceneType.MenuScene)

                }
            }       
        }      
    }
}

为了尽可能简短,所有内容都有注释。下一个代码(MenuScene.swift):

import SpriteKit

class MenuScene: BaseScene  {

    override func didMoveToView(view: SKView) {

        super.didMoveToView(view)
        backgroundColor = SKColor.purpleColor()
    }

    deinit {
        print ("MenuScene deinited") //If this method isn't called, you might have problems with strong reference cycles.
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        let touch = touches.first

        if let location = touch?.locationInNode(self){

            //Give a priority to a button - if button is tapped go to GameScene
            let node = nodeAtPoint(location)
            if node.name == "goToGameScene"{
                GlobalData.previousScene = SceneType.MenuScene
                goToScene(SceneType.GameScene)
            }else{
                //Otherwise, do a transition to the previous scene

                //Get the previous scene
                if let previousScene = GlobalData.previousScene {

                    GlobalData.previousScene = SceneType.MenuScene
                    goToScene(previousScene)

                } 
            }
        } 
    }
}

最后(GameScene.swift):

import SpriteKit

class GameScene: BaseScene{

    override func didMoveToView(view: SKView) {

        super.didMoveToView(view)

     self.backgroundColor = SKColor.orangeColor() 
    }

    deinit {print ("GameScene deinited")}

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        //Here, we ignore black button because we don't want to transition to the same scene

         if let previousScene = GlobalData.previousScene {

            GlobalData.previousScene = SceneType.GameScene
            goToScene(previousScene)  
        }
    }
}

预览:

transitions

只要从头再读一遍规则,你就会没事的(例如,在 GameScene 中黑色按钮不起作用,或者在第一次启动时 previousScene 没有设置,所以你将默认转换到 MenuScene)。

就是这样。希望这个对你有帮助。您可以复制并粘贴代码以对其进行测试并根据您的需要对其进行改进。不过,不确定您是否真的需要这个。看起来你只需要 correctly transition between scenes .

提示:这里重要的是每个场景 BaseScene、WelcomeScene... 都有自己的 .sks 文件。您从 File->New->File->Resource 创建它们并适当命名(如 BaseClass.sks、WelcomeScene.sks...)此外,您的工作是维护 GlobalData.previousScene 的状态。变量(例如,在进行转换之前设置它)。

关于swift - 使用 presentScene() 更改 SKScene,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34498982/

相关文章:

swift - 实例化 View Controller 不工作

ios - SKVideoNode 不显示视频

ios - SpriteKit - 获取最近的节点

ios - SpriteKit View 不在 ViewController 的 viewDidLoad 中呈现场景

ios - 如何从 GameScene 中的 ViewController 调用方法

ios - 为什么我的 ViewController 在重新打开后不显示另一个 SKScene?

ios - 原因 : 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.'

json - Swift:使用 JSON 文件中具有特定值的数据填充 TableView

ios - WKWebView 询问 "would like to use your current location"未本地化,始终为英文

ios - 检测 Swift 2 中一个节点的子节点和另一个节点的碰撞